posthog-js icon indicating copy to clipboard operation
posthog-js copied to clipboard

Pageview path capture broken for SPAs with hash-based routing

Open lesderid opened this issue 9 months ago • 3 comments

When hash-based (or other non-browser) routing is used (e.g. React Router v5's HashRouter), paths aren't captured properly in the pageview/history autocapture.

Sentry solved this by allowing the user to pass a custom history (from the history npm package) object instead of using the browser built-in HTML History API (i.e. window.history). It's then possible to pass any of the history implementations to it. This seems to work well, but might imply an additional (peer) dependency, as the npm package's API doesn't match the standard HTML one.

lesderid avatar Jun 11 '25 12:06 lesderid

Hi @lesderid, I hadn't come across hash-based routing before today, what's your use case for using this instead of path-based routing?

From reading https://v5.reactrouter.com/web/api/HashRouter it seems like this is to support legacy browsers that don't support the history API yet, is this your use case, or something else?

You can use the before_send config option to overwrite any properties on events before they are sent, so in your case, you could replace the path ($pathname property) with something custom, like path + hash.

robbie-c avatar Jul 07 '25 11:07 robbie-c

Our use case is (internal) legacy code/libraries that assume hash-based routing is used.

Other use cases:

  • SPAs deployed to environments without URL rewrite support (static site hosts like GitHub pages, local file:// URIs etc.)
  • Capacitor apps on Android using non-https androidScheme (see https://ionic.io/blog/capacitor-android-customscheme-issue-with-chrome-117)
  • Legacy browsers as you mentioned

lesderid avatar Jul 12 '25 21:07 lesderid

Pageview auto-capture does not work at all with hash-based routing. It is not just about the $pathname being incorrect. There is a check to see if pathname changed. However, location.pathname does not include hash, so it never calls capture after the initial page load. If I switch line 85 to location?.hash it works.

As mentioned above, there are plenty of use cases for hash-based routing. In my case, I use hash routing in an Electron app, so I believe there is a need for additional configuration. I am happy to create a PR if you decide on the approach.

Laruxo avatar Nov 01 '25 14:11 Laruxo