@altertable/altertable-js
JavaScript SDK for capturing and sending analytics events to Altertable.
Installation
npm install @altertable/altertable-js
# or
pnpm add @altertable/altertable-js
# or
yarn add @altertable/altertable-js
# or
bun add @altertable/altertable-js
Quick Start
import { altertable } from '@altertable/altertable-js';
// Initialize with your API key
altertable.init('YOUR_API_KEY');
// Track an event
altertable.track('Step Completed', {
step: 1,
});
// Identify a user
altertable.identify('u_01jza857w4f23s1hf2s61befmw', {
email: '[email protected]',
name: 'John Doe',
company: 'Acme Corp',
role: 'Software Engineer',
});
// Update user traits
altertable.updateTraits({
onboarding_completed: true,
});
// Link a new ID to the current identity
altertable.alias('new_user_id-019aca6a-1e42-71af-81a0-1e14bbe2ccbd');
Features
- Automatic page view tracking – Captures page views automatically
- Session management – Handles anonymous and session IDs automatically
- Offline delivery – Persists unsent events and retries when the browser comes back online
- Event queuing – Queues events when consent is pending
- Privacy compliance – Built-in tracking consent management
- Multiple storage options – localStorage, cookies, or both
- TypeScript support – Full TypeScript definitions included
- Lightweight – Minimal bundle size with no external dependencies
API Reference
Initialization
altertable.init(apiKey, config?)
Initializes the Altertable SDK with your API key and optional configuration.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
apiKey | string | Yes | Your Altertable API key for the target environment |
config | AltertableConfig | No | Configuration options |
Example:
altertable.init('YOUR_API_KEY');
Calling init again replaces configuration and discards any events still in the outbound batch buffer. If you need them sent first (for example before switching API keys), await altertable.flush() before calling init again.
Event Tracking
altertable.track(event, properties?)
Tracks a custom event with optional properties.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
event | string | Yes | - | The event name |
properties | EventProperties | No | {} | Custom event properties |
Example:
altertable.track('Purchase Completed', {
product_id: 'p_01jza8fr5efvgbxxdd1bwkd0m5',
amount: 29.99,
currency: 'USD',
});
altertable.page(url)
Tracks a page view event.
When autoCapture is enabled, this method is automatically called when the page URL changes.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | The page URL |
Example:
altertable.page('https://example.com/products');
[!NOTE]
Page Tracking: By default, Altertable automatically captures page views. Only use
page()when you've disabled auto-capture.Why use auto-capture (default)?
- No manual tracking required
- Handles browser navigation events (
popstate,hashchange)- Consistent tracking across all page changes
When to use
page():
- Custom routing that doesn't trigger browser events
- Virtual page views that don't trigger URL changes (modals, step changes)
- Server-side tracking where auto-capture isn't available
Existing analytics adapters
Reuse an existing PostHog implementation without changing its tracking calls. Initialize Altertable before PostHog:
import posthog from 'posthog-js';
import { altertable } from '@altertable/altertable-js';
altertable.init('ALTERTABLE_KEY', {
adapters: { posthog },
});
posthog.init('POSTHOG_KEY');
Altertable forwards PostHog events and disables its own collection.
track, page, identify, alias, and updateTraits calls are ignored, and
autocapture stays off while the adapter is configured.
Transforming events
Use transformEvent to customize a fully constructed track event before the
SDK queues, persists, or sends it. The transformer also runs for automatically
captured page views, so you can enrich them without disabling autoCapture or
adding router-specific tracking code.
altertable.init('YOUR_API_KEY', {
transformEvent(event) {
if (event.event === '$pageview') {
return {
...event,
properties: {
...event.properties,
title: document.title,
content_group: 'documentation',
},
};
}
return event;
},
});
The callback receives the complete TrackPayload, including
the event name, generated context, timestamp, and default properties. It runs
synchronously for events created by track() and page(); adapter, identity,
and alias payloads are not transformed.
Return null to discard an event:
altertable.init('YOUR_API_KEY', {
transformEvent(event) {
if (event.properties.internal_traffic === true) {
return null;
}
return event;
},
});
If the transformer throws, Altertable discards the event instead of sending
the original payload. The error is logged and passed to onError when an error
handler is configured. You can replace transformEvent at runtime with
altertable.configure({ transformEvent }).
User Identification
altertable.identify(userId, traits?)
Identifies a user with their ID and optional traits. It flags the identity as being a identitied user.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
userId | string | Yes | - | The user's unique identifier |
traits | UserTraits | No | {} | User properties |
Example:
altertable.identify('u_01jza857w4f23s1hf2s61befmw', {
email: '[email protected]',
name: 'John Doe',
company: 'Acme Corp',
role: 'Software Engineer',
});
altertable.updateTraits(traits)
Updates user traits for the current user.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
traits | UserTraits | Yes | User properties to update |
Example:
altertable.updateTraits({
onboarding_completed: true,
});
altertable.alias(newUserId)
Links a new ID to the current identity.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
newUserId | string | Yes | ------- | New ID to link to the current identity |
Example:
altertable.alias('new_user_id-019aca6a-1e42-71af-81a0-1e14bbe2ccbd');
Session Management
altertable.reset(options?)
Resets the current identity context so future events are not associated with the previous user.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
options | object | No | {} | Reset options |
options.resetDeviceId | boolean | No | false | Whether to reset device ID |
Example:
// Reset everything except device ID
altertable.reset();
// Reset all IDs
altertable.reset({
resetDeviceId: true,
});
Configuration
altertable.configure(updates)
Updates the configuration after initialization. A baseUrl change applies to new
requests; batches already in flight keep their original destination across retries.
If enabling autocapture fails to subscribe, calling configure({ autoCapture: true })
again retries registration.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
updates | AltertableConfigUpdates | Yes | Configuration updates |
Example:
altertable.configure({
trackingConsent: 'granted',
});
Privacy & Consent
altertable.getTrackingConsent()
Returns the current tracking consent state.
Returns: TrackingConsentType
Example:
const consent = altertable.getTrackingConsent();
if (consent === 'granted') {
// Tracking is allowed
}
Types
AltertableConfig
Configuration options for the Altertable SDK.
| Property | Type | Default | Description |
|---|---|---|---|
baseUrl | string | "https://api.altertable.ai" | The base URL of the Altertable API |
adapters | Adapters | - | Existing analytics instances; currently { posthog } |
mode | TrackingMode | "product" | Product analytics or restricted audience measurement; fixed until the next init() |
autoCapture | boolean | true; off while an adapter is set | Whether to automatically capture page views and events |
release | string | - | The release ID of the application |
debug | boolean | false | Whether to log events to the console |
persistence | StorageType | "localStorage+cookie" | The persistence strategy for IDs |
eventPersistence | StorageType or false | Same as persistence | The persistence strategy for unsent event payloads |
trackingConsent | TrackingConsentType | "granted" | The tracking consent state |
onError | (error: Error) => void | - | Optional handler for SDK errors |
transformEvent | TransformEvent | - | Transform or discard track and page-view events |
flushEventThreshold | number | 20 | Flush when combined buffered events reach this count |
flushIntervalMs | number | 150 | Periodic batch flush interval (ms) |
maxBatchSize | number | 20 | Max payloads per HTTP request |
Audience measurement
Use audience mode to collect aggregate usage statistics without persistent client identifiers:
altertable.init('YOUR_API_KEY', { mode: 'audience' });
altertable.track('Install Copied', { package: 'react' });
Page views and custom events automatically use audience processing. In this mode, the SDK:
- Omits user, anonymous, session, and device IDs from events.
- Keeps identity, consent, and unsent events in memory, overriding persistence options. Saved data is not restored, and unsent events are lost on reload.
- Ignores
identify(),alias(), andupdateTraits()calls. - Removes URL credentials, query parameters, fragments, referrer paths, and
viewport data. Invalid, relative, and non-HTTP URLs become
null. - Omits browser request credentials and the HTTP referrer on all deliveries.
Event names, custom properties, and URL paths can contain personal data. Use
transformEvent to remove it before transmission. The SDK applies audience
restrictions after the transform. Adapters forward source identities and
properties and do not support audience mode.
trackingConsent controls delivery: pending or dismissed events wait in memory,
and denied events are discarded. Supply the consent state on each init().
To change modes, call init(). configure() cannot change mode.
Reinitialization discards buffered events; call flush() first if you want to
send them.
Search measurement
Audience mode strips search query parameters such as q from automatic page
tracking. Track searches explicitly to measure usage and result counts:
altertable.track('Search Performed', {
category: 'documentation',
result_count: results.length,
});
Search terms can contain personal data. If you need to collect them, explicitly
add a search_term property after reviewing which values are safe to send.
Offline Delivery
Altertable can persist unsent event payloads so they survive reloads and send when the browser comes back online. By default, event payloads use the same storage strategy as persistence, but cookie-backed strategies store event payloads in localStorage only.
If you do not want event payloads written to durable browser storage, set eventPersistence: false. Events will still batch in memory for the current page session, but they will not survive a reload.
altertable.init('YOUR_API_KEY', {
eventPersistence: false,
});
AltertableConfigUpdates
Options accepted by configure(). Includes the fields in AltertableConfig
except mode, which is set through init().
EventProperties
Custom properties for events.
type EventProperties = Record<string, unknown>;
Example:
{
product_id: 'p_01jza8fr5efvgbxxdd1bwkd0m5',
amount: 29.99,
currency: 'USD',
category: 'electronics',
user_type: 'premium'
}
TrackPayload
The complete payload passed to transformEvent in both tracking modes. Product
mode sends the transformed TrackPayload; audience mode applies its restrictions
and sends an AudienceTrackPayload without identity fields.
type TrackPayload = {
event: string;
properties: EventProperties;
timestamp: string;
device_id: `device-${string}`;
distinct_id: string;
anonymous_id: `anonymous-${string}` | null;
session_id: `session-${string}`;
};
AudienceTrackPayload
The audience payload sent to the track API after transformEvent:
type AudienceTrackPayload = {
mode: 'audience';
event: string;
properties: EventProperties;
timestamp: string;
};
TransformEvent
type TransformEvent = (event: TrackPayload) => TrackPayload | null;
EventProperties, TrackPayload, AudienceTrackPayload, and TransformEvent
are exported from @altertable/altertable-js for use in application code.
UserTraits
User properties for identification.
type UserTraits = Record<string, unknown>;
Example:
{
email: '[email protected]',
name: 'John Doe',
company: 'Acme Corp',
role: 'Software Engineer',
plan: 'premium',
signup_date: '2024-01-15'
}
StorageType
persistence and eventPersistence also accept a custom synchronous storage
adapter. It must implement getItem(key): string | null,
setItem(key, value): boolean, and removeItem(key): void. Return false from
setItem when a write fails. Async backends must finish hydration before
initialization and provide a synchronous in-memory adapter; do not pass an async
storage API directly.
Thrown custom write and deletion errors reach onError. Failed event writes leave
events in memory, and storage errors do not requeue acknowledged events. Read
errors propagate to init() or configure(); after a failed migration read, fix
the backend and retry the same configuration.
Use the exported getStorageKeys(apiKey) to resolve the API-key-scoped session
and events keys before hydration.
For custom runtimes, supply a platform to the constructor.
Its isOnline() method reads connectivity; returning false retains buffered
events until a later flush.
The Altertable constructor is exported for applications that need separate
client instances. Call the cleanup function returned by init() when disposing
an instance.
Available storage strategies.
| Value | Description |
|---|---|
"localStorage" | Use localStorage only |
"sessionStorage" | Use sessionStorage only |
"cookie" | Use cookies only |
"memory" | Use in-memory storage (not persisted) |
"localStorage+cookie" | Use localStorage with cookie fallback |
TrackingMode
| Value | Behavior |
|---|---|
"product" | Product analytics with identity, profiles, and configurable persistence. |
"audience" | Aggregate usage measurement without persistent client identifiers. |
TrackingConsentType
Available tracking consent states.
| Value | Description |
|---|---|
"granted" | User has granted consent for tracking |
"denied" | User has denied consent for tracking |
"pending" | User hasn't made a decision yet |
"dismissed" | User dismissed the consent prompt |
Runtime platforms
new Altertable() uses browserPlatform by default. Supply a Platform to the
constructor when hosting the core SDK in another runtime. The platform is fixed
for the client's lifetime and is available before init(), so queued events keep
the context captured when they were recorded.
import { Altertable, type Platform } from '@altertable/altertable-js';
const platform: Platform = {
getContext: () => ({ properties: { runtime: 'worker' } }),
};
const client = new Altertable(platform);
client.track('Started');
const cleanup = client.init('YOUR_API_KEY', { persistence: 'memory' });
await client.flush();
cleanup();
| Capability | Contract |
|---|---|
getContext() | Return the current URL, referrer, viewport, and default event properties. Omitted browser fields become null. Event properties can override defaults. |
isOnline() | Read connectivity without side effects. Omitting it assumes connectivity. |
subscribeLifecycle(listener) | Report active, inactive, online, or exit; return a cleanup function. Active, inactive, and online events request normal delivery. |
subscribeUrlChanges(listener) | Report subsequent URL changes; return a cleanup function. With autoCapture enabled, the SDK records the initial URL and tracks changes with the previous URL as referrer. |
prepareDelivery() | Await prerequisites before sending each fixed normal delivery snapshot. Resolve with true or undefined to proceed, false to defer, or reject to prevent the attempt. This does not run for exit transport or each HTTP retry. |
sendOnExit({ url, body }) | Optionally provide synchronous best-effort exit delivery. Events remain persisted until normal delivery succeeds. Without this capability, an exit event requests normal delivery. |
Only getContext() is required. Missing subscriptions disable those integrations;
the SDK does not substitute browser implementations for an explicitly supplied
platform. Storage remains a separate dependency through persistence and
eventPersistence, which accept a StorageAdapter.
Normal delivery respects tracking consent and connectivity. For platforms with
asynchronous delivery preparation, overlapping automatic requests are coalesced;
new threshold events trigger a subsequent snapshot, while failed requests wait
for a later trigger. Overlapping lifecycle or interval requests share the current
snapshot; events below the threshold remain batched until the next trigger.
Snapshots select events before preparation starts; later arrivals require their
own prepared snapshot. Explicit flush() continues draining, preparing every new
snapshot. flush({ drain: false }) shares the automatic delivery task on these
platforms. Preparation failures reach onError for automatic attempts and reject
explicit flushes.
Cleanup stops platform subscriptions, timers, and further delivery. Subscription ownership is revoked before cleanup runs, so queued callbacks and callbacks retained by failed cleanup are ignored. Retired batchers cannot modify storage when old requests finish. Cleanup, reset, and consent denial cancel HTTP retries; cleanup and reinitialization also prevent pending preparation from starting stale delivery. Reinitialize before continuing to use a cleaned-up client.
To extend browser behavior, compose the exported implementation directly:
import { Altertable, browserPlatform } from '@altertable/altertable-js';
const client = new Altertable({
...browserPlatform,
getContext() {
return {
...browserPlatform.getContext(),
properties: { application: 'dashboard' },
};
},
});
The React Native package supplies native context, AppState lifecycle handling, optional connectivity, and asynchronous storage preparation through this same contract. Analytics-provider subscriptions are independent of browser detection; a configured provider must satisfy its own adapter contract.