workbox
workbox copied to clipboard
[Workbox Google Analytics] [Offline] No payload sent to GTM when network resumed.
Library Affected: workbox-google-analytics
Browser & Platform: Google Chrome Version 83.0.4103.116 (Official Build) (64-bit).
Issue Description:
I used GTM in my site with heavily using dataLayer
to sent data to GTM and GA.
The problem is GTM request is using POST
method with passing data via long query parameters append in the url, no body used.
currently, when offline, workbox stores the un-reachable GTM requests to indexedDB and used them later when network resumed. after network resumed, Workbox retry all the requests but without body sent.
here is my debugging console with showing values of variables in the scope of onSync
method from google-analytics in compiled version (v5.1.2) (https://github.com/GoogleChrome/workbox/blob/v6/packages/workbox-google-analytics/src/initialize.ts#L49)
As you can see ( I debugged in generated version), I did print t
in console, which is params. It was only return qt
(queue time) which should return many parameters according to the request context in the right side panel ( s.url
variable )
My purpose solution is at this line (https://github.com/GoogleChrome/workbox/blob/v6/packages/workbox-google-analytics/src/initialize.ts#L59)
we cloud do check bodyUsed
also.
Sorry you're running into issues here. From looking at your example you, I see you're using the new App+Web (beta) in Google Analytics, and that ultimately appears to be the source of the problem.
I looked into it, and as far as I can tell there are two issues, one of which Workbox can fix, and one of which we can't:
1) It looks like the RegExp that workbox-google-analytics
is using was overly lax, and it ended up matching the new collection endpoint used by gtag.js
with App+Web properties (e.g. https://www.google-analytics.com/g/collect
).
We can update our code to only match the endpoints used by analytics.js
(e.g. /collect
, /r/collect
, and /j/collect
), which will prevent our plugin from handling those requests, but that will also mean those requests will be lost when users are offline.
2) The main issue is that the new /g/collect
endpoint used by App+Web properties does not support the &qt
param to specify time offsets, which means we can't backdate timestamps (which is needed to associate hits sent after returning online to their correct offline time). The other issue is that the /g/collect
endpoint is still in beta and it's not documented, and I'm not particularly comfortable supporting an undocumented API (that could change without notice).
If offline analytics is important to you, I'd suggest not using a App+Web property at the moment. We can look into adding support if/when App+Web properties come out of beta and support setting custom timestamps.
(cc: @diminishedprime who might know more about Google Analytic's plans to support this feature.)
Hi @philipwalton , the GA4 has been released for a while, when your team will support it?
@jingz I'm experiencing the same issue, did you find a way to fix it please? I'm really stuck on this one :(
kop khun mak khrap
@philipwalton I am having the same issue for Universal Analytics (analytics.js) as well. It seems the background-sync data is correctly saved into IndexedDB when GA tracks offline.
However, when the internet resumed, it sends empty payload other than qt=
.
So, could you please look into why it happens?
FYI: we have some thoughts on how to deal with offline analytics moving forward in the Workbox project at https://github.com/GoogleChrome/workbox/issues/3055
It's likely that we're going to encourage folks to use an appropriate "recipe" in the future, as opposed to keeping workbox-google-analytics
up to date with change in the underlying analytics platform.
I also encountered this error and raised an issue.
To fix the issue, I changed (using patch-package
) this line in node_modules/workbox-google-analytics/initialize.js
.
// Measurement protocol requests can set their payload parameters in
// either the URL query string (for GET requests) or the POST body.
const params =
request.method === 'POST'
? new URLSearchParams(await request.clone().text())
: url.searchParams;
to this
const params = url.searchParams;
// Measurement protocol requests can be set in the POST body as well.
if (request.method === 'POST') {
const additionalParams = new URLSearchParams(await request.clone().text());
for (const [key, value] of additionalParams.entries()) {
params.append(key, value);
}
}