> ## Documentation Index
> Fetch the complete documentation index at: https://www.glyphhq.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Node.js

> Send server-side events with @glyphhq/node.

`@glyphhq/node` sends events from API routes, webhooks, and background jobs. Use server-side tracking for payments, subscription changes, and other events that must not depend on a browser session.

## Install

```bash theme={"dark"}
npm install @glyphhq/node
```

The package ships ESM and CJS builds with TypeScript types. Node.js 18+ is required (the SDK uses the built-in `fetch`).

The SDK reports its package name and version with each request. Glyph stores this as diagnostic metadata alongside the write key used for ingestion. It is not added to event properties.

## Initialize

```ts theme={"dark"}
import { GlyphNode } from "@glyphhq/node";

const writeKey = process.env.GLYPH_WRITE_KEY;
if (!writeKey) {
  throw new Error("GLYPH_WRITE_KEY is not set");
}

const glyph = new GlyphNode({
  writeKey,
});
```

Keep the write key in an environment variable. Use a `glyph_pk_...` key in production and a `glyph_test_...` key while testing the integration. [Configuration & delivery](/docs/reference/configuration) lists the shared constructor options. The Node client adds one option:

| Option        | Default | Description                                                                                                                   |
| ------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `flushOnExit` | `false` | Flush queued messages on the process's `beforeExit` event. A best-effort safety net — prefer explicit `flush()` or `close()`. |

## Identify customers with `profile`

Call `profile` when a customer signs up or when a profile trait changes. `userId` is the stable identity key, and every profile must include `email`.

```ts theme={"dark"}
await glyph.profile("user_123", {
  email: "sarah@example.com",
  name: "Sarah Chen",
  plan: "pro",
});
```

## Record actions with `track`

```ts theme={"dark"}
await glyph.track("user_123", "Invoice paid", {
  amount: 4900,
  currency: "USD",
});
```

Methods resolve once the message is queued. If a call reaches the `flushAt` threshold, its promise waits for that flush attempt. To backfill an event, pass its original timestamp as the fourth argument:

```ts theme={"dark"}
await glyph.track("user_123", "Invoice paid", { amount: 4900 }, {
  timestamp: new Date("2026-06-01T09:30:00Z"),
});
```

## Record account context with `group`

`group` records a group/account event on the customer's timeline. Glyph does not currently create a separate account record or provide group-level analytics.

```ts theme={"dark"}
await glyph.group("user_123", "acme_inc", { plan: "enterprise" });
```

## Flushing

Messages queue locally and flush when the queue reaches `flushAt` (default 20) or on the `flushIntervalMs` timer (default 5 s). In short-lived processes, flush explicitly before exiting:

```ts theme={"dark"}
await glyph.flush(); // send everything queued now
await glyph.close(); // stop the timer and flush — call on shutdown
```

### Serverless and API routes

Serverless runtimes can freeze or terminate as soon as a response is sent, taking your queue with them. Flush before responding:

```ts theme={"dark"}
import { GlyphNode } from "@glyphhq/node";
import { NextResponse } from "next/server";

const writeKey = process.env.GLYPH_WRITE_KEY;
if (!writeKey) {
  throw new Error("GLYPH_WRITE_KEY is not set");
}

const glyph = new GlyphNode({ writeKey });

export async function POST() {
  await glyph.track("user_123", "Report exported");
  await glyph.flush();

  return NextResponse.json({ ok: true });
}
```

## Handle delivery failures

The SDK retries transient delivery failures. Add an `onError` callback to log batches that still fail:

```ts theme={"dark"}
import { GlyphNode } from "@glyphhq/node";

const writeKey = process.env.GLYPH_WRITE_KEY;
if (!writeKey) {
  throw new Error("GLYPH_WRITE_KEY is not set");
}

const glyph = new GlyphNode({
  writeKey,
  onError: (error, messages, { retryable, status }) => {
    console.error(`Glyph delivery failed (${status ?? "network"})`, {
      retryable,
      dropped: retryable ? 0 : messages.length,
    });
  },
});
```

Retryable failures leave the batch queued for a later flush. Non-retryable failures, such as a `401` from an invalid write key, call `onError` and then drop the batch. See [Configuration & delivery](/docs/reference/configuration).
