Skip to content

Commit eedf4a5

Browse files
authored
feat(browser): Set user.ip_address explicitly to {{auto}} (#15008)
Part of getsentry/team-sdks#118 This is so far inferred at relay-side, which is pretty intransparent and potentially confusing. So instead, we want to explicitly set this in the SDK. If this is set to `null` it will not be inferred (which is kind of intransparent too, but...) This is set for: * error events (as `user.ip_address`) * transactions (as `user.ip_address`) * replay events (as `user.ip_address`) * profiles (as `user.ip_address`) * sessions (as `user.ip_address`) * session aggregates: as `attr.ip_address: '{{auto}}'` * standalone spans (not by default, but added to all standalone web vitals spans we emit, as `'client.address': '{{auto}}'` attribute)
1 parent 9cdf720 commit eedf4a5

File tree

30 files changed

+228
-13
lines changed

30 files changed

+228
-13
lines changed

dev-packages/browser-integration-tests/suites/feedback/attachTo/test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ sentryTest('should capture feedback with custom button', async ({ getLocalTestUr
5757
event_id: expect.stringMatching(/\w{32}/),
5858
environment: 'production',
5959
tags: {},
60+
user: {
61+
ip_address: '{{auto}}',
62+
},
6063
sdk: {
6164
integrations: expect.arrayContaining(['Feedback']),
6265
version: expect.any(String),

dev-packages/browser-integration-tests/suites/feedback/captureFeedback/test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ sentryTest('should capture feedback', async ({ getLocalTestUrl, page }) => {
6969
'User-Agent': expect.stringContaining(''),
7070
},
7171
},
72+
user: {
73+
ip_address: '{{auto}}',
74+
},
7275
platform: 'javascript',
7376
});
7477
});

dev-packages/browser-integration-tests/suites/feedback/captureFeedbackAndReplay/hasSampling/test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ sentryTest('should capture feedback', async ({ forceFlushReplay, getLocalTestUrl
103103
'User-Agent': expect.stringContaining(''),
104104
},
105105
},
106+
user: {
107+
ip_address: '{{auto}}',
108+
},
106109
platform: 'javascript',
107110
});
108111
});

dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ sentryTest('should capture feedback', async ({ getLocalTestUrl, page }) => {
6969
'User-Agent': expect.stringContaining(''),
7070
},
7171
},
72+
user: {
73+
ip_address: '{{auto}}',
74+
},
7275
platform: 'javascript',
7376
});
7477
const cspViolation = await page.evaluate<boolean>('window.__CSPVIOLATION__');

dev-packages/browser-integration-tests/suites/manual-client/browser-context/test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ sentryTest('allows to setup a client manually & capture exceptions', async ({ ge
3434
'User-Agent': expect.any(String),
3535
}),
3636
},
37+
user: {
38+
ip_address: '{{auto}}',
39+
},
3740
timestamp: expect.any(Number),
3841
environment: 'local',
3942
release: '0.0.1',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Sentry.setUser({
2+
id: 'foo',
3+
ip_address: null,
4+
});
5+
6+
Sentry.captureMessage('first_user');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event } from '@sentry/core';
3+
4+
import { sentryTest } from '../../../../utils/fixtures';
5+
import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers';
6+
7+
sentryTest('should allow to set ip_address to null', async ({ getLocalTestUrl, page }) => {
8+
const url = await getLocalTestUrl({ testDir: __dirname });
9+
10+
const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);
11+
12+
expect(eventData.message).toBe('first_user');
13+
expect(eventData.user).toEqual({
14+
id: 'foo',
15+
ip_address: null,
16+
});
17+
});

dev-packages/browser-integration-tests/suites/public-api/setUser/unset_user/test.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ sentryTest('should unset user', async ({ getLocalTestUrl, page }) => {
1010
const eventData = await getMultipleSentryEnvelopeRequests<Event>(page, 3, { url });
1111

1212
expect(eventData[0].message).toBe('no_user');
13-
expect(eventData[0].user).toBeUndefined();
13+
expect(eventData[0].user).toEqual({ ip_address: '{{auto}}' });
1414

1515
expect(eventData[1].message).toBe('user');
16-
expect(eventData[1].user).toMatchObject({
16+
expect(eventData[1].user).toEqual({
1717
id: 'foo',
1818
ip_address: 'bar',
1919
other_key: 'baz',
2020
});
2121

2222
expect(eventData[2].message).toBe('unset_user');
23-
expect(eventData[2].user).toBeUndefined();
23+
expect(eventData[2].user).toEqual({
24+
ip_address: '{{auto}}',
25+
});
2426
});

dev-packages/browser-integration-tests/suites/public-api/setUser/update_user/test.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ sentryTest('should update user', async ({ getLocalTestUrl, page }) => {
1010
const eventData = await getMultipleSentryEnvelopeRequests<Event>(page, 2, { url });
1111

1212
expect(eventData[0].message).toBe('first_user');
13-
expect(eventData[0].user).toMatchObject({
13+
expect(eventData[0].user).toEqual({
1414
id: 'foo',
1515
ip_address: 'bar',
1616
});
1717

1818
expect(eventData[1].message).toBe('second_user');
19-
expect(eventData[1].user).toMatchObject({
19+
expect(eventData[1].user).toEqual({
2020
id: 'baz',
21+
ip_address: '{{auto}}',
2122
});
2223
});

dev-packages/browser-integration-tests/suites/public-api/startSpan/standalone-mixed-transaction/test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ sentryTest(
103103
headers: expect.any(Object),
104104
url: expect.any(String),
105105
},
106+
user: {
107+
ip_address: '{{auto}}',
108+
},
106109
sdk: expect.any(Object),
107110
spans: [
108111
{

dev-packages/browser-integration-tests/suites/public-api/withScope/nested_scopes/test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ sentryTest('should allow nested scoping', async ({ getLocalTestUrl, page }) => {
1010
const eventData = await getMultipleSentryEnvelopeRequests<Event>(page, 5, { url });
1111

1212
expect(eventData[0].message).toBe('root_before');
13-
expect(eventData[0].user).toMatchObject({ id: 'qux' });
13+
expect(eventData[0].user).toEqual({ id: 'qux', ip_address: '{{auto}}' });
1414
expect(eventData[0].tags).toBeUndefined();
1515

1616
expect(eventData[1].message).toBe('outer_before');
17-
expect(eventData[1].user).toMatchObject({ id: 'qux' });
17+
expect(eventData[1].user).toEqual({ id: 'qux', ip_address: '{{auto}}' });
1818
expect(eventData[1].tags).toMatchObject({ foo: false });
1919

2020
expect(eventData[2].message).toBe('inner');
21-
expect(eventData[2].user).toBeUndefined();
21+
expect(eventData[2].user).toEqual({ ip_address: '{{auto}}' });
2222
expect(eventData[2].tags).toMatchObject({ foo: false, bar: 10 });
2323

2424
expect(eventData[3].message).toBe('outer_after');
25-
expect(eventData[3].user).toMatchObject({ id: 'baz' });
25+
expect(eventData[3].user).toEqual({ id: 'baz', ip_address: '{{auto}}' });
2626
expect(eventData[3].tags).toMatchObject({ foo: false });
2727

2828
expect(eventData[4].message).toBe('root_after');
29-
expect(eventData[4].user).toMatchObject({ id: 'qux' });
29+
expect(eventData[4].user).toEqual({ id: 'qux', ip_address: '{{auto}}' });
3030
expect(eventData[4].tags).toBeUndefined();
3131
});

dev-packages/browser-integration-tests/suites/replay/captureReplay/test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ sentryTest('should capture replays (@sentry/browser export)', async ({ getLocalT
5555
'User-Agent': expect.stringContaining(''),
5656
},
5757
},
58+
user: {
59+
ip_address: '{{auto}}',
60+
},
5861
platform: 'javascript',
5962
});
6063

@@ -93,6 +96,9 @@ sentryTest('should capture replays (@sentry/browser export)', async ({ getLocalT
9396
'User-Agent': expect.stringContaining(''),
9497
},
9598
},
99+
user: {
100+
ip_address: '{{auto}}',
101+
},
96102
platform: 'javascript',
97103
});
98104
});

dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ sentryTest('should capture replays (@sentry-internal/replay export)', async ({ g
5555
'User-Agent': expect.stringContaining(''),
5656
},
5757
},
58+
user: {
59+
ip_address: '{{auto}}',
60+
},
5861
platform: 'javascript',
5962
});
6063

@@ -93,6 +96,9 @@ sentryTest('should capture replays (@sentry-internal/replay export)', async ({ g
9396
'User-Agent': expect.stringContaining(''),
9497
},
9598
},
99+
user: {
100+
ip_address: '{{auto}}',
101+
},
96102
platform: 'javascript',
97103
});
98104
});

dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-cls-standalone-spans/test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ sentryTest('captures a "GOOD" CLS vital with its source as a standalone span', a
6969
transaction: expect.stringContaining('index.html'),
7070
'user_agent.original': expect.stringContaining('Chrome'),
7171
'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/),
72+
'client.address': '{{auto}}',
7273
},
7374
description: expect.stringContaining('body > div#content > p'),
7475
exclusive_time: 0,
@@ -137,6 +138,7 @@ sentryTest('captures a "MEH" CLS vital with its source as a standalone span', as
137138
transaction: expect.stringContaining('index.html'),
138139
'user_agent.original': expect.stringContaining('Chrome'),
139140
'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/),
141+
'client.address': '{{auto}}',
140142
},
141143
description: expect.stringContaining('body > div#content > p'),
142144
exclusive_time: 0,
@@ -203,6 +205,7 @@ sentryTest('captures a "POOR" CLS vital with its source as a standalone span.',
203205
transaction: expect.stringContaining('index.html'),
204206
'user_agent.original': expect.stringContaining('Chrome'),
205207
'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/),
208+
'client.address': '{{auto}}',
206209
},
207210
description: expect.stringContaining('body > div#content > p'),
208211
exclusive_time: 0,
@@ -270,6 +273,7 @@ sentryTest(
270273
transaction: expect.stringContaining('index.html'),
271274
'user_agent.original': expect.stringContaining('Chrome'),
272275
'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/),
276+
'client.address': '{{auto}}',
273277
},
274278
description: 'Layout shift',
275279
exclusive_time: 0,

dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-late/test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ sentryTest('should capture an INP click event span after pageload', async ({ bro
7171
'sentry.source': 'custom',
7272
transaction: 'test-url',
7373
'user_agent.original': expect.stringContaining('Chrome'),
74+
'client.address': '{{auto}}',
7475
},
7576
measurements: {
7677
inp: {

dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized-late/test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ sentryTest(
7474
'sentry.source': 'custom',
7575
transaction: 'test-route',
7676
'user_agent.original': expect.stringContaining('Chrome'),
77+
'client.address': '{{auto}}',
7778
},
7879
measurements: {
7980
inp: {

dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-parametrized/test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ sentryTest(
7070
'sentry.origin': 'auto.http.browser.inp',
7171
transaction: 'test-route',
7272
'user_agent.original': expect.stringContaining('Chrome'),
73+
'client.address': '{{auto}}',
7374
},
7475
measurements: {
7576
inp: {

dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp/test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ sentryTest('should capture an INP click event span during pageload', async ({ br
6969
'sentry.origin': 'auto.http.browser.inp',
7070
transaction: 'test-url',
7171
'user_agent.original': expect.stringContaining('Chrome'),
72+
'client.address': '{{auto}}',
7273
},
7374
measurements: {
7475
inp: {

dev-packages/browser-integration-tests/utils/replayEventTemplates.ts

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ const DEFAULT_REPLAY_EVENT = {
3737
'User-Agent': expect.any(String),
3838
},
3939
},
40+
user: {
41+
ip_address: '{{auto}}',
42+
},
4043
platform: 'javascript',
4144
};
4245

dev-packages/e2e-tests/test-applications/react-17/tests/transactions.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ test('sends an INP span', async ({ page }) => {
8383
'sentry.exclusive_time': expect.any(Number),
8484
replay_id: expect.any(String),
8585
'user_agent.original': expect.stringContaining('Chrome'),
86+
'client.address': '{{auto}}',
8687
},
8788
description: 'body > div#root > input#exception-button[type="button"]',
8889
op: 'ui.interaction.click',

dev-packages/e2e-tests/test-applications/react-router-6/tests/transactions.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ test('sends an INP span', async ({ page }) => {
8383
'sentry.exclusive_time': expect.any(Number),
8484
replay_id: expect.any(String),
8585
'user_agent.original': expect.stringContaining('Chrome'),
86+
'client.address': '{{auto}}',
8687
},
8788
description: 'body > div#root > input#exception-button[type="button"]',
8889
op: 'ui.interaction.click',

dev-packages/e2e-tests/test-applications/react-router-7-spa/tests/transactions.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ test('sends an INP span', async ({ page }) => {
8383
'sentry.exclusive_time': expect.any(Number),
8484
replay_id: expect.any(String),
8585
'user_agent.original': expect.stringContaining('Chrome'),
86+
'client.address': '{{auto}}',
8687
},
8788
description: 'body > div#root > input#exception-button[type="button"]',
8889
op: 'ui.interaction.click',

packages/browser-utils/src/metrics/utils.ts

+3
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ export function startStandaloneWebVitalSpan(options: StandaloneWebVitalSpanOptio
108108
// For example: Chrome vs. Chrome Mobile
109109
'user_agent.original': WINDOW.navigator?.userAgent,
110110

111+
// This tells Sentry to infer the IP address from the request
112+
'client.address': '{{auto}}',
113+
111114
...passedAttributes,
112115
};
113116

packages/browser/src/client.ts

+31
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
ParameterizedString,
99
Scope,
1010
SeverityLevel,
11+
User,
1112
} from '@sentry/core';
1213
import { Client, applySdkMetadata, getSDKSource } from '@sentry/core';
1314
import { eventFromException, eventFromMessage } from './eventbuilder';
@@ -82,6 +83,23 @@ export class BrowserClient extends Client<BrowserClientOptions> {
8283
}
8384
});
8485
}
86+
87+
this.on('postprocessEvent', event => {
88+
addAutoIpAddressToUser(event);
89+
});
90+
91+
this.on('beforeSendSession', session => {
92+
if ('aggregates' in session) {
93+
if (session.attrs?.['ip_address'] === undefined) {
94+
session.attrs = {
95+
...session.attrs,
96+
ip_address: '{{auto}}',
97+
};
98+
}
99+
} else {
100+
addAutoIpAddressToUser(session);
101+
}
102+
});
85103
}
86104

87105
/**
@@ -112,6 +130,19 @@ export class BrowserClient extends Client<BrowserClientOptions> {
112130
isolationScope: Scope,
113131
): PromiseLike<Event | null> {
114132
event.platform = event.platform || 'javascript';
133+
115134
return super._prepareEvent(event, hint, currentScope, isolationScope);
116135
}
117136
}
137+
138+
// By default, we want to infer the IP address, unless this is explicitly set to `null`
139+
// We do this after all other processing is done
140+
// If `ip_address` is explicitly set to `null` or a value, we leave it as is
141+
function addAutoIpAddressToUser(objWithMaybeUser: { user?: User | null }): void {
142+
if (objWithMaybeUser.user?.ip_address === undefined) {
143+
objWithMaybeUser.user = {
144+
...objWithMaybeUser.user,
145+
ip_address: '{{auto}}',
146+
};
147+
}
148+
}

0 commit comments

Comments
 (0)