Documentation Index
Fetch the complete documentation index at: https://docs.tell.rs/llms.txt
Use this file to discover all available pages before exploring further.
npm install @tell-rs/node
A server-side SDK — you create a client, pass a user ID on every call, and a background worker handles batching and delivery over HTTP + JSONL. Zero dependencies.
Data collected server-side is trustworthy and tamper-proof. Unlike the browser SDK, the Node.js SDK doesn’t auto-collect device context — you control exactly what properties are sent.
Quick start
import { Tell, production, Events } from "@tell-rs/node";
const tell = new Tell(production("a1b2c3d4e5f60718293a4b5c6d7e8f90"));
tell.track("user_123", "Page Viewed", { url: "/home" });
tell.identify("user_123", { name: "Jane", plan: "pro" });
await tell.close();
Verify it works
In development mode (logLevel: "debug"), the SDK logs to the console when events are batched and flushed. You can also call await tell.flush() and check that no error is reported via onError.
Configuration
Two presets are available:
// Production — default endpoint, batch 100, flush 10s, error-only logging
const tell = new Tell(production("YOUR_API_KEY"));
// Development — localhost:8080, batch 10, flush 2s, debug logging
const tell = new Tell(development("YOUR_API_KEY"));
For custom settings:
const tell = new Tell({
apiKey: "YOUR_API_KEY",
endpoint: "https://collect.internal",
batchSize: 200,
flushInterval: 5_000,
maxRetries: 5,
closeTimeout: 10_000,
networkTimeout: 60_000,
logLevel: "debug",
gzip: true,
onError: (e) => console.error("[Tell]", e),
});
Tracking events
Every method takes userId as its first parameter. For details on each event type and when to use them, see Events & Properties.
tell.track("user_123", "Feature Used", { feature: "dark_mode", enabled: true });
tell.identify("user_123", { name: "Jane", email: "jane@example.com" });
tell.group("user_123", "company_456", { plan: "enterprise" });
tell.revenue("user_123", 49.99, "USD", "order_789", { product: "annual_plan" });
tell.alias("anon_visitor_abc", "user_123");
Pass undefined when you don’t need properties:
tell.track("user_123", "App Started");
Standard event names
import { Events } from "@tell-rs/node";
tell.track("user_123", Events.PageViewed, { url: "/pricing" });
tell.track("user_123", Events.UserSignedUp, { source: "organic" });
tell.track("user_123", Events.OrderCompleted, { total: 99.00 });
tell.track("user_123", Events.FeatureUsed, { feature: "export" });
Constants cover user lifecycle, revenue, subscriptions, trials, shopping, engagement, and communication events. Custom string names always work too.
Super properties
tell.register({ app_version: "2.1.0", env: "production" });
// This track call automatically includes app_version and env
tell.track("user_123", "Click", { button: "submit" });
tell.unregister("env");
Event-specific properties override super properties when keys conflict. See Events & Properties for more on property patterns.
Structured logging
tell.logError("Payment failed", "billing", { error: "card_declined", amount: 9.99 });
tell.logInfo("User signed in", "auth", { method: "oauth" });
tell.logWarning("High memory usage", "api");
The service parameter defaults to "app". Nine severity levels from logEmergency to logTrace. See Logs for the full level reference and when to use each.
Generic logging method:
tell.log("error", "Something broke", "worker", { job_id: "j_123" });
Redaction & beforeSend
Transform or drop events before they’re queued. Return null to drop an item. Supports a single function or an array of functions applied in order.
Drop health-check events
const tell = new Tell({
apiKey: "YOUR_API_KEY",
beforeSend: (event) => {
if (event.properties?.url === "/health") return null;
return event;
},
});
Scrub user PII from traits
const tell = new Tell({
apiKey: "YOUR_API_KEY",
beforeSend: (event) => {
if (event.traits?.email) {
return { ...event, traits: { ...event.traits, email: "[REDACTED]" } };
}
return event;
},
beforeSendLog: [scrubPII, addTimezone], // pipeline of functions
});
redact() utility
For common patterns, use the built-in redact() factory:
import { Tell, redact, redactLog, SENSITIVE_PARAMS } from "@tell-rs/node";
const tell = new Tell({
apiKey: "YOUR_API_KEY",
beforeSend: redact({
dropRoutes: ["/health", "/readyz"],
stripParams: SENSITIVE_PARAMS,
redactKeys: ["email", "phone", "ssn"],
}),
beforeSendLog: redactLog({
redactKeys: ["password", "credit_card"],
}),
});
You can combine redact() with custom hooks in an array:
const tell = new Tell({
apiKey: "YOUR_API_KEY",
beforeSend: [
redact({ stripParams: SENSITIVE_PARAMS }),
myCustomHook,
],
});
Server-side redaction prevents sensitive data from ever leaving your infrastructure. For defense in depth, also configure pipeline redaction to catch anything that slips through.
Lifecycle
await tell.flush(); // Force-send all queued events
tell.resetSession(); // Rotate session ID
await tell.close(); // Flush + shut down
Always call close() before your process exits to avoid losing buffered events.
Error handling
Tracking calls (track, identify, group, revenue, alias) and logging calls never throw. Validation errors and network failures route through the onError callback:
const tell = new Tell({
apiKey: "YOUR_API_KEY",
onError: (err) => console.error("[Tell]", err.message),
});
Constructor and lifecycle methods (flush, close) can throw or reject — handle these in your application code.
Retry behavior
On HTTP send failure (5xx or network error), the SDK retries with exponential backoff: 1-second base delay, 1.5x multiplier, 20% jitter, capped at 30 seconds. After maxRetries attempts (default: 3), the batch is dropped and reported via onError.
4xx errors (except 413) are not retried — they indicate a client-side issue (e.g. invalid API key). On 413 (payload too large), the SDK automatically halves the batch size for future sends.
Configuration reference
| Parameter | Production | Development | Description |
|---|
endpoint | https://collect.tell.app | http://localhost:8080 | HTTP collector URL |
batchSize | 100 | 10 | Events per batch before auto-flush |
flushInterval | 10,000 ms | 2,000 ms | Time between auto-flushes |
maxRetries | 3 | 3 | Retry attempts on send failure |
closeTimeout | 5,000 ms | 5,000 ms | Max wait on close() |
networkTimeout | 30,000 ms | 30,000 ms | HTTP request timeout |
maxQueueSize | 1,000 | 1,000 | Max queued items before oldest drops |
gzip | false | false | Compress payloads with gzip |
source | os.hostname() | os.hostname() | Log source identifier |
logLevel | error | debug | SDK log verbosity |
disabled | false | false | Drop all events locally |