Node.js

Server-side JavaScript and TypeScript for Node 18+, ESM and CommonJS.

For a backend, not a browser. Every call puts an event on a bounded queue and returns: nothing throws into your code, nothing is awaited on the hot path, and if firstrun is unreachable your program keeps working. No runtime dependencies.

Install the package

Terminal
npm install @firstrun/node

Create the client

TypeScript
import { Firstrun } from "@firstrun/node";

const firstrun = new Firstrun({
  sourceKey: process.env.FIRSTRUN_SOURCE_KEY!,   // fr_server_...
  host: "https://app.firstrun.app",
  serviceVersion: process.env.GIT_SHA,
  onDiagnostic: (d) => log.warn({ firstrun: d }),
});

A bad key or host disables the client and reports it rather than throwing, because a typo in an environment variable must not stop your service booting. onDiagnostic is the only reporting channel: nothing is ever written to stdout or stderr.

Write events

TypeScript
firstrun.event("exported_csv", { rows: rows.length }, { distinctId: req.user.id });

firstrun.error(err, { "http.route": "/reports/:id" }, { distinctId: req.user.id });

firstrun.log({
  name: "queue_depth",
  severity: 9,
  distinctId: "worker-3",
  attributes: { "firstrun.metric": "queue_depth", "firstrun.value": depth },
});

await firstrun.close(2000);   // on exit. Bounded, never rejects

Not awaited, and there is nothing here to await. event writes at INFO and error at ERROR, both filling in the conventional attributes; log takes any name, any severity and any attributes. Values are JSON, so a number stays a number. A long-running service needs no close(): beforeExit, SIGTERM and SIGINT already flush with a budget. A CLI or a one-shot job should call it.

distinctId is yours to supply. A browser has a visitor id and a desktop install has one on disk. A server has neither, so pass an id you already have per call. An event without one is dropped and reported rather than sent under an invented id: a loud failure beats a silently wrong number nobody can spot from a dashboard. Set the client-level distinctId only when the process really is the subject, such as a CLI or a device agent.