Session Tracking
Correlate every request from a single user session across your backend services using an explicit session header or IP/user-agent fingerprinting as a fallback.
Session Tracking
Session tracking links every request to a consistent session identifier. This lets you answer questions like "show me everything that happened during this user's checkout session" — spanning all backend services, AI calls, and database queries.
How sessions are identified
The SDK uses two complementary mechanisms:
1. Explicit session header (primary)
When your frontend sends an auth token or session cookie, the SDK reads it, hashes it (SHA-256, one-way), and uses the hash as the session ID. The original token is never stored.
2. Fingerprinting (fallback)
For requests without an auth token — login pages, registration, public endpoints — the SDK falls back to fingerprinting (IP address, user-agent, etc.) to provide best-effort session continuity.
Fingerprinting on open routes provides a best-effort session ID. Once the user authenticates and the frontend starts sending a token, the session transitions to the explicit header approach. The two segments may not automatically merge in the dashboard.
Configuration
createSdk({
session: {
source: 'auto', // recommended for most applications
},
});Source options
| Source | Behavior |
|---|---|
'auto' | Tries JWT → cookies → Authorization header. Uses the first match. |
'jwt' | Reads Authorization: Bearer <token> and hashes the full token. |
'cookie' | Reads a named cookie. Set cookieName to specify which one. |
'header' | Reads a named header. Set headerName to specify which one. |
'none' | Disables session tracking entirely. |
JWT (most common)
createSdk({
session: { source: 'jwt' },
});If you are already sending JWT tokens with your API calls via Authorization: Bearer <token>, this works out of the box — no frontend changes required.
Cookie-based sessions
createSdk({
session: {
source: 'cookie',
cookieName: 'connect.sid', // Express Session default
},
});Other common cookie names:
next-auth.session-token— NextAuth.js__session— Firebase Auth / Remixsid— custom session implementations
Custom header
createSdk({
session: {
source: 'header',
headerName: 'x-session-token',
},
});Auto mode
auto tries the following in order and uses the first match:
Authorization: Bearer <token>(JWT)- Any cookie matching
cookieName(if set) Authorizationheader value
This is the recommended setting for most applications.
What the frontend needs to do
For the explicit header approach, the frontend must include the auth token or session cookie with each request. In most applications this is already the case.
// Axios — set globally
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
// fetch — set per request
fetch('/api/data', {
headers: { Authorization: `Bearer ${token}` },
});Cookies: If your auth token is in a cookie, the browser sends it automatically with same-origin requests. No frontend changes needed.
Session lifecycle
| Event | Session behavior |
|---|---|
| User logs in | Token changes → new session ID from next request |
| User logs out | Token cleared → fingerprint-only until next login |
| Token refresh | New token → new session ID (brief continuity gap) |
| Browser closed | Session ends; new session on next visit |
User identity
Session tracking and user identity work together. The SDK reads user ID and tenant ID from the request object after your auth middleware sets them:
createSdk({
userIdPath: 'user.id', // reads req.user.id
tenantIdPath: 'user.tenantId', // reads req.user.tenantId
});These are read at response finish time, so they are available regardless of where your auth middleware sets them relative to the Trasys middleware.
Attributes attached to every span:
| Attribute | Source |
|---|---|
trasys.user.id | req.user.id |
trasys.user.email | req.user.email (auto) |
trasys.user.role | req.user.role (auto) |
trasys.tenant.id | req.user.tenantId |
trasys.session.id | Hashed token or fingerprint |
trasys.session.source | jwt, cookie, header, or fingerprint |
Debugging specific users
To record 100% of requests for a specific user regardless of your sampling rate:
createSdk({
sampling: {
alwaysRecordUserIds: ['usr_problematic_customer_id'],
},
});Clear alwaysRecordUserIds once you are done debugging. Leaving specific users at 100% sampling in production increases data volume unexpectedly.
Next steps
Distributed Tracing
Propagate W3C TraceContext across HTTP, gRPC, and message queues so a request spanning multiple services appears as one unified trace in the Trasys dashboard.
Transport & Batching
How the SDK batches, sends, and retries telemetry — flush intervals, buffer size during network outages, and retry/backoff tuning.

