@SassNinja opened this Issue on July 16th 2021

Expected Behavior

I expect when I provide a callback to trackEvent, it's called AFTER the tracking is done meaning there's no pending request.

Current Behavior

When I pass a callback to trackEvent and immediately redirect the user once it's called, the request to matomo is still pending and therefore never finished.

matomo_callback_issue

Possible Solution

Not sure, where exactly the origin of that problem comes from.
After digging into the code I haven't found anything suspicious though the result is definitely wrong.
I assume it's related to this part in the code:
https://github.com/matomo-org/matomo/blob/fa66bc580852c2b098ba5ea7f7ba57048f258714/js/piwik.js#L2800

Steps to Reproduce (for Bugs)

  1. create a promise, track an event and pass the resolver as callback
  2. wait until the promise is resolved (meaning the callback is called) and the redirect to another page
  3. expect the matomo request being finished in the network panel in the browser dev tools
const trackEvent = () => {
  return new Promise(resolve => {
    window._paq.push(['trackEvent', 'category', 'action', undefined, undefined, undefined, resolve])
  })
}

const redirect = async () => {
  await trackEvent()
  console.log('expect matomo request being finished')
  window.location.href = 'https://...'
}

redirect()

Context

I'm redirecting the used to another website once he's done with a renewal. Therefore I cannot track anything on the target page but must track it right before redirecting him. This means I need to know when the matomo request is done to be sure everything is tracked before the current page is left.

Your Environment

  • Matomo Version: latest (4.3.1)
  • PHP Version: 7.4.20
  • Server Operating System:
  • Additionally installed plugins:
  • Browser: Chrome
  • Operating System: Mac OS
@SassNinja commented on July 16th 2021

One addition (to prove it's a timing issue):
When I just wait a bit after the tracking (but before redirecting) it's working as expected, meaning no more pending matomo request.

const justWait = () => {
  return new Promise(resolve => {
    setTimeout(resolve, 1000)
  })
}

const redirect = async () => {
  await trackEvent()
  await justWait()
  // all good when redirecting now
}
@sgiehl commented on July 16th 2021 Member

@SassNinja Maybe you need to disable the usage of sendBeacon in that case. This is used by default (if available), and as far as I know doesn't provide the possibility to execute a callback when finished. So we trigger the callback if sendBeacon returns true, which means the browser queued the request (and thus confirms the request will be sent before the unload event)

@tsteur commented on July 18th 2021 Member

@SassNinja as @sgiehl this is currently expected behaviour as when using sendBeacon the requests are sent in the background by the browser and we can't know when the request is finished. The request will generally still finish and a callback is in many cases not needed (or it is not needed to wait for the request to finish) in most cases.

I'll close this issue for now as there isn't really anything we can do. If it's important to wait for the request to finish before redirecting or so then you can disable send beacon using _paq.push(['disableAlwaysUseSendBeacon']). Generally, because the request will basically always finish when using sendBeacon, it should be fine to redirect the user directly.

@SassNinja commented on July 27th 2021

@sgiehl thanks for the hint!

I was a bit confused that the following didn't work

window._pag.push(['alwaysUseSendBeacon', false])

However calling the method disableAlwaysUseSendBeacon has worked so I'm happy

@SassNinja commented on July 27th 2021

@tsteur thanks for the explanation!

callback is in many cases not needed (or it is not needed to wait for the request to finish) in most cases

yeah, seems my case is special due to the redirect immediately after the event is dispatched (what I cannot change)

so then you can disable send beacon using _paq.push(['disableAlwaysUseSendBeacon'])

oh I see, that looks better than my approach (which I did because push(['alwaysUseSendBeacon', false]) didn't work)

const asyncTracker = window.Matomo.getAsyncTrackers()[0]

asyncTracker.disableAlwaysUseSendBeacon()
This Issue was closed on July 18th 2021
Powered by GitHub Issue Mirror