Skip to content

Node.js SDK

Server-side tracking for Node.js. Events are queued in memory, batched, and delivered asynchronously to /v1/batch with your write key — your request path never blocks on analytics.

Terminal window
npm install @origamy/node-sdk
import { New, Track } from "@origamy/node-sdk";
const client = New(process.env.ORIGAMY_WRITE_KEY);
client.enqueue(new Track({
userId: "user-123",
event: "Signed Up",
}));
// Flush any queued messages and close the client.
await client.close();

By default the client flushes every 5 seconds or 250 events, whichever comes first, and sends to https://events.origamy.io.

NewWithConfig validates the config and returns a Go-style [client, err] tuple:

import { NewWithConfig } from "@origamy/node-sdk";
const [client, err] = NewWithConfig(process.env.ORIGAMY_WRITE_KEY, {
endpoint: "https://events.yourcompany.com", // your gateway on a self-hosted data plane
verbose: process.env.ORIGAMY_VERBOSE === "true",
});
if (err) throw err;
Option Default Description
endpoint https://events.origamy.io Ingestion endpoint. Point at your own gateway on a self-hosted data plane.
intervalMs 5000 Flush interval.
batchSize 250 Events per batch before an early flush.
verbose false Log deliveries and errors.
logger console Custom logger implementation.
dispatcher HTTP Custom transport — see development mode below.
queue / queueCapacity in-memory Custom or bounded queue.
defaultContext Context merged into every event.
retryAfter exponential (attempt) => ms backoff strategy.
maxConcurrentRequests Cap on in-flight batch requests.

The message types mirror the event spec — construct one and enqueue it:

import {
New, Track, Identify, Page, Group, Alias,
NewProperties, NewTraits,
} from "@origamy/node-sdk";
const client = New(process.env.ORIGAMY_WRITE_KEY);
// Track an action
client.enqueue(new Track({
userId: "user-123",
event: "Order Completed",
properties: NewProperties()
.set("orderId", "ORD-9999")
.setRevenue(99.99)
.setCurrency("USD"),
}));
// Identify a user with traits
client.enqueue(new Identify({
userId: "user-123",
traits: NewTraits()
.setEmail("[email protected]")
.setName("Alice Smith")
.set("plan", "pro"),
}));
// Track a page view
client.enqueue(new Page({
userId: "user-123",
name: "Pricing",
properties: { url: "https://example.com/pricing" },
}));
// Associate a user with a group/company
client.enqueue(new Group({
userId: "user-123",
groupId: "company-acme",
traits: NewTraits().setName("Acme Corp"),
}));
// Alias an anonymous ID to an identified user
client.enqueue(new Alias({
userId: "user-123",
previousId: "anon-session-abc",
}));

For anonymous tracking, pass anonymousId instead of (or alongside) userId.

Use the NoopDispatcher to log events to the console instead of sending them:

import { NewWithConfig, NoopDispatcher, Track } from "@origamy/node-sdk";
const [client, err] = NewWithConfig("your-write-key", {
dispatcher: new NoopDispatcher({ verbose: true }),
});
if (err) throw err;
client.enqueue(new Track({ userId: "user-123", event: "button_clicked" }));
await client.close();

Always close the client before the process exits so queued events are flushed:

process.on("SIGTERM", async () => {
await client.close();
process.exit(0);
});

Wrap the client in an injectable service so tracking is one call anywhere in your app, and flushing happens on shutdown via OnModuleDestroy:

import { Injectable, Logger, OnModuleDestroy } from "@nestjs/common";
import { Client, NewWithConfig, Track, Identify } from "@origamy/node-sdk";
@Injectable()
export class AnalyticsService implements OnModuleDestroy {
private readonly logger = new Logger(AnalyticsService.name);
private readonly client: Client | null;
constructor() {
const [client, err] = NewWithConfig(process.env.ORIGAMY_WRITE_KEY, {
endpoint: process.env.ORIGAMY_HOST || "https://events.origamy.io",
verbose: process.env.ORIGAMY_VERBOSE === "true",
});
if (err) {
this.logger.error(`Failed to init Origamy client: ${err.message}`);
this.client = null;
} else {
this.client = client;
}
}
identify(userId: string, traits?: Record<string, unknown>): void {
if (!this.client || !userId) return;
this.client.enqueue(new Identify({ userId, traits }));
}
track(userId: string, event: string, properties?: Record<string, unknown>): void {
if (!this.client || !userId) return;
this.client.enqueue(new Track({ userId, event, properties }));
}
async onModuleDestroy(): Promise<void> {
await this.client?.close();
}
}
// anywhere in your app
this.analyticsService.identify(userId, { plan: "pro" });
this.analyticsService.track(userId, "Order Completed", { amount: 99.99 });

Batches post to POST /v1/batch using the same payload as every Origamy SDK, authenticated with HTTP Basic auth (write key as username, empty password). See the Ingestion API for endpoints, limits, and response codes.