From 20dd38a7ba9859c987fc43bafa93a8b4a62f46ee Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Tue, 21 Apr 2026 08:35:15 +0200 Subject: [PATCH 1/3] implement --- packages/core/src/tracing/spans/envelope.ts | 16 +++- packages/core/src/types-hoist/span.ts | 5 ++ .../test/lib/tracing/spans/envelope.test.ts | 81 ++++++++++++++++++- 3 files changed, 98 insertions(+), 4 deletions(-) diff --git a/packages/core/src/tracing/spans/envelope.ts b/packages/core/src/tracing/spans/envelope.ts index 8429b22d7e1c..9d0f7c2277d2 100644 --- a/packages/core/src/tracing/spans/envelope.ts +++ b/packages/core/src/tracing/spans/envelope.ts @@ -12,9 +12,10 @@ export function createStreamedSpanEnvelope( dsc: Partial, client: Client, ): StreamedSpanEnvelope { + const options = client.getOptions(); const dsn = client.getDsn(); - const tunnel = client.getOptions().tunnel; - const sdk = getSdkMetadataForEnvelopeHeader(client.getOptions()._metadata); + const tunnel = options.tunnel; + const sdk = getSdkMetadataForEnvelopeHeader(options._metadata); const headers: StreamedSpanEnvelope[0] = { sent_at: new Date().toISOString(), @@ -23,9 +24,18 @@ export function createStreamedSpanEnvelope( ...(!!tunnel && dsn && { dsn: dsnToString(dsn) }), }; + const isBrowserSdk = options._metadata?.sdk?.name === 'sentry.javascript.browser'; + const inferSetting = options.sendDefaultPii ? 'auto' : 'never'; + const spanContainer: SpanContainerItem = [ { type: 'span', item_count: serializedSpans.length, content_type: 'application/vnd.sentry.items.span.v2+json' }, - { items: serializedSpans }, + { + version: 2, + ...(isBrowserSdk && { + ingest_settings: { infer_ip: inferSetting, infer_useragent: inferSetting }, + }), + items: serializedSpans, + }, ]; return createEnvelope(headers, [spanContainer]); diff --git a/packages/core/src/types-hoist/span.ts b/packages/core/src/types-hoist/span.ts index a918cc57859c..7b0e59243cc4 100644 --- a/packages/core/src/types-hoist/span.ts +++ b/packages/core/src/types-hoist/span.ts @@ -69,6 +69,11 @@ export type SerializedStreamedSpan = Omit; }; diff --git a/packages/core/test/lib/tracing/spans/envelope.test.ts b/packages/core/test/lib/tracing/spans/envelope.test.ts index 197b7ed40365..8184006ce187 100644 --- a/packages/core/test/lib/tracing/spans/envelope.test.ts +++ b/packages/core/test/lib/tracing/spans/envelope.test.ts @@ -181,6 +181,7 @@ describe('createStreamedSpanEnvelope', () => { type: 'span', }, { + version: 2, items: [mockSpan], }, ], @@ -199,7 +200,7 @@ describe('createStreamedSpanEnvelope', () => { expect(envelopeItems).toEqual([ [ { type: 'span', item_count: 3, content_type: 'application/vnd.sentry.items.span.v2+json' }, - { items: [mockSpan1, mockSpan2, mockSpan3] }, + { version: 2, items: [mockSpan1, mockSpan2, mockSpan3] }, ], ]); }); @@ -222,11 +223,89 @@ describe('createStreamedSpanEnvelope', () => { type: 'span', }, { + version: 2, items: [], }, ], ], ]); }); + + it("includes ingest_settings with 'auto' values when SDK is browser and sendDefaultPii is true", () => { + const mockSpan = createMockSerializedSpan(); + const mockClient = new TestClient( + getDefaultTestClientOptions({ + sendDefaultPii: true, + _metadata: { + sdk: { name: 'sentry.javascript.browser', version: '8.0.0' }, + }, + }), + ); + const dsc: Partial = {}; + + const envelopeItems = createStreamedSpanEnvelope([mockSpan], dsc, mockClient)[1]; + + expect(envelopeItems).toEqual([ + [ + { type: 'span', item_count: 1, content_type: 'application/vnd.sentry.items.span.v2+json' }, + { + version: 2, + ingest_settings: { infer_ip: 'auto', infer_useragent: 'auto' }, + items: [mockSpan], + }, + ], + ]); + }); + + it("includes ingest_settings with 'never' values when SDK is browser and sendDefaultPii is false", () => { + const mockSpan = createMockSerializedSpan(); + const mockClient = new TestClient( + getDefaultTestClientOptions({ + sendDefaultPii: false, + _metadata: { + sdk: { name: 'sentry.javascript.browser', version: '8.0.0' }, + }, + }), + ); + const dsc: Partial = {}; + + const envelopeItems = createStreamedSpanEnvelope([mockSpan], dsc, mockClient)[1]; + + expect(envelopeItems).toEqual([ + [ + { type: 'span', item_count: 1, content_type: 'application/vnd.sentry.items.span.v2+json' }, + { + version: 2, + ingest_settings: { infer_ip: 'never', infer_useragent: 'never' }, + items: [mockSpan], + }, + ], + ]); + }); + + it('omits ingest_settings when SDK is not browser', () => { + const mockSpan = createMockSerializedSpan(); + const mockClient = new TestClient( + getDefaultTestClientOptions({ + sendDefaultPii: true, + _metadata: { + sdk: { name: 'sentry.javascript.node', version: '10.38.0' }, + }, + }), + ); + const dsc: Partial = {}; + + const envelopeItems = createStreamedSpanEnvelope([mockSpan], dsc, mockClient)[1]; + + expect(envelopeItems).toEqual([ + [ + { type: 'span', item_count: 1, content_type: 'application/vnd.sentry.items.span.v2+json' }, + { + version: 2, + items: [mockSpan], + }, + ], + ]); + }); }); }); From a98a9ce62011315a4e14e3253e16f26f89353f50 Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Tue, 21 Apr 2026 09:11:25 +0200 Subject: [PATCH 2/3] bump size limits --- .size-limit.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.size-limit.js b/.size-limit.js index c4b37635ecda..f1dd4dc668c1 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -221,7 +221,7 @@ module.exports = [ name: 'CDN Bundle (incl. Tracing, Replay, Logs, Metrics)', path: createCDNPath('bundle.tracing.replay.logs.metrics.min.js'), gzip: true, - limit: '83 KB', + limit: '83.5 KB', }, { name: 'CDN Bundle (incl. Tracing, Replay, Feedback)', @@ -283,7 +283,7 @@ module.exports = [ path: createCDNPath('bundle.tracing.replay.logs.metrics.min.js'), gzip: false, brotli: false, - limit: '255 KB', + limit: '255.5 KB', }, { name: 'CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed', @@ -297,7 +297,7 @@ module.exports = [ path: createCDNPath('bundle.tracing.replay.feedback.logs.metrics.min.js'), gzip: false, brotli: false, - limit: '268 KB', + limit: '268.5 KB', }, // Next.js SDK (ESM) { From 8c1f58f1f8ac7c7675a577325d470af4dbea71be Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Tue, 21 Apr 2026 11:11:56 +0200 Subject: [PATCH 3/3] better browser detection --- .../public-api/startSpan/streamed/test.ts | 2 + packages/core/src/tracing/spans/envelope.ts | 4 +- .../test/lib/tracing/spans/envelope.test.ts | 48 ++++++++----------- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/public-api/startSpan/streamed/test.ts b/dev-packages/browser-integration-tests/suites/public-api/startSpan/streamed/test.ts index 9ea2197fff85..bd9e8438ad24 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/startSpan/streamed/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/startSpan/streamed/test.ts @@ -56,6 +56,8 @@ sentryTest( [ { content_type: 'application/vnd.sentry.items.span.v2+json', item_count: 4, type: 'span' }, { + version: 2, + ingest_settings: { infer_ip: 'never', infer_useragent: 'never' }, items: expect.any(Array), }, ], diff --git a/packages/core/src/tracing/spans/envelope.ts b/packages/core/src/tracing/spans/envelope.ts index 9d0f7c2277d2..33f985fe198c 100644 --- a/packages/core/src/tracing/spans/envelope.ts +++ b/packages/core/src/tracing/spans/envelope.ts @@ -3,6 +3,7 @@ import type { DynamicSamplingContext, SpanContainerItem, StreamedSpanEnvelope } import type { SerializedStreamedSpan } from '../../types-hoist/span'; import { dsnToString } from '../../utils/dsn'; import { createEnvelope, getSdkMetadataForEnvelopeHeader } from '../../utils/envelope'; +import { isBrowser } from '../../utils/isBrowser'; /** * Creates a span v2 span streaming envelope @@ -24,14 +25,13 @@ export function createStreamedSpanEnvelope( ...(!!tunnel && dsn && { dsn: dsnToString(dsn) }), }; - const isBrowserSdk = options._metadata?.sdk?.name === 'sentry.javascript.browser'; const inferSetting = options.sendDefaultPii ? 'auto' : 'never'; const spanContainer: SpanContainerItem = [ { type: 'span', item_count: serializedSpans.length, content_type: 'application/vnd.sentry.items.span.v2+json' }, { version: 2, - ...(isBrowserSdk && { + ...(isBrowser() && { ingest_settings: { infer_ip: inferSetting, infer_useragent: inferSetting }, }), items: serializedSpans, diff --git a/packages/core/test/lib/tracing/spans/envelope.test.ts b/packages/core/test/lib/tracing/spans/envelope.test.ts index 8184006ce187..04d443239e1e 100644 --- a/packages/core/test/lib/tracing/spans/envelope.test.ts +++ b/packages/core/test/lib/tracing/spans/envelope.test.ts @@ -1,9 +1,18 @@ -import { describe, expect, it } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; import { createStreamedSpanEnvelope } from '../../../../src/tracing/spans/envelope'; import type { DynamicSamplingContext } from '../../../../src/types-hoist/envelope'; import type { SerializedStreamedSpan } from '../../../../src/types-hoist/span'; +import { isBrowser } from '../../../../src/utils/isBrowser'; import { getDefaultTestClientOptions, TestClient } from '../../../mocks/client'; +vi.mock('../../../../src/utils/isBrowser', () => ({ + isBrowser: vi.fn(() => false), +})); + +afterEach(() => { + vi.mocked(isBrowser).mockReturnValue(false); +}); + function createMockSerializedSpan(overrides: Partial = {}): SerializedStreamedSpan { return { trace_id: 'abc123', @@ -231,16 +240,11 @@ describe('createStreamedSpanEnvelope', () => { ]); }); - it("includes ingest_settings with 'auto' values when SDK is browser and sendDefaultPii is true", () => { + it("includes ingest_settings with 'auto' values when in browser and sendDefaultPii is true", () => { + vi.mocked(isBrowser).mockReturnValue(true); + const mockSpan = createMockSerializedSpan(); - const mockClient = new TestClient( - getDefaultTestClientOptions({ - sendDefaultPii: true, - _metadata: { - sdk: { name: 'sentry.javascript.browser', version: '8.0.0' }, - }, - }), - ); + const mockClient = new TestClient(getDefaultTestClientOptions({ sendDefaultPii: true })); const dsc: Partial = {}; const envelopeItems = createStreamedSpanEnvelope([mockSpan], dsc, mockClient)[1]; @@ -257,16 +261,11 @@ describe('createStreamedSpanEnvelope', () => { ]); }); - it("includes ingest_settings with 'never' values when SDK is browser and sendDefaultPii is false", () => { + it("includes ingest_settings with 'never' values when in browser and sendDefaultPii is false", () => { + vi.mocked(isBrowser).mockReturnValue(true); + const mockSpan = createMockSerializedSpan(); - const mockClient = new TestClient( - getDefaultTestClientOptions({ - sendDefaultPii: false, - _metadata: { - sdk: { name: 'sentry.javascript.browser', version: '8.0.0' }, - }, - }), - ); + const mockClient = new TestClient(getDefaultTestClientOptions({ sendDefaultPii: false })); const dsc: Partial = {}; const envelopeItems = createStreamedSpanEnvelope([mockSpan], dsc, mockClient)[1]; @@ -283,16 +282,9 @@ describe('createStreamedSpanEnvelope', () => { ]); }); - it('omits ingest_settings when SDK is not browser', () => { + it('omits ingest_settings when not in browser', () => { const mockSpan = createMockSerializedSpan(); - const mockClient = new TestClient( - getDefaultTestClientOptions({ - sendDefaultPii: true, - _metadata: { - sdk: { name: 'sentry.javascript.node', version: '10.38.0' }, - }, - }), - ); + const mockClient = new TestClient(getDefaultTestClientOptions({ sendDefaultPii: true })); const dsc: Partial = {}; const envelopeItems = createStreamedSpanEnvelope([mockSpan], dsc, mockClient)[1];