Skip to content

Commit 2140083

Browse files
authored
feat(browser): Add navigation activationStart timestamp to pageload span (#13658)
Add the navigation performance entry `activationStart` property as a span attribute to the pageload span. The attribute is called `performance.activationStart` and it is measured in ms relative to performance.timeOrigin.
1 parent 5d0094a commit 2140083

File tree

3 files changed

+32
-15
lines changed

3 files changed

+32
-15
lines changed

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

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,30 @@ sentryTest('paint web vitals values are greater than TTFB', async ({ browserName
5959
expect(fpValue).toBeGreaterThanOrEqual(ttfbValue!);
6060
});
6161

62-
sentryTest('captures time origin as span attribute', async ({ getLocalTestPath, page }) => {
63-
// Only run in chromium to ensure all vitals are present
64-
if (shouldSkipTracingTest()) {
65-
sentryTest.skip();
66-
}
62+
sentryTest(
63+
'captures time origin and navigation activationStart as span attributes',
64+
async ({ getLocalTestPath, page }) => {
65+
// Only run in chromium to ensure all vitals are present
66+
if (shouldSkipTracingTest()) {
67+
sentryTest.skip();
68+
}
6769

68-
const url = await getLocalTestPath({ testDir: __dirname });
69-
const [eventData] = await Promise.all([getFirstSentryEnvelopeRequest<Event>(page), page.goto(url)]);
70+
const url = await getLocalTestPath({ testDir: __dirname });
71+
const [eventData] = await Promise.all([getFirstSentryEnvelopeRequest<Event>(page), page.goto(url)]);
7072

71-
const timeOriginAttribute = eventData.contexts?.trace?.data?.['performance.timeOrigin'];
72-
const transactionStartTimestamp = eventData.start_timestamp;
73+
const timeOriginAttribute = eventData.contexts?.trace?.data?.['performance.timeOrigin'];
74+
const activationStart = eventData.contexts?.trace?.data?.['performance.activationStart'];
7375

74-
expect(timeOriginAttribute).toBeDefined();
75-
expect(transactionStartTimestamp).toBeDefined();
76+
const transactionStartTimestamp = eventData.start_timestamp;
7677

77-
const delta = Math.abs(transactionStartTimestamp! - timeOriginAttribute);
78+
expect(timeOriginAttribute).toBeDefined();
79+
expect(transactionStartTimestamp).toBeDefined();
7880

79-
// The delta should be less than 1ms if this flakes, we should increase the threshold
80-
expect(delta).toBeLessThanOrEqual(1);
81-
});
81+
const delta = Math.abs(transactionStartTimestamp! - timeOriginAttribute);
82+
83+
// The delta should be less than 1ms if this flakes, we should increase the threshold
84+
expect(delta).toBeLessThanOrEqual(1);
85+
86+
expect(activationStart).toBeGreaterThanOrEqual(0);
87+
},
88+
);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ test('Captures a pageload transaction', async ({ page }) => {
2323
'sentry.sample_rate': 1,
2424
'sentry.source': 'route',
2525
'performance.timeOrigin': expect.any(Number),
26+
'performance.activationStart': expect.any(Number),
2627
},
2728
op: 'pageload',
2829
span_id: expect.any(String),

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
addTtfbInstrumentationHandler,
1818
} from './instrument';
1919
import { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan } from './utils';
20+
import { getActivationStart } from './web-vitals/lib/getActivationStart';
2021
import { getNavigationEntry } from './web-vitals/lib/getNavigationEntry';
2122
import { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher';
2223

@@ -383,6 +384,14 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries
383384
// Set timeOrigin which denotes the timestamp which to base the LCP/FCP/FP/TTFB measurements on
384385
span.setAttribute('performance.timeOrigin', timeOrigin);
385386

387+
// In prerendering scenarios, where a page might be prefetched and pre-rendered before the user clicks the link,
388+
// the navigation starts earlier than when the user clicks it. Web Vitals should always be based on the
389+
// user-perceived time, so they are not reported from the actual start of the navigation, but rather from the
390+
// time where the user actively started the navigation, for example by clicking a link.
391+
// This is user action is called "activation" and the time between navigation and activation is stored in
392+
// the `activationStart` attribute of the "navigation" PerformanceEntry.
393+
span.setAttribute('performance.activationStart', getActivationStart());
394+
386395
_setWebVitalAttributes(span);
387396
}
388397

0 commit comments

Comments
 (0)