SDKs / TypeScript / Node

TypeScript / Node

Batched log shipping plus an Express error handler that attaches the log lines leading to the failure.

Requires Node 18+Package @insightrecorder/insight-recorderSource on GitHub →

Before you start

Where your InsightRecorder runs
The base URL every call goes to — http://localhost:8080 when you are running it locally, your own hostname otherwise.
An API key
Settings → API keys, scoped to logs:write and bug:write. The token (crk_…) is shown exactly once — it is hashed at rest — and is revocable. Do not use a login JWT: it expires within the hour and is not meant for machines.
  1. 01

    Install

    Zero runtime dependencies; ships its own type declarations.

    npm install @insightrecorder/insight-recorder
  2. 02

    Create the client and shipper

    Once, at composition. Close it on shutdown or the last batch is lost.

    import { Client } from "@insightrecorder/insight-recorder";
    
    const client = new Client(process.env.INSIGHT_BASE_URL, process.env.INSIGHT_API_KEY);
    const shipper = client.shipper();
    
    shipper.send({ level: "error", message: "checkout failed", traceId, attrs: { order_id: "1234" } });
    
    await shipper.close();
  3. 03

    Report unhandled errors

    Register it LAST in the Express stack — an error handler before the routes never sees them.

    app.use(errorHandler(client, { shipper, service: "checkout-api" }));
  4. 04

    Verify it is working

    Ship one line and throw from a route. Register the error handler LAST, after your routes, or Express never reaches it.

    shipper.send({ level: "error", message: "insightrecorder smoke test" });
    
    app.get("/_boom", () => {
      throw new Error("insightrecorder smoke test");
    });

    Then look for the line at /app/logs and the report at /app/bugs.

    If nothing shows up

    Nothing arrived? Check shipper.dropped — a rising count means the queue is undersized. Delivery errors are silent unless you pass onError. And await shipper.close() on shutdown, or the last batch is lost.

Before you ship

  • Each request is capped at the batch size, so a burst cannot exceed the server's body limit.
  • Retries are bounded and honour the server's 429 + Retry-After.
PROMPT Install the TypeScript / Node SDK with an AI agent
Raw .md

Paste this into a coding agent running inside your project, or point the agent at /docs/prompts/typescript directly. It is self-contained: the agent needs no prior knowledge of InsightRecorder.

# Install and wire the InsightRecorder TypeScript/JavaScript SDK

Paste this into a coding agent (Claude Code, Cursor, …) running inside your
Node.js service's repository. It is self-contained — the agent needs no prior
knowledge of InsightRecorder.

---

You are working in a Node.js service (TypeScript or JavaScript). Install and
wire the InsightRecorder SDK so this service ships its logs to InsightRecorder and reports
unhandled errors.

**Context you need:**

- InsightRecorder collects application logs and bug reports. `@insightrecorder/insight-recorder`
  is the supported way for a Node **server** to talk to it. (A browser app uses
  a different thing — a `<script>` capture agent — so do not install this
  package in front-end-only code.)
- Requires **Node 18+**. The package has zero runtime dependencies.
- Authentication uses a long-lived **API key** shaped like `crk_…`, created in
  the InsightRecorder UI under *Settings → API keys* with the `logs:write` scope (add
  `bug:write` to report errors). **Do not** use a login JWT: those expire after
  an hour and are not meant for machines.

  Add `bug:read` for anything the SDK reads back (`listBugs/getBug`), and `logs:read` if you query logs. A write-only key is the common mistake: shipping works, the first read returns 403.

- **Wire trace correlation if the application uses OpenTelemetry.** A log line
  and the request that wrote it are one investigation, and that join is the
  reason to ship logs here rather than anywhere else — see the "Trace
  correlation" section of the README for what this language needs (several do it
  automatically; the rest take one hook). Without it, every log call has to carry
  `trace_id` by hand, which nobody sustains past the first week.

**Steps:**

1. `npm install @insightrecorder/insight-recorder` (or the project's package manager —
   match what the repo already uses: yarn, pnpm, bun).

2. Read configuration from the environment, never hard-code it. Add
   `INSIGHT_BASE_URL` and `INSIGHT_API_KEY` to the project's existing config
   loading and to `.env.example` / deployment manifests. If either is empty, the
   service must start normally with shipping disabled — telemetry is never a
   startup dependency.

3. In the service's composition root (where the logger and HTTP server are
   built — do not invent a new bootstrap module if one exists):

   ```ts
   import { Client, errorHandler } from "@insightrecorder/insight-recorder";

   const client = new Client(process.env.INSIGHT_BASE_URL!, process.env.INSIGHT_API_KEY!);
   const shipper = client.shipper();
   ```

4. Bridge the service's existing logger to `shipper.send(...)`. Match what the
   repo already uses:
   - **pino**: add a custom transport/stream, or call `shipper.send` from a
     `hooks.logMethod` wrapper.
   - **winston**: add a small custom `Transport` whose `log()` calls
     `shipper.send`.
   - **console only**: wrap the call sites, or leave logging alone and only wire
     error reporting (step 5).

   Map fields as: `level` → level, the message → `message`, a trace id →
   `traceId`, and everything else into `attrs` (string values).

5. If the service uses Express, register the error handler **last**, after all
   routes:

   ```ts
   app.use(errorHandler(client, { shipper, service: "<service name>" }));
   ```

   For Fastify/Koa/NestJS, call `client.reportBug(...)` from that framework's
   own error hook instead — the payload shape is in the package's README.

6. Flush on shutdown. Add `await shipper.close()` to the service's existing
   SIGTERM/SIGINT handling, next to the server close. Without it the final batch
   is lost.

**Rules — do not violate these:**

- Do **not** write a custom fetch loop that POSTs one request per log line. The
  SDK batches, retries with backoff, respects the server's quota (429 +
  `Retry-After`), and caps each request at `batchSize`.
- Do **not** `await shipper.send(...)` or wrap it in anything that waits — it is
  deliberately synchronous and non-blocking, and drops when its queue is full.
- Do **not** log the API key, and do not commit it.
- Do **not** capture request bodies, headers, cookies, or query strings in error
  reports. The SDK records only the method and path, because those routinely
  carry credentials and personal data.

**Verify before you finish:**

1. The project's build/typecheck and test commands pass.
2. Start the service with both env vars set, hit an endpoint, then confirm the
   log lines appear in InsightRecorder at `/app/logs`.
3. Trigger a deliberate error and confirm a bug appears at `/app/bugs`.
4. Confirm the service still starts with both variables **unset**.
5. Report what you changed, and state explicitly whether `shipper.close()` runs
   on shutdown.

If anything is ambiguous — which logger, where the composition root is, how
shutdown is handled — inspect the repository and follow what is already there.
Do not restructure the service to fit the SDK.