diff --git a/packages/browser-utils/src/metrics/webVitalSpans.ts b/packages/browser-utils/src/metrics/webVitalSpans.ts index 9c4f82249874..89024148865c 100644 --- a/packages/browser-utils/src/metrics/webVitalSpans.ts +++ b/packages/browser-utils/src/metrics/webVitalSpans.ts @@ -1,6 +1,7 @@ import type { Client, Integration, Span, SpanAttributes } from '@sentry/core'; import { browserPerformanceTimeOrigin, + correctedPerformanceTimeOrigin, debug, getActiveSpan, getClient, @@ -329,7 +330,9 @@ export function trackInpAsSpan(client: Client): void { export function _sendInpSpan(inpValue: number, entry: PerformanceEventTiming, standalone = false): void { DEBUG_BUILD && debug.log(`Sending INP span (${inpValue})`); - const startTime = msToSec((browserPerformanceTimeOrigin() as number) + entry.startTime); + // INP reports on pagehide, potentially hours after the origin cached at init, so the corrected origin is used to stay + // on the same timeline as span and event timestamps. + const startTime = msToSec((correctedPerformanceTimeOrigin() as number) + entry.startTime); const duration = msToSec(inpValue); const interactionType = INP_ENTRY_MAP[entry.name]; diff --git a/packages/browser-utils/test/metrics/webVitalSpans.test.ts b/packages/browser-utils/test/metrics/webVitalSpans.test.ts index ef938d7017f0..95fc1494447e 100644 --- a/packages/browser-utils/test/metrics/webVitalSpans.test.ts +++ b/packages/browser-utils/test/metrics/webVitalSpans.test.ts @@ -17,6 +17,7 @@ vi.mock('@sentry/core', async () => { return { ...actual, browserPerformanceTimeOrigin: vi.fn(), + correctedPerformanceTimeOrigin: vi.fn(), timestampInSeconds: vi.fn(), getCurrentScope: vi.fn(), getClient: vi.fn(), @@ -475,6 +476,7 @@ describe('_sendInpSpan', () => { beforeEach(() => { vi.mocked(SentryCore.getCurrentScope).mockReturnValue(mockScope as any); vi.mocked(SentryCore.browserPerformanceTimeOrigin).mockReturnValue(1000); + vi.mocked(SentryCore.correctedPerformanceTimeOrigin).mockReturnValue(1000); vi.mocked(htmlTreeAsString).mockReturnValue('