BuilderIO / partytown

Relocate resource intensive third-party scripts off of the main thread and into a web worker. 🎉
https://partytown.builder.io
MIT License
12.85k stars 426 forks source link

[🐞] Error 404 for '/_next/static/%7Epartytown/proxytown' and some iOS/Safari versions #554

Open andre-mr opened 4 months ago

andre-mr commented 4 months ago

Describe the bug

Hi. I've noticed a discrepancy in event tracking on Google Analytics (using Google Tag Manager) compared to other records made by the page's own code. There are fewer events registered in Google Analytics.

During investigations, I observed that in the Cloudfront logs, there are hundreds of 404 errors targeting this uri: /_next/static/%7Epartytown/proxytown

And all of them from just these 2 user-agents: Mozilla/5.0%20(iPhone;%20CPU%20iPhone%20OS%2015_8%20like%20Mac%20OS%20X)%20AppleWebKit/605.1.15%20(KHTML,%20like%20Gecko)%20Version/15.6.6%20Mobile/15E148%20Safari/604.1

Mozilla/5.0%20(iPhone;%20CPU%20iPhone%20OS%2017_2_1%20like%20Mac%20OS%20X)%20AppleWebKit/605.1.15%20(KHTML,%20like%20Gecko)%20Version/17.2%20Mobile/15E148%20Safari/604.1

I'm concerned that this may be affecting event capture on these devices. Until today, I have been using version 0.8.1, and I just noticed that we are now at 0.9.1, and I have updated to it just now. However, I haven't found any mention of this scenario in the commits.

Reproduction

Impossible to reproduce

Steps to reproduce

I cannot reproduce this without those devices/browsers and you don't answer "Discussions" posts.

Browser Info

Safari 15.6.6 and 17.2

Additional Information

next version: 13.5.5 partytown version (when cdn logs were generated): 0.8.1 (i just updated now to 0.9.1)

_app.tsx:

import "@/styles/globals.css";
import type { AppProps } from "next/app";
import Script from "next/script";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Script id="google-tag-manager" strategy="worker">
        {`
        (function(w,d,s,l,i){
          w[l]=w[l]||[];
          w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});
          var f=d.getElementsByTagName(s)[0],
          j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';
          j.async=true;
          j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
          f.parentNode.insertBefore(j,f);
        })(window,document,'script','dataLayer','${process.env.NEXT_PUBLIC_GTM_ID}');
        `}
      </Script>
      <Component {...pageProps} />
    </>
  );
}

next.config.js:

  experimental: {
    nextScriptWorkers: true,
  },

these configs seem to work for the last months, i only have part of events not being fired and i found those logs from cdn.

gioboa commented 4 months ago

is it related to this one #546?

karenmt commented 4 months ago

I don't believe it's related to that bug. We had the same issue, which resulted in lost conversions. We have our library in /~partytown, and it generated 404 errors to /~partytownproxytown and to /~partytown/proxytown, but only on Apple devices - iOS Safari 604.1, iPad Safari 604.1, and MacOS Safari 605.1.15. We are using PartyTown 0.8.2, though for awhile we were referencing a different directory which has 0.8.1, with the same errors. We have a Cloudflare worker as a proxy.

Config:

window.onload = function () {
    window.partytown = {
        resolveUrl: function(url, location, type) {
            if (type === 'script') {
                let proxyUrl = new URL("https://www.ourdomain.com/api/partytown/proxy")
                proxyUrl.searchParams.append('url', url.href)
                return proxyUrl;
            }
            return new URL(url);
        },
        // debug: true,
        lib: "/~partytown/",
        forward: [
            'dataLayer.push', // Google Tag Manager
            'fbq', // Facebook
            '_tfa.push', // Taboola
        ],
    }

    document.head.appendChild(partytownScript);
}
andre-mr commented 4 months ago

we had to disable it. analytics data is priority over performance for our business now. ios users are about 1/3 and it's a lot of data lost.

we'll monitor this thread.

just one of many apple things we had to deal with. safari seems to be the new internet explorer for web evolution. :/

myleshyson commented 3 months ago

Ok not sure if this is exactly the same issue, but we found a drop in traffic as well when using Google Tag Manger, and I think we share the same underlying problem. Specifically for us, the drop was from Safari (in-app) traffic, and we were able to fix it by updating the GTM snippet.

I'll explain what the issue is below but the TL;DR is, because the GTM snippet dynamically loads the gtm.js script, if the snippet itself is loaded by partytown, then the fallback partytown has in place won't work. You need to check to make sure serviceWorkers are supported. Here's our updated snippet that started working for us. We added navigator as an argument to check if service workers were available.

(function(w,d,s,l,i,n){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
  j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.src=
  'https://www.googletagmanager.com/gtm.js?id='+i+dl;
  j.type=n.serviceWorker ? 'text/partytown' : ''; // <--------------make sure service workers work. if not, load like normal.
  j.async=!n.serviceWorker; // <------------------- this isn't necessary, but the script is already a little delayed from partytown. Didn't want it delayed any more than it is.
  f.parentNode.insertBefore(j,f);
  w.dispatchEvent(new CustomEvent('ptupdate')); // <----------------- because it's dynamically loaded, make sure partytown knows about it.
})(window,document,'script','dataLayer','{{ containerId }}', navigator);

The reason is because there are two different webviews apps can use, SFSafariViewController and WKWebView. Apps like slack use SFSafariViewController which is essentially full featured safari and includes support for service workers. Apps like Instagram appear to use WKWebView which is basically a barebones Safari, and doesn't appear to support service workers.

I'm not super familiar with next.js, but it looks like your loading the GTM script as a web worker from the get-go. If there's no fallback logic to load your GTM snippet on the main thread, then it won't load on apps like Instagram.

Partytown itself tries to fallback to loading any text/partytown scripts on the main thread when serviceWorkers are disabled. However with the GTM snippet, and from a lot of examples i've seen on the internet, simply adding j.type=text/partytown in the GTM snippet won't fallback correctly. Reason is because partytown will fallback the snippet itself, but that snippet is dynamically loading scripts itself which partytown doesn't seem to account for.

I think the docs for for GTM in partytown need to be updated as well. Gtag and GTM are two different things. The current HTML example shows how to load the gtag snippet, which is different than the tag manager snippet i'm referencing here.