Skip to content
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

Add option to wait for requests on navigation #205

Open
macobo opened this issue Mar 19, 2021 · 9 comments
Open

Add option to wait for requests on navigation #205

macobo opened this issue Mar 19, 2021 · 9 comments
Labels
enhancement New feature or request

Comments

@macobo
Copy link
Contributor

macobo commented Mar 19, 2021

When user navigates away from the page, we do try to send queued events in a best-effort way with sendBeacon. However this has a low reliability rate, resulting in lost events and more. This can be especially annoying for form submissions, which immediately reload the page.

Proposal:
Add configuration option that pauses page navigation until posthog-js has finished sending out requests or until some timeframe has passed (e.g. 1s). Default this to false, but suggest it if users if they're experiencing trouble.

@mariusandra
Copy link
Collaborator

How should this happen? The only way I know to pause leaving a page is to show an annoying popup like this:

image

@macobo
Copy link
Contributor Author

macobo commented Mar 23, 2021

There's a small hack you can do for this - you can block the event loop for (with a while (true) loop) inside the beforeunload handler. Obviously the page will 'freeze' but ideally you'd do this for a really short while.

You can see this approach from He@p does when you beautify their tracking script - they do it for 100ms by default.

@mariusandra
Copy link
Collaborator

Haha, that's nifty. Hopefully no browsers will start punishing scripts that do this any time soon. Worth trying for sure.

@snemvalts
Copy link

snemvalts commented Jan 24, 2022

Usecase which we have:

posthog.submit('Form submitted', { properties: { formParams } })
await submit(formParams)
window.reload()

In cases like these it is highly unlikely that posthog.submit will submit the event before we reload the page. If it's a new feature and we are measuring whether users care about it with this event, this can influence our product decisions by a lot. Since it's hard to measure how many events are dropped in cases like this (dependent on the internet connection of users etc), it makes it even more scary.

Ideally posthog.capture should return a Promise, but as Karl responded, older browser support is required. Plausible solves this by providing a callback https://plausible.io/docs/custom-event-goals#1-trigger-custom-events-with-javascript-on-your-site, that can be wrapped to a promise really easily on our side, a la:

const wrappedCapture = (name, properties, options) => new Promise((res, reject) => {
  // not mandatory but in case it takes too long
  const rejectionTimeout = setTimeout(reject, 1000)
  posthog.capture(name, properties, {
    ...options,
    callback: () => { 
      res()
      clearTimeout(rejectionTimeout)
    },
  })
})

or even on Posthog's API side with a config option or something. Or even moving failure into the callback itself, so there isn't a need to setTimeout outside, or making it a separate option (successCallback and failureCallback)

IMO the timeout blocking the event loop wouldn't be a solution, more like a band-aid in this case, it still doesn't provide guarantee that an event went through while freezing the page, which is bad for end user UX.

@mariusandra
Copy link
Collaborator

I think the right call is to expose something like posthog.flush(), which would clear all enqueued requests, and return a promise you can await for.

As a temporary workaround, the undocumented internal _handle_unload() function that sends the last events can be called manually before reloading the window.

posthog.submit('Form submitted', { properties: { formParams } })
await submit(formParams)
posthog._handle_unload() // flush the buffer
await new Promise(resolve => window.setTimeout(resolve, 500)) // wait 500ms
window.reload()

Unfortunately it doesn't return a promise nor take a callback, but a 500ms delay could be enough to make sure the events get captured.

@toger5
Copy link

toger5 commented Jan 3, 2023

With the current version of posthog-js there is also the option to use send_instantly for the capture options:

const options = {send_instantly: true};
posthog.capture("myEV", { ...properties }, options);

@keith-chargeover
Copy link

Following.

We would like to see this implemented also. We are concerned that we are losing events (and thus that Posthog data is inaccurate and misleading our customer intelligence efforts) because there is no way to ensure the events are actually delivered.

@jacknewberry
Copy link

Me too. Capturing when a user leaves your website must be a common use case.

In our case, when the user clicks a button, if the form data is valid, we want to capture an event then redirect.

Ideally postHost.capture would take a callback or return a promise, but a method to flush the queue (and get a promise/callback for when it is flushed) would also work.

@rafaeelaudibert rafaeelaudibert added the enhancement New feature or request label Dec 11, 2024
@rafaeelaudibert
Copy link
Member

This could be partially solved if we supported offline applications because we'd always keep a copy of our events in an IndexedDB-based database, which could then be flushed once we came back to that page. See #1583

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants