Skip to main content
The JavaScript SDK is a family of packages for sending events and structured logs to Tell from any JS/TS environment.
PackageEnvironmentInstall
tell-nodeNode.js serversnpm install tell-node
@tell-rs/browserBrowsersnpm install @tell-rs/browser
@tell-rs/reactReact appsnpm install @tell-rs/react
@tell-rs/nextjsNext.js appsnpm install @tell-rs/nextjs
@tell-rs/vueVue appsnpm install @tell-rs/vue
Server (tell-node) and client (@tell-rs/browser) are standalone — framework packages wrap the browser SDK with idiomatic bindings.

Node.js (server)

A server SDK — you create a client, pass a user ID on every call, and a background worker handles batching and delivery over HTTP.

Quick start

import { Tell, production, Events } from "tell-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();
Zero dependencies. The client batches up to 100 events and flushes every 10 seconds over HTTP + JSONL.

Configuration

// Production — default endpoint, batch 100, flush 10s
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.
tell.track("user_123", "Feature Used", { feature: "dark_mode", enabled: true });

tell.identify("user_123", { name: "Jane", email: "[email protected]" });

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-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.

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 the machine hostname. Convenience methods are available for all nine RFC 5424 levels: logEmergency, logAlert, logCritical, logError, logWarning, logNotice, logInfo, logDebug, and logTrace.

beforeSend hooks

Transform or drop events before they’re queued:
const tell = new Tell({
  apiKey: "YOUR_API_KEY",
  beforeSend: (event) => {
    if (event.user_id === "test") return null; // drop
    return event; // pass through
  },
  beforeSendLog: [scrubPII, addTimezone], // pipeline of functions
});
Return null to drop an item. Supports a single function or an array of functions applied in order.

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.

Configuration reference

ParameterDefaultDescription
endpointhttps://collect.tell.appHTTP collector URL
batchSize100Events per batch before auto-flush
flushInterval10,000 msTime between auto-flushes
maxRetries3Retry attempts on send failure
closeTimeout5,000 msMax wait on close()
networkTimeout30,000 msHTTP request timeout
maxQueueSize1,000Max queued items before oldest drops
gzipfalseCompress payloads with gzip
sourceos.hostname()Log source identifier
disabledfalseDrop all events locally

Browser (client)

A client SDK — you configure a singleton once, and it handles device IDs, sessions, and delivery automatically. No user ID needed on track calls.

Quick start

import { tell } from "@tell-rs/browser";

tell.configure("a1b2c3d4e5f60718293a4b5c6d7e8f90");

tell.track("Page Viewed", { url: "/home" });
tell.identify("user_123", { name: "Jane", plan: "pro" });
Events called before configure() are queued and replayed once ready.

Configuration

tell.configure("YOUR_API_KEY", {
  endpoint: "https://collect.tell.app",
  batchSize: 20,
  flushInterval: 5_000,
  sessionTimeout: 30 * 60 * 1000,
  persistence: "localStorage",
  respectDoNotTrack: false,
  botDetection: true,
  captureErrors: false,
  onError: (e) => console.error("[Tell]", e),
});

Tracking events

No user ID parameter — the SDK tracks the current user automatically (anonymous until you call identify).
tell.track("Feature Used", { feature: "dark_mode", enabled: true });
tell.identify("user_123", { name: "Jane", email: "[email protected]" });
tell.group("company_456", { plan: "enterprise" });
tell.revenue(49.99, "USD", "order_789", { product: "annual_plan" });
tell.alias("anon_visitor_abc", "user_123");

Sessions

Sessions are managed automatically:
  1. Generates a persistent device ID (stored in localStorage)
  2. Creates a new session on page load
  3. Tracks tab visibility changes
  4. Starts a new session after 30 minutes of inactivity (configurable via sessionTimeout)
  5. Captures UTM parameters from the URL as super properties
Device context collected automatically includes browser, OS, screen dimensions, viewport, locale, timezone, referrer, connection type, and touch support.

Privacy

tell.optOut();               // Stop all tracking — events are dropped locally
tell.optIn();                // Resume tracking
tell.isOptedOut();           // Check current state
tell.reset();                // Clear user, device ID, session, super properties
Opt-out state is persisted to localStorage. Set respectDoNotTrack: true to honor the browser’s Do Not Track setting.

Browser-specific features

Bot detection — automatically disables tracking when navigator.webdriver is set or the user agent contains “headless”. Controlled by botDetection (default: true). Error auto-capture — set captureErrors: true to automatically log window.onerror and unhandledrejection events. Page unload — the SDK flushes via navigator.sendBeacon on beforeunload and visibilitychange to minimize data loss.

Configuration reference

ParameterDefaultDescription
endpointhttps://collect.tell.appHTTP collector URL
batchSize20Events per batch before auto-flush
flushInterval5,000 msTime between auto-flushes
maxRetries5Retry attempts on send failure
networkTimeout10,000 msHTTP request timeout
sessionTimeout1,800,000 msInactivity time before new session
persistencelocalStorage"localStorage" or "memory"
respectDoNotTrackfalseHonor browser DNT setting
botDetectiontrueAuto-disable for bots/headless
captureErrorsfalseAuto-log uncaught errors
maxQueueSize1,000Max queued items before oldest drops

React

Wrap your app with TellProvider, then use hooks for tracking.
npm install @tell-rs/react @tell-rs/browser

Setup

import { TellProvider } from "@tell-rs/react";

function App() {
  return (
    <TellProvider apiKey="YOUR_API_KEY" options={{ captureErrors: true }}>
      <MyApp />
    </TellProvider>
  );
}
The provider calls tell.configure() on mount and tell.close() on unmount.

Hooks

import { useTell, useTrack, useIdentify } from "@tell-rs/react";

function SignUpButton() {
  const track = useTrack();
  const identify = useIdentify();

  function handleSignUp(user) {
    identify(user.id, { name: user.name });
    track("Sign Up Completed", { plan: "pro" });
  }

  return <button onClick={handleSignUp}>Sign Up</button>;
}
useTell() returns the full browser SDK instance. useTrack() and useIdentify() return stable callbacks safe for dependency arrays.

Direct access

import { tell } from "@tell-rs/react";
tell.track("Background Task");

Next.js

A drop-in component for the App Router with automatic page view tracking.
npm install @tell-rs/nextjs @tell-rs/browser

Setup

// app/layout.tsx
import { Tell } from "@tell-rs/nextjs";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Tell apiKey="YOUR_API_KEY" />
        {children}
      </body>
    </html>
  );
}
The Tell component watches usePathname() and useSearchParams() and fires a Page Viewed event on every route change. Disable with trackPageViews={false}.

Manual tracking

"use client";
import { tell } from "@tell-rs/nextjs";

tell.track("Checkout Started", { items: 3 });
tell.identify("user_123", { plan: "pro" });

Vue

A plugin with a composable and global $tell property.
npm install @tell-rs/vue @tell-rs/browser

Setup

import { createApp } from "vue";
import { TellPlugin } from "@tell-rs/vue";

const app = createApp(App);
app.use(TellPlugin, { apiKey: "YOUR_API_KEY" });
app.mount("#app");
The plugin calls tell.configure() on install and tell.close() on app unmount.

Composable

<script setup>
import { useTell } from "@tell-rs/vue";

const tell = useTell();

function onSignUp() {
  tell.track("Sign Up Clicked", { plan: "pro" });
  tell.identify("user_123", { name: "Alice" });
}
</script>

<template>
  <button @click="onSignUp">Sign Up</button>
</template>

Page view tracking with Vue Router

import { tell } from "@tell-rs/vue";
import router from "./router";

router.afterEach((to) => {
  tell.track("Page Viewed", { path: to.path, url: to.fullPath });
});

Validation rules

These apply to all packages:
FieldRule
API key32-character hex string
User IDNon-empty
Event name1–256 characters
Log message1–65,536 characters
Group IDNon-empty
Revenue amountPositive number
CurrencyNon-empty
Order IDNon-empty