Skip to Content
Hardware integrationTypeScript SDK

TypeScript SDK

Best for Node services, workers, and — via a server proxy — browser apps. Requires Node 18+; ESM and CJS builds are both shipped.

1. Setup client

npm install plexus-typescript

Create a client with your API key, a stable sourceId, and a kind. Plexus registers the source automatically on first send.

import { Plexus } from "plexus-typescript"; const px = new Plexus({ apiKey: "YOUR_API_KEY", sourceId: "checkout-api", kind: "service", });

kind declares what this source is — "service", "web-app", or "worker" — so the app labels it correctly and shows the right template instead of treating it as a bare device. The declaration is best-effort after the first successful send; if it fails, the source just stays generic.

In production, set PLEXUS_API_KEY as an environment variable instead of hardcoding the key — the SDK picks it up automatically:

const px = new Plexus({ sourceId: "checkout-api", kind: "service" });

Get your API key from API Keys in the dashboard.

2. Send metrics

// Single metric await px.send("request_latency_ms", 42); // With tags — slice by queue, region, version, etc. await px.send("queue_depth", 17, { tags: { queue: "emails" } }); // Batch — all points land in one network call await px.sendBatch([ ["temperature", 22.4], ["humidity", 58.1], ["pressure", 1013.2], ]);

value accepts numbers, strings, booleans, objects, and arrays. Numbers become metric points; everything else becomes an event point.

3. Send events

Use event() for things that happen rather than things you measure — faults, state transitions, deploys. They show up as markers on charts, not time-series lines.

await px.event("fault", "E-stop triggered"); await px.event("state_change", { from: "IDLE", to: "RUNNING" }); await px.event("deploy", { sha: "abc123" });

4. Reliability

Points are sent immediately. On failure the SDK retries with exponential backoff (4 attempts total by default); when retries are exhausted, points go into an in-memory buffer (default capacity 10,000, oldest dropped first) and are prepended to the next send. flush() drains the buffer explicitly; close() is a final best-effort flush on shutdown.

send() resolves false rather than rejecting on delivery failure. Telemetry calls are routinely fire-and-forget, so a network blip never becomes an unhandled rejection. It rejects only on programmer error (invalid metric or source) or authentication failure (AuthenticationError on 401/403).

const delivered = await px.send("engine_rpm", 3450); // true, or false if buffered // On shutdown: await px.close();

Retry behavior is configurable via new Plexus({ retry: { maxRetries, baseDelayMs, ... } }).

5. Timestamps

Wire timestamps are milliseconds since epoch. Omit timestamp and the SDK uses Date.now().

await px.send("temp", 72.5); // now await px.send("temp", 72.5, { timestamp: new Date("2026-07-01") }); // Date accepted await px.send("temp", 72.5, { timestamp: 1751328000 }); // seconds — auto-scaled to ms

Numbers below 1e12 are treated as seconds and auto-scaled — the same rule the gateway applies, so second-resolution timestamps from other systems land correctly.

6. Browser apps

Browsers must never hold a plx_ API key: the key grants org-wide write access, and anything shipped to the browser is public. The pattern is a two-piece proxy — the page fires fire-and-forget beacons at a first-party route, and that route (which holds the key in server env) forwards to the gateway. The key never ships to the browser.

Server side (Next.js route handler shown; works with anything that speaks web-standard Request/Response — Remix, Hono, Bun, Deno):

// app/api/plexus/route.ts import { createIngestProxy } from "plexus-typescript/server"; export const POST = createIngestProxy({ sourceId: "web-frontend", allowMetrics: ["page_view", "signup", "read_seconds"], });

Browser side:

import { createBrowserClient } from "plexus-typescript/browser"; const plexus = createBrowserClient(); // posts to /api/plexus plexus.track("page_view", 1, { page: "/pricing" }); plexus.event("signup", { plan: "team" });

The browser client uses navigator.sendBeacon (survives page unload) with a keepalive fetch fallback, and never throws. The proxy route is public, so it sanitizes what it forwards — set allowMetrics to pin the metric names you expect. It always responds 204; telemetry must never break the calling page.

Environment variables

VariableDescriptionDefault
PLEXUS_API_KEYAPI key (required)none
PLEXUS_GATEWAY_URLHTTP ingest URLhttps://gateway.plexus.company
PLEXUS_ENDPOINTProduct app (runs + kind declaration)https://app.plexus.company

Resolution order: explicit option > environment > ~/.plexus/config.json > default.

Last updated on