Skip to content

feat: add history api autocapture pageviews #1886

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

lricoy
Copy link
Member

@lricoy lricoy commented Apr 10, 2025

Changes

This is a follow-up of PostHog/posthog-js-lite#446, which ports the same functionality here. The tests and code are structured in a similar way but I've changed them in a attempt to make they fit the standard of this project a bit more.

In summary, if { capture_pageviews: 'history_change' } config is provided, we will send history events as page views, but only on pathname changes (no query string or hash change should trigger pageviews, even when using the back button).

Checklist

  • Tests for new code (see advice on the tests we use)
  • Accounted for the impact of any changes across different browsers
  • Accounted for backwards compatibility of any changes (no breaking changes in posthog-js!)

Copy link

vercel bot commented Apr 10, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
posthog-js ✅ Ready (Inspect) Visit Preview Apr 14, 2025 10:53pm

Copy link

github-actions bot commented Apr 10, 2025

Size Change: +16.4 kB (+0.45%)

Total Size: 3.68 MB

Filename Size Change
dist/array.full.es5.js 306 kB +1.74 kB (+0.57%)
dist/array.full.js 386 kB +1.51 kB (+0.39%)
dist/array.full.no-external.js 385 kB +1.51 kB (+0.39%)
dist/array.js 198 kB +1.72 kB (+0.88%)
dist/array.no-external.js 196 kB +1.72 kB (+0.89%)
dist/main.js 198 kB +1.72 kB (+0.88%)
dist/module.full.js 386 kB +1.51 kB (+0.39%)
dist/module.full.no-external.js 385 kB +1.51 kB (+0.39%)
dist/module.js 198 kB +1.72 kB (+0.88%)
dist/module.no-external.js 197 kB +1.72 kB (+0.88%)
ℹ️ View Unchanged
Filename Size
dist/all-external-dependencies.js 216 kB
dist/customizations.full.js 11.6 kB
dist/dead-clicks-autocapture.js 14.4 kB
dist/exception-autocapture.js 10.2 kB
dist/external-scripts-loader.js 2.75 kB
dist/posthog-recorder.js 211 kB
dist/recorder-v2.js 115 kB
dist/recorder.js 115 kB
dist/surveys-preview.js 64.7 kB
dist/surveys.js 71.4 kB
dist/tracing-headers.js 1.76 kB
dist/web-vitals.js 10.4 kB

compressed-size-action

src/types.ts Outdated
Comment on lines 1280 to 1284
/**
* Whether to capture History API events (pushState, replaceState, popstate)
*/
captureHistoryEvents?: boolean

Copy link
Member

Choose a reason for hiding this comment

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

do we need this on remote config?
are you adding this in team settings as well? that's super cool!

Copy link
Member Author

Choose a reason for hiding this comment

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

I was actually going to ask what the pattern is here; I see most of the extensions are on the remote config, but I don't think we would actually need it there, but if it is a good thing, sure!

Copy link
Member

Choose a reason for hiding this comment

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

so, you only need to add it to remote config if you want to control whether it is active remotely from team settings

we don't control pageview capture iirc from remote settings so i think safe not to add this here

Copy link
Member

Choose a reason for hiding this comment

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

yep, confirmed we don't control page view capture remotely so i'd skip this

const result = originalPushState.apply(this, args)
try {
if (isEnabled()) {
instance.capture('$pageview', { navigation_type: 'pushState' })
Copy link
Member

Choose a reason for hiding this comment

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

Just thinking through some edge cases here.

What about something like e.g. metabase where every query run updates the state? Or sites that automatically update query params when you visit (I've seen this with google ad links, e.g. when I google shoes and click the first shopping link https://arterton.co.uk/products/acme-wingtip-balmoral-oxford-8091?variant=43255266050221&utm_medium=product_sync&utm_source=google&utm_content=sag_organic&utm_campaign=sag_organic&gad_source=1&gclid=EAIaIQobChMIxsXc4PvNjAMVlJJQBh0Dew1OEAQYASABEgJ18vD_BwE it did this (it added the country code as a query param)

Maybe this should only trigger when the actual pathname changes, rather than the query or hash?

Or maybe those users just shouldn't use this 🤷

Copy link
Member Author

Choose a reason for hiding this comment

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

That is a really good point. I think most use cases would be for only the pathname, but on that same link, if I click on different sizes, it changes the query for the variant, which some people may also want to track.

We could add an option on the config like { captureHistoryChange: 'always' | 'pathname' | 'never'} instead of just a boolean but I am afraid this could grow...

Thoughts @ivanagas ?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should only trigger a pageview on path change if possible and keep it as a boolean.

This seems to be what people expect. For example, the Docusaurus plugin captured when the hash changed unintentionally and people complained so we fixed it. Hash or state changes are probably handled better by autocapture or custom events.

Copy link
Member Author

Choose a reason for hiding this comment

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

Cool! I've updated both PRs to follow that line and only capture pageviews when the path changes.

@lricoy lricoy force-pushed the feat/add-history-api-autocapture-pageviews branch from f180342 to e0d50ec Compare April 11, 2025 00:13
@lricoy lricoy marked this pull request as ready for review April 11, 2025 00:38
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.

PR Summary

This PR adds automatic pageview tracking for History API navigation events in the PostHog JavaScript SDK.

  • Added new capture_history_events configuration option (default: false) to enable automatic pageview tracking for History API navigation
  • Created HistoryAutocapture class that monitors pushState, replaceState, and popstate events to capture pageviews
  • Implemented pathname-based tracking that only triggers pageviews when the URL path changes (ignoring query string/hash changes)
  • Added comprehensive test suite covering various navigation scenarios, edge cases, and proper integration with PageViewManager

4 file(s) reviewed, 2 comment(s)
Edit PR Review Bot Settings | Greptile

src/types.ts Outdated
*
* @default false
*/
capture_history_events: boolean
Copy link
Member

@robbie-c robbie-c Apr 11, 2025

Choose a reason for hiding this comment

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

How about adding another option to capture_pageview, e.g. capture_pageview: 'history-change?

This is what people might expect capture_pageview to do anyway

Copy link
Member Author

@lricoy lricoy Apr 11, 2025

Choose a reason for hiding this comment

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

Makes sense to me, there is no capture_pageview option for posthog-js-lite, so it would be just the way we would configure this here, right? Asking because I am trying to keep those two in sync as much as possible.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done :)

@lricoy lricoy force-pushed the feat/add-history-api-autocapture-pageviews branch from f85c74a to f1810ee Compare April 11, 2025 18:33
@lricoy lricoy requested a review from robbie-c April 11, 2025 19:10
@lricoy
Copy link
Member Author

lricoy commented Apr 14, 2025

@ivanagas @pauldambra, this looks good to be merged. Do you guys want to take another look?

Copy link

github-actions bot commented Apr 14, 2025

@lricoy lricoy force-pushed the feat/add-history-api-autocapture-pageviews branch from b53e9d0 to 1fc878c Compare April 14, 2025 22:09
@lricoy lricoy enabled auto-merge (squash) April 14, 2025 22:10
@lricoy
Copy link
Member Author

lricoy commented Apr 15, 2025

TWIMC: I am updating the playground samples and checking some docs references before merging this, it should be good to go tomorrow

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.

4 participants