Identity
Grounded has two identity layers now:
- lightweight server-side identity in
@grounded/tracing - stable browser identity and session context in
@grounded/analytics
Server Identity In @grounded/tracing
tracing.identify({
userId: 'user_123',
sessionId: 'chat_123',
anonymousId: 'anon_123',
traits: {
email: 'jane@example.com',
plan: 'pro',
region: 'us',
},
});The tracing SDK stores those traits in process memory and attaches them to future traces that match:
- the same
userId - the same
sessionId - or the same
anonymousId
Traits are merged into trace.metadata.identityTraits.
Browser Identity In @grounded/analytics
const analytics = init({
apiKey: process.env.NEXT_PUBLIC_GROUNDED_PUBLISHABLE_KEY!,
agentId: 'agt_support',
});
analytics.identify('user_123', {
plan: 'pro',
region: 'us',
});The analytics SDK persists:
sessionIdanonymousIduserId
and exposes them with:
const context = analytics.getContext();Primary Correlation Pattern
Use analytics.getContext() as the browser-to-server handoff contract.
Browser:
const groundedContext = analytics.getContext();
await fetch('/api/support/reply', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
message,
grounded: groundedContext,
}),
});Server:
const trace = tracing.startTrace({
name: 'support.reply',
sessionId: req.body.grounded.sessionId,
anonymousId: req.body.grounded.anonymousId,
userId: req.body.grounded.userId,
resource: { agentId: 'agt_support', snapshotId: 'snap_live' },
});This is what lets Grounded merge browser telemetry and backend traces into one session timeline.
Important Limits
@grounded/tracing
- traits are in-memory only
- there is no cookie persistence
- identity state is not shared across processes unless your app does it
@grounded/analytics
- browser identity is for telemetry correlation, not profile storage
- traits should stay small and non-sensitive
- if you call
reset(), a newsessionIdandanonymousIdare generated
Recommendations
- use your internal stable user ID, not email, as the primary
userId - treat traits as helpful context, not canonical profile storage
- forward
getContext()on any request that also emits backend traces