Skip to main content
This page describes behavior that is the same in spirit for Node and Python. Language-specific names are called out in tabs only where they differ.

How server sessions work

Server SDKs maintain an in-memory server session per distinct_id (and optional explicit session id):
  1. A session object is created with a new UUID for session_id unless you pass one (to match the browser).
  2. Before the first event or identify call, the SDK ensures the session is registered with Trodo by posting to POST /api/sdk/track with a synthetic session payload (referrer: "server", device_type: "server", etc.).
  3. Custom events are sent to POST /api/events with session_id, user_id, event_name, event_category, and custom_properties.
You normally do not interact with session_id directly; use forUser / for_user (or the direct methods) and optionally pass sessionId / session_id for correlation.

Correlating with the browser

If the user already has a Trodo session in the browser, pass that session id when creating the user context:
const user = client.forUser(distinctId, {
  sessionId: req.cookies.trodo_session_id,
});
await user.track('checkout_validated', { ok: true });

Custom events (track)

Unified behavior
  • Sends a custom event (event_type: custom) with your event_name and JSON-serializable properties (stored as custom_properties).
  • Default event_category is custom. Override per call where the SDK allows.
await client.forUser('user-1').track('subscription_created', {
  plan: 'pro',
  mrr_cents: 9900,
});

// Optional category (maps to event_category on the wire)
await client.forUser('user-1').track('risk_flag', { score: 0.8 }, { category: 'security' });

// Alias
await client.forUser('user-1').trackEvent('same_as_track', {});
Direct style:
await client.track('user-1', 'subscription_created', { plan: 'pro' });
Implementation note: Node’s track options use a TrackOptions object (category, optional timestamp in types); Python passes category as a third positional argument on track / track_event.

Batching

When batch mode is enabled at client construction:
  • Events are queued in memory.
  • The SDK flushes when the queue reaches batchSize / batch_size, on a timer (batchFlushIntervalMs / batch_flush_interval), or when you call flush().
  • Flushes use POST /api/events/bulk with { events: [...] }.
const client = new TrodoClient({
  siteId: '...',
  batchEnabled: true,
  batchSize: 50,
  batchFlushIntervalMs: 5000,
});

await client.forUser('u1').track('a');
await client.flush(); // before shutdown or deploy
await client.shutdown();
Use batching for high-volume workers; keep shutdown() / flush() on process exit so events are not dropped.

Identify

Unified behavior: links the current distinct id to an application identify_id (e.g. database user id, Stripe customer id). The API is POST /api/sdk/identify with siteId, sessionId, userId, distinctId, and identifyId. The response may include a merged newDistinctId. The SDK updates the in-memory session’s distinct id when merging occurs.
const result = await client.forUser(anonymousId).identify('user_db_999');
// result.newDistinctId, result.merged, etc.
Caching subtlety (Python): TrodoClient caches UserContext by the original for_user key. After a merge, prefer using the returned distinct id for new for_user calls in long-lived processes if you need strict alignment with the merged profile. The Node client updates internal session maps when newDistinctId is returned; behavior is equivalent for typical request-scoped usage.

Reset

Clears the server-side session for that user context and notifies the backend via POST /api/sdk/reset.
await client.forUser(distinctId).reset();
// Also evicts cached UserContext for that distinctId on client.reset(distinctId)

Wallet address

Associates a wallet address with the user (POST /api/sdk/wallet-address). Same session and identity rules as identify.
await client.forUser(distinctId).walletAddress('0x...');

Manual error capture

Both SDKs expose captureError / capture_error on UserContext to record an exception as an analytics event (separate from auto global handlers).
try {
  await doWork();
} catch (e) {
  await client.forUser(userId).captureError(e, 'error');
}
Severity on Node is typed as 'critical' | 'error' | 'warning'; Python accepts a string (same values recommended).

Singleton helpers

If you use trodo.init / import trodo (Python) or trodo.init / default export (Node), the same operations exist as top-level functions: track, identify, reset, walletAddress / wallet_address, etc. See Overview.