Skip to content

Conversation

@lricoy
Copy link
Member

@lricoy lricoy commented Oct 14, 2025

Changes

Adds a new 'on_navigation' option for the capture_pageleave config that captures pageleave events on every history navigation event (pushState, replaceState, popstate) in addition to window unload.

This is an extension to the capture:_pageview: 'history_change' option to allow people who rely on client-side navigation to have this behavior:

When capture_pageleave: 'on_navigation' is set:

  • pageView A → (navigate) → pageLeave A + pageView B → (navigate) → pageLeave B + pageView C -> (closes tab) -> pageLeave C

The regular true or if_capture_pageview would be:

  • pageView A → (navigate) → pageView B → (navigate) → pageView C -> (closes tab) -> pageLeave C

The pageleave event is captured before the new pageview during navigation and has a timestamp as well as all the other expected props because this PR only changes the trigger, everything is still handled by PageViewManager.

⚠️ This requires docs update on posthog.com to clarify the different $pageleave behavior.

@vercel
Copy link

vercel bot commented Oct 14, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
posthog-js Ready Ready Preview Oct 14, 2025 7:20pm

@github-actions
Copy link
Contributor

github-actions bot commented Oct 14, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Oct 14, 2025

Size Change: +3.14 kB (+0.07%)

Total Size: 4.84 MB

Filename Size Change
packages/browser/dist/array.full.es5.js 291 kB +359 B (+0.12%)
packages/browser/dist/array.full.js 358 kB +280 B (+0.08%)
packages/browser/dist/array.full.no-external.js 372 kB +346 B (+0.09%)
packages/browser/dist/array.js 158 kB +280 B (+0.18%)
packages/browser/dist/array.no-external.js 169 kB +346 B (+0.2%)
packages/browser/dist/main.js 159 kB +280 B (+0.18%)
packages/browser/dist/module.full.js 359 kB +280 B (+0.08%)
packages/browser/dist/module.full.no-external.js 372 kB +346 B (+0.09%)
packages/browser/dist/module.js 159 kB +280 B (+0.18%)
packages/browser/dist/module.no-external.js 170 kB +346 B (+0.2%)
ℹ️ View Unchanged
Filename Size Change
packages/ai/dist/anthropic/index.cjs 16.7 kB 0 B
packages/ai/dist/anthropic/index.mjs 16.5 kB 0 B
packages/ai/dist/gemini/index.cjs 17.6 kB 0 B
packages/ai/dist/gemini/index.mjs 17.5 kB 0 B
packages/ai/dist/index.cjs 120 kB 0 B
packages/ai/dist/index.mjs 119 kB 0 B
packages/ai/dist/langchain/index.cjs 39.6 kB 0 B
packages/ai/dist/langchain/index.mjs 39 kB 0 B
packages/ai/dist/openai/index.cjs 29.8 kB 0 B
packages/ai/dist/openai/index.mjs 29.5 kB 0 B
packages/ai/dist/vercel/index.cjs 21.9 kB 0 B
packages/ai/dist/vercel/index.mjs 21.9 kB 0 B
packages/browser/dist/all-external-dependencies.js 223 kB 0 B
packages/browser/dist/crisp-chat-integration.js 1.97 kB 0 B
packages/browser/dist/customizations.full.js 19.1 kB 0 B
packages/browser/dist/dead-clicks-autocapture.js 12.6 kB 0 B
packages/browser/dist/exception-autocapture.js 11.6 kB 0 B
packages/browser/dist/external-scripts-loader.js 2.81 kB 0 B
packages/browser/dist/intercom-integration.js 2.02 kB 0 B
packages/browser/dist/lazy-recorder.js 147 kB 0 B
packages/browser/dist/posthog-recorder.js 241 kB 0 B
packages/browser/dist/recorder-v2.js 113 kB 0 B
packages/browser/dist/recorder.js 113 kB 0 B
packages/browser/dist/surveys-preview.js 71.1 kB 0 B
packages/browser/dist/surveys.js 80 kB 0 B
packages/browser/dist/tracing-headers.js 1.84 kB 0 B
packages/browser/dist/web-vitals.js 10.4 kB 0 B
packages/browser/react/dist/esm/index.js 15.1 kB 0 B
packages/browser/react/dist/umd/index.js 17.8 kB 0 B
packages/core/dist/error-tracking/chunk-ids.js 2.54 kB 0 B
packages/core/dist/error-tracking/chunk-ids.mjs 1.31 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.js 2.3 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.mjs 993 B 0 B
packages/core/dist/error-tracking/coercers/error-coercer.js 2.02 kB 0 B
packages/core/dist/error-tracking/coercers/error-coercer.mjs 794 B 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.js 1.76 kB 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.mjs 513 B 0 B
packages/core/dist/error-tracking/coercers/event-coercer.js 1.82 kB 0 B
packages/core/dist/error-tracking/coercers/event-coercer.mjs 548 B 0 B
packages/core/dist/error-tracking/coercers/index.js 6.79 kB 0 B
packages/core/dist/error-tracking/coercers/index.mjs 326 B 0 B
packages/core/dist/error-tracking/coercers/object-coercer.js 3.46 kB 0 B
packages/core/dist/error-tracking/coercers/object-coercer.mjs 2.07 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.js 1.67 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.mjs 419 B 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.js 2.25 kB 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.mjs 904 B 0 B
packages/core/dist/error-tracking/coercers/string-coercer.js 2.01 kB 0 B
packages/core/dist/error-tracking/coercers/string-coercer.mjs 820 B 0 B
packages/core/dist/error-tracking/coercers/utils.js 2.06 kB 0 B
packages/core/dist/error-tracking/coercers/utils.mjs 716 B 0 B
packages/core/dist/error-tracking/error-properties-builder.js 5.64 kB 0 B
packages/core/dist/error-tracking/error-properties-builder.mjs 4.24 kB 0 B
packages/core/dist/error-tracking/index.js 4.11 kB 0 B
packages/core/dist/error-tracking/index.mjs 152 B 0 B
packages/core/dist/error-tracking/parsers/base.js 1.84 kB 0 B
packages/core/dist/error-tracking/parsers/base.mjs 472 B 0 B
packages/core/dist/error-tracking/parsers/chrome.js 2.7 kB 0 B
packages/core/dist/error-tracking/parsers/chrome.mjs 1.29 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.js 2.45 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.mjs 1.11 kB 0 B
packages/core/dist/error-tracking/parsers/index.js 4.36 kB 0 B
packages/core/dist/error-tracking/parsers/index.mjs 1.92 kB 0 B
packages/core/dist/error-tracking/parsers/node.js 3.95 kB 0 B
packages/core/dist/error-tracking/parsers/node.mjs 2.68 kB 0 B
packages/core/dist/error-tracking/parsers/opera.js 2.22 kB 0 B
packages/core/dist/error-tracking/parsers/opera.mjs 706 B 0 B
packages/core/dist/error-tracking/parsers/react-native.js 203 B 0 B
packages/core/dist/error-tracking/parsers/react-native.mjs 0 B 0 B 🆕
packages/core/dist/error-tracking/parsers/safari.js 1.88 kB 0 B
packages/core/dist/error-tracking/parsers/safari.mjs 574 B 0 B
packages/core/dist/error-tracking/parsers/winjs.js 1.7 kB 0 B
packages/core/dist/error-tracking/parsers/winjs.mjs 406 B 0 B
packages/core/dist/error-tracking/types.js 1.33 kB 0 B
packages/core/dist/error-tracking/types.mjs 131 B 0 B
packages/core/dist/error-tracking/utils.js 1.8 kB 0 B
packages/core/dist/error-tracking/utils.mjs 604 B 0 B
packages/core/dist/eventemitter.js 1.78 kB 0 B
packages/core/dist/eventemitter.mjs 571 B 0 B
packages/core/dist/featureFlagUtils.js 6.5 kB 0 B
packages/core/dist/featureFlagUtils.mjs 4.28 kB 0 B
packages/core/dist/gzip.js 1.88 kB 0 B
packages/core/dist/gzip.mjs 577 B 0 B
packages/core/dist/index.js 5.7 kB 0 B
packages/core/dist/index.mjs 485 B 0 B
packages/core/dist/logger.js 2.46 kB 0 B
packages/core/dist/logger.mjs 1.17 kB 0 B
packages/core/dist/posthog-core-stateless.js 29.7 kB 0 B
packages/core/dist/posthog-core-stateless.mjs 27.1 kB 0 B
packages/core/dist/posthog-core.js 28 kB 0 B
packages/core/dist/posthog-core.mjs 24 kB 0 B
packages/core/dist/process/index.js 2.27 kB 0 B
packages/core/dist/process/index.mjs 35 B 0 B
packages/core/dist/process/spawn-local.js 2.33 kB 0 B
packages/core/dist/process/spawn-local.mjs 1.01 kB 0 B
packages/core/dist/process/utils.js 3.11 kB 0 B
packages/core/dist/process/utils.mjs 1.15 kB 0 B
packages/core/dist/testing/index.js 2.93 kB 0 B
packages/core/dist/testing/index.mjs 79 B 0 B
packages/core/dist/testing/PostHogCoreTestClient.js 3.15 kB 0 B
packages/core/dist/testing/PostHogCoreTestClient.mjs 1.74 kB 0 B
packages/core/dist/testing/test-utils.js 2.77 kB 0 B
packages/core/dist/testing/test-utils.mjs 1.09 kB 0 B
packages/core/dist/types.js 8.2 kB 0 B
packages/core/dist/types.mjs 5.93 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.js 3.14 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.mjs 1.76 kB 0 B
packages/core/dist/utils/index.js 9.26 kB 0 B
packages/core/dist/utils/index.mjs 1.88 kB 0 B
packages/core/dist/utils/number-utils.js 2 kB 0 B
packages/core/dist/utils/number-utils.mjs 735 B 0 B
packages/core/dist/utils/promise-queue.js 2 kB 0 B
packages/core/dist/utils/promise-queue.mjs 768 B 0 B
packages/core/dist/utils/string-utils.js 1.91 kB 0 B
packages/core/dist/utils/string-utils.mjs 414 B 0 B
packages/core/dist/utils/type-utils.js 6.93 kB 0 B
packages/core/dist/utils/type-utils.mjs 3.03 kB 0 B
packages/core/dist/vendor/uuidv7.js 8.29 kB 0 B
packages/core/dist/vendor/uuidv7.mjs 6.72 kB 0 B
packages/nextjs-config/dist/config.js 5.51 kB 0 B
packages/nextjs-config/dist/config.mjs 4.03 kB 0 B
packages/nextjs-config/dist/index.js 2.24 kB 0 B
packages/nextjs-config/dist/index.mjs 30 B 0 B
packages/nextjs-config/dist/utils.js 3.74 kB 0 B
packages/nextjs-config/dist/utils.mjs 1.87 kB 0 B
packages/nextjs-config/dist/webpack-plugin.js 3.69 kB 0 B
packages/nextjs-config/dist/webpack-plugin.mjs 1.98 kB 0 B
packages/node/dist/client.js 22.4 kB 0 B
packages/node/dist/client.mjs 20.6 kB 0 B
packages/node/dist/entrypoints/index.edge.js 4.14 kB 0 B
packages/node/dist/entrypoints/index.edge.mjs 652 B 0 B
packages/node/dist/entrypoints/index.node.js 5.08 kB 0 B
packages/node/dist/entrypoints/index.node.mjs 901 B 0 B
packages/node/dist/exports.js 3.6 kB 0 B
packages/node/dist/exports.mjs 124 B 0 B
packages/node/dist/extensions/error-tracking/autocapture.js 2.65 kB 0 B
packages/node/dist/extensions/error-tracking/autocapture.mjs 1.23 kB 0 B
packages/node/dist/extensions/error-tracking/index.js 3.88 kB 0 B
packages/node/dist/extensions/error-tracking/index.mjs 2.61 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.js 8.81 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs 7.15 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.js 2.78 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.mjs 1.45 kB 0 B
packages/node/dist/extensions/express.js 2.17 kB 0 B
packages/node/dist/extensions/express.mjs 548 B 0 B
packages/node/dist/extensions/feature-flags/crypto.js 1.57 kB 0 B
packages/node/dist/extensions/feature-flags/crypto.mjs 395 B 0 B
packages/node/dist/extensions/feature-flags/feature-flags.js 26.8 kB 0 B
packages/node/dist/extensions/feature-flags/feature-flags.mjs 25 kB 0 B
packages/node/dist/extensions/sentry-integration.js 4.66 kB 0 B
packages/node/dist/extensions/sentry-integration.mjs 3.17 kB 0 B
packages/node/dist/storage-memory.js 1.52 kB 0 B
packages/node/dist/storage-memory.mjs 297 B 0 B
packages/node/dist/types.js 603 B 0 B
packages/node/dist/types.mjs 0 B 0 B 🆕
packages/node/dist/version.js 1.21 kB 0 B
packages/node/dist/version.mjs 46 B 0 B
packages/nuxt/dist/module.mjs 4.29 kB 0 B
packages/nuxt/dist/runtime/nitro-plugin.js 994 B 0 B
packages/nuxt/dist/runtime/vue-plugin.js 652 B 0 B
packages/react-native/dist/autocapture.js 4.68 kB 0 B
packages/react-native/dist/error-tracking/index.js 6.63 kB 0 B
packages/react-native/dist/error-tracking/utils.js 2.58 kB 0 B
packages/react-native/dist/frameworks/wix-navigation.js 1.3 kB 0 B
packages/react-native/dist/hooks/useFeatureFlag.js 1.49 kB 0 B
packages/react-native/dist/hooks/useFeatureFlags.js 821 B 0 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.46 kB 0 B
packages/react-native/dist/hooks/usePostHog.js 467 B 0 B
packages/react-native/dist/index.js 3.12 kB 0 B
packages/react-native/dist/native-deps.js 13.9 kB 0 B
packages/react-native/dist/optional/OptionalAsyncStorage.js 299 B 0 B
packages/react-native/dist/optional/OptionalExpoApplication.js 377 B 0 B
packages/react-native/dist/optional/OptionalExpoDevice.js 347 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 386 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystemLegacy.js 423 B 0 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 383 B 0 B
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 303 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 443 B 0 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 644 B 0 B
packages/react-native/dist/optional/OptionalSessionReplay.js 455 B 0 B
packages/react-native/dist/posthog-rn.js 34.4 kB 0 B
packages/react-native/dist/PostHogContext.js 329 B 0 B
packages/react-native/dist/PostHogProvider.js 4.77 kB 0 B
packages/react-native/dist/storage.js 3.39 kB 0 B
packages/react-native/dist/surveys/components/BottomSection.js 1.34 kB 0 B
packages/react-native/dist/surveys/components/Cancel.js 909 B 0 B
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.58 kB 0 B
packages/react-native/dist/surveys/components/QuestionHeader.js 1.11 kB 0 B
packages/react-native/dist/surveys/components/QuestionTypes.js 10.1 kB 0 B
packages/react-native/dist/surveys/components/SurveyModal.js 3.86 kB 0 B
packages/react-native/dist/surveys/components/Surveys.js 7.18 kB 0 B
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 3.48 kB 0 B
packages/react-native/dist/surveys/icons.js 7.76 kB 0 B
packages/react-native/dist/surveys/index.js 600 B 0 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 5.66 kB 0 B
packages/react-native/dist/surveys/surveys-utils.js 9.31 kB 0 B
packages/react-native/dist/surveys/useActivatedSurveys.js 3.38 kB 0 B
packages/react-native/dist/surveys/useSurveyStorage.js 2.16 kB 0 B
packages/react-native/dist/types.js 70 B 0 B
packages/react-native/dist/utils.js 539 B 0 B
packages/react-native/dist/version.js 130 B 0 B
packages/react/dist/esm/index.js 15.1 kB 0 B
packages/react/dist/umd/index.js 17.8 kB 0 B
packages/web/dist/index.cjs 13.8 kB 0 B
packages/web/dist/index.mjs 13.7 kB 0 B
tooling/rollup-utils/dist/index.js 1.17 kB 0 B

compressed-size-action

Add new 'on_navigation' option for capture_pageleave config that captures
pageleave events on every SPA navigation (pushState, replaceState, popstate)
in addition to window unload.

This enables the expected behavior pattern for pure client-side navigation:
- pageView A → (navigate) → pageLeave A + pageView B → (navigate) → pageLeave B + pageView C
@lricoy lricoy force-pushed the lricoy/pageleave-on-navigation branch from 2148ad7 to 0be6d6f Compare October 14, 2025 18:14
@lricoy lricoy changed the title feat: add capture_pageleave 'on_navigation' option feat: add option to capture pageviews on navigation history transitions Oct 14, 2025
@lricoy lricoy marked this pull request as ready for review October 14, 2025 19:16
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@rafaeelaudibert
Copy link
Member

@lricoy what's the use case for this?

@lricoy
Copy link
Member Author

lricoy commented Oct 14, 2025

@lricoy what's the use case for this?

@rafaeelaudibert This is mostly for people using SPA/Client side navigation that would expect to have the pageview/pageleave events matching the same behavior as non-SPAs (each non-first navigation has a pageleave from the previous page and a pageview on the new page).

They could implement this themselves on each framework but I think we should have this config available since we're the ones controlling the SDK behavior. It is a recurrent question if people need the $pageleave event for some metrics (e.g: to do something like time on page reports), so I am hoping to extend the work after the PR here with some more docs on pageleave/engagement metrics like scroll depth and duration in the hopes to bring those back to the Web Analytics dashboard.

@rafaeelaudibert
Copy link
Member

It is a recurrent question if people need the $pageleave event for some metrics (e.g: to do something like time on page reports), so I am hoping to extend the work after the PR here with some more docs on pageleave/engagement metrics like scroll depth and duration in the hopes to bring those back to the Web Analytics dashboard.

Yeah, but ultimately the answer is: "no, you don't need that", right? They can run the same analysis just by using the existing events. So that's why I'm playing bad cop here lol

Will approve in case you still think strongly that this should be an option - make sure you add the right labels to this PR

Copy link
Member

@rafaeelaudibert rafaeelaudibert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you testing that you're not capturing two page leaves when you actually leave the page/browser?

if (this._instance._shouldCapturePageleaveOnNavigation()) {
const pageleaveProps = this._instance.pageViewManager.doPageLeave(new Date())
// Only capture pageleave if there was a previous page ($prev_pageview_id will be present)
if (pageleaveProps.$prev_pageview_id) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When could this not be the case? (prev_pageview_id is not present)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants