From 4bf814ee537134818c9a29bfa75b27e077f0376a Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 3 Jun 2026 13:23:33 +0200 Subject: [PATCH 1/2] feat(browser): Attach `session.id` to outgoing telemetry --- .../src/integrations/browsersession.ts | 54 ++++++++++++++++++- packages/core/src/semanticAttributes.ts | 2 + 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/browser/src/integrations/browsersession.ts b/packages/browser/src/integrations/browsersession.ts index 7d339baa42d5..985f768c6e16 100644 --- a/packages/browser/src/integrations/browsersession.ts +++ b/packages/browser/src/integrations/browsersession.ts @@ -1,4 +1,11 @@ -import { captureSession, debug, defineIntegration, getIsolationScope, startSession } from '@sentry/core/browser'; +import { + captureSession, + debug, + defineIntegration, + getIsolationScope, + SEMANTIC_ATTRIBUTE_SESSION_ID, + startSession, +} from '@sentry/core/browser'; import { addHistoryInstrumentationHandler } from '@sentry-internal/browser-utils'; import { DEBUG_BUILD } from '../debug-build'; import { WINDOW } from '../helpers'; @@ -29,6 +36,51 @@ export const browserSessionIntegration = defineIntegration((options: BrowserSess return { name: 'BrowserSession', + setup(client) { + function attachSessionId | undefined }>(telemetryItem: T): T { + const session = getIsolationScope().getSession(); + const attributes = telemetryItem.attributes ?? (telemetryItem.attributes = {}); + if (session?.sid && !attributes?.[SEMANTIC_ATTRIBUTE_SESSION_ID]) { + attributes[SEMANTIC_ATTRIBUTE_SESSION_ID] = session.sid; + } + return telemetryItem; + } + + client.on('processMetric', attachSessionId); + client.on('beforeCaptureLog', attachSessionId); + // only applies to streamed spans + client.on('processSpan', attachSessionId); + + // for errors and transactions (non-streamed spans) + client.addEventProcessor(event => { + if (event.type && event.type !== 'transaction') { + return event; + } + + const sessionId = getIsolationScope().getSession()?.sid; + if (!sessionId) { + return event; + } + + if (!event.tags?.[SEMANTIC_ATTRIBUTE_SESSION_ID]) { + event.tags = { + ...event.tags, + [SEMANTIC_ATTRIBUTE_SESSION_ID]: sessionId, + }; + } + + event.spans?.forEach(span => { + if (!span.data?.[SEMANTIC_ATTRIBUTE_SESSION_ID]) { + span.data = { + ...span.data, + [SEMANTIC_ATTRIBUTE_SESSION_ID]: sessionId, + }; + } + }); + + return event; + }); + }, setupOnce() { if (typeof WINDOW.document === 'undefined') { DEBUG_BUILD && diff --git a/packages/core/src/semanticAttributes.ts b/packages/core/src/semanticAttributes.ts index fd3b0e0c4022..7ff72dee4a08 100644 --- a/packages/core/src/semanticAttributes.ts +++ b/packages/core/src/semanticAttributes.ts @@ -116,3 +116,5 @@ export const SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE = 'sentry.link.type'; * For LangGraph: configurable.thread_id */ export const GEN_AI_CONVERSATION_ID_ATTRIBUTE = 'gen_ai.conversation.id'; + +export const SEMANTIC_ATTRIBUTE_SESSION_ID = 'session.id'; From 5ef0ac61a9b07ad58d12ebabde35f47bbb99cfae Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Wed, 3 Jun 2026 14:45:25 +0200 Subject: [PATCH 2/2] set session context instead of tags --- .../src/integrations/browsersession.ts | 25 ++++++++++--------- packages/core/src/types/context.ts | 5 ++++ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/browser/src/integrations/browsersession.ts b/packages/browser/src/integrations/browsersession.ts index 985f768c6e16..eb149084343a 100644 --- a/packages/browser/src/integrations/browsersession.ts +++ b/packages/browser/src/integrations/browsersession.ts @@ -54,6 +54,7 @@ export const browserSessionIntegration = defineIntegration((options: BrowserSess // for errors and transactions (non-streamed spans) client.addEventProcessor(event => { if (event.type && event.type !== 'transaction') { + // ignore other events than errors and transactions for now return event; } @@ -62,20 +63,20 @@ export const browserSessionIntegration = defineIntegration((options: BrowserSess return event; } - if (!event.tags?.[SEMANTIC_ATTRIBUTE_SESSION_ID]) { - event.tags = { - ...event.tags, - [SEMANTIC_ATTRIBUTE_SESSION_ID]: sessionId, - }; - } + // set a session context on the event. Relay will extract the `session.id` + // tag from this context which will make it queryable in the UI. + event.contexts = { + session: { + id: sessionId, + }, + ...event.contexts, + }; event.spans?.forEach(span => { - if (!span.data?.[SEMANTIC_ATTRIBUTE_SESSION_ID]) { - span.data = { - ...span.data, - [SEMANTIC_ATTRIBUTE_SESSION_ID]: sessionId, - }; - } + span.data = { + [SEMANTIC_ATTRIBUTE_SESSION_ID]: sessionId, + ...span.data, + }; }); return event; diff --git a/packages/core/src/types/context.ts b/packages/core/src/types/context.ts index 9e52ff9d6834..76b24f155e56 100644 --- a/packages/core/src/types/context.ts +++ b/packages/core/src/types/context.ts @@ -16,6 +16,7 @@ export interface Contexts extends Record { state?: StateContext; profile?: ProfileContext; flags?: FeatureFlagContext; + session?: SessionContext; } export interface StateContext extends Record { @@ -139,3 +140,7 @@ export interface MissingInstrumentationContext extends Record { export interface FeatureFlagContext extends Record { values: FeatureFlag[]; } + +export interface SessionContext extends Record { + id?: string; +}