Open Manduro opened 2 years ago
I am having the same issue here. On top of that, I also seem to be getting CORs for google analytics.
I am also loading Google Tag Assistant. However by sheer luck it randomly connected. I kept refreshing and after about 40 times it finally connected. Ive been able to connect 3 times without the error, but it does seem like its completely random. I've been getting OPs original error when it does not connect.
So the main reason this is happening from my investigation is that when you try to connect google tag assistant to your app, it will try to fetch the script from https://www.googletagmanager.com/debug/bootstrap?cond=2&id=GTM-xxxxxxx
which does not have the right headers in place and results in CORs.
This requires a reverse proxy set up for this particular resource and I've set it up a way as shown below:
<Partytown
forward={['dataLayer.push']}
resolveUrl={(url) => {
if (url.pathname.includes('debug/bootstrap')) {
var proxyUrl = new URL(
'https://your-hosted-url/party-proxy',
)
proxyUrl.searchParams.append('url', url)
return proxyUrl
}
return url
}}
/>
and I've set up a proxy with NGINX with a hard-coded link for testing purposes as below
location /party-proxy {
proxy_set_header Access-Control-Allow-Origin *;
proxy_pass https://www.googletagmanager.com/debug/bootstrap?id=GTM-xxxxxxx&src=GTM&cond=2;
}
This helps me get passed the CORs issue but I end up with these errors in the console after the timeout and I can't seem to identify what I may need to forward to the main thread.
This helps me get passed the CORs issue but I end up with these errors in the console after the timeout and I can't seem to identify what I may need to forward to the main thread.
Yeah I got to the same point. the c.Postmessage is not a function
error is repeated every second.
To make sure it's not a disallowing the POST method I tried adding:
headers["Access-Control-Allow-Origin"] = "*"; headers["Access-Control-Allow-Methods"] = "GET,POST,HEAD,OPTIONS";
To my reverse proxy to https://www.googletagmanager.com/debug/bootstrap... And that doesn't seem to be the issue.
There's a partytown JS error that precedes the postMessage error. I ran partytown in debug mode and here's the console output (in case it's helpful to anybody).
The solution I ultimately arrived at is to set a query param like ?no_partytown=1 that if true, suppresses type="text/partytown"
on the gtm script tag.
I played with integrating tag assistant here: https://github.com/slawekkolodziej/partytown/tree/tag-assistant
I wrote a document with what I've found: https://github.com/slawekkolodziej/partytown/blob/tag-assistant/src/lib/web-worker/tag-assistant.md
The implementation is not finished yet. It's rather at early stage / POC. There are some missing parts and the implementation is definitely not production ready.
Thanks @slawekkolodziej, I think the doc you linked has moved here: https://github.com/slawekkolodziej/partytown/blob/tag-assistant/docs/tag-assistant.md.
Would this issue be causing this behavior?
Basically added GTM with Partytown but unable to debug that events are working before merging Partytown to production.
Hey @graysonhicks yes, I moved that file recently. From your screenshots I can tell that you are using legacy Tag Assistant plugin. My code works with Tag Assistant Companion (https://chrome.google.com/webstore/detail/tag-assistant-companion/jmekfmbnaedfebfnmakmokmlfpblbfdm).
I figured out a nicer way to integrate Tag Assistant that doesn't require adding GTM-specific code to Partytown. However, it still needs some changes in src/lib/web-worker/worker-serialization.ts
.
thanks @slawekkolodziej, I found a similar problem in version 6.2. I think you have added this from your PR (https://github.com/BuilderIO/partytown/pull/183).
Do I need to follow the steps you share here https://github.com/slawekkolodziej/partytown/blob/tag-assistant/docs/tag-assistant.md ?
I am facing the same issue. I am able to move the GTM script to a SW, but once it is there, I am not able to test the GTM events.
Any suggestion on how I should test it?
I read the guide about debugging Tag Assistant, but I'm still confused on a few things:
@NotFrancee I'm still not clear either on the debug mode.
For Gatsby the proxy is either with createRedirect
if you are not using the Script
component or with the partytownProxiedUrls
option if you are using the Script
component.
Without Script
component:
https://github.com/PaulieScanlon/gatsby-third-party-scripts/pull/4/files
With Script
component:
https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-script/#proxy-configuration
I'm also facing the same error partytown-ww-sw.js?v=0.7.3:1715 Error: Error finding instance "1ycwlf6dz4.d" on window 2
On nextJS 11. Anyone know how to test / fix this?
The solution I ultimately arrived at is to set a query param like ?no_partytown=1 that if true, suppresses
type="text/partytown"
on the gtm script tag.
@tarponjargon how you fixed it? Can you paste is here?
Just curious, are you trying to use this within react application? I may wrap the code I created in a react component sometime over the next week or two and release it as npm module.
@slawekkolodziej if you have a sample of how to use partytown with NextJS, please I'd love to see one. I've tried a lot and never managed to make it work with NextJS Script component worker
strategy. It always throws CORS
errors. Partytown docs says to use NextJS rewrites as a reverse-proxy but never really understood how to do it. Never found any example either.
@slawekkolodziej I'm working with Next 11 and able to load all GTM and other 3rd parties which are added inside GTM with worker. I'm able to see realtime analysis in GA as well with partytown worker, But when doing "Tag Assistant" check its show instance error . I did added all proxies of all my third-parties on nginx which works good.
@babvi If its possible can you share a minimal repo. I am facing same issue and couldnt solve it for few days...
I have faced same issue. But I just resolved this issue by update partytown version from 0.7.1 to 0.7.4 and add below code into Set Hook to disable partytown when using Google Tag Assistant (check debug signal in the URL - gtm_debug) in NextJS Static Web:
set={(opts) => { const isDebugging = opts.window.location.search.includes("gtm_debug"); if ( isDebugging && opts.name === "type" && opts.nodeName === "SCRIPT" ) { return opts.prevent; } return opts.continue; }}
@phongnguyen0601 We came up with a similar solution for our SSR (not using NEXT) and it's an okay workaround for the moment.
function checkIfGoogleTagAssistantIsEnabled(ctx) {
const [, query] = ctx.request.url.split('?');
const searchParams = new URLSearchParams(query);
return !!searchParams.get('gtm_debug');
}
return `<script type="text/${
checkIfGoogleTagAssistantIsEnabled(ctx) ? 'javascript' : 'partytown'
}">(function(w,d,s,l,i){w[l]=w[l]||[];w[l].p..........
This is how I fixed the CORS error for analytics and preview mode
Use resolveUrl
in gatsby-ssr.js:
<script
key="partytown-vanilla-config"
dangerouslySetInnerHTML={{
__html: `partytown = {
resolveUrl(url, location) {
if (
url.hostname === "www.google-analytics.com" &&
url.pathname.endsWith(".js")
) {
var proxyUrl = new URL(location.origin+'/google-analytics');
proxyUrl.searchParams.append("url", url.href);
return proxyUrl;
}
if (
url.pathname.includes("/debug/bootstrap")
) {
var proxyUrl = new URL(location.origin+'/googletagmanager/debug/bootstrap');
proxyUrl.searchParams.append("url", url.href);
return proxyUrl;
}
return url;
}
}`,
}}
/>,
createRedirect
in gatsby-node.js
exports.onPreBuild = async ({ actions: { createRedirect } }: any) => {
await copyLibFiles(path.join(__dirname, "static", "~partytown"));
createRedirect({
fromPath: `/google-analytics?url=:url`,
toPath: `:url`,
statusCode: 200,
});
createRedirect({
fromPath: `/googletagmanager/debug/bootstrap?url=:url`,
toPath: `:url`,
statusCode: 200,
});
};
@slawekkolodziej if you have a sample of how to use partytown with NextJS, please I'd love to see one. I've tried a lot and never managed to make it work with NextJS Script component
worker
strategy. It always throwsCORS
errors. Partytown docs says to use NextJS rewrites as a reverse-proxy but never really understood how to do it. Never found any example either.
If you are looking for a solution, you can take a look at the configuration in my last project. you must put related codes to _app and _document
https://github.com/NavidGoalpure/visabox/blob/master/pages/_document.tsx https://github.com/NavidGoalpure/visabox/blob/master/pages/_app.tsx
I found this solution on the Internet of course, but I can remember the reference.
I have faced same issue. But I just resolved this issue by update partytown version from 0.7.1 to 0.7.4 and add below code into Set Hook to disable partytown when using Google Tag Assistant (check debug signal in the URL - gtm_debug) in NextJS Static Web:
set={(opts) => { const isDebugging = opts.window.location.search.includes("gtm_debug"); if ( isDebugging && opts.name === "type" && opts.nodeName === "SCRIPT" ) { return opts.prevent; } return opts.continue; }}
It works for me! thanks
I have faced same issue. But I just resolved this issue by update partytown version from 0.7.1 to 0.7.4 and add below code into Set Hook to disable partytown when using Google Tag Assistant (check debug signal in the URL - gtm_debug) in NextJS Static Web:
set={(opts) => { const isDebugging = opts.window.location.search.includes("gtm_debug"); if ( isDebugging && opts.name === "type" && opts.nodeName === "SCRIPT" ) { return opts.prevent; } return opts.continue; }}
You can try another way to disable partytown by checking attribute data-tag-assistant-present
of document element (#document) inside iframe of partytown sandbox service worker. It works for me:
let docElement = opts.window.document.documentElement;
let assistant = docElement.getAttribute("data-tag-assistant-present");
if (assistant && opts.name === "type" && opts.nodeName === "SCRIPT") {
return opts.prevent;
}
@phongnguyen0601 We came up with a similar solution for our SSR (not using NEXT) and it's an okay workaround for the moment.
function checkIfGoogleTagAssistantIsEnabled(ctx) { const [, query] = ctx.request.url.split('?'); const searchParams = new URLSearchParams(query); return !!searchParams.get('gtm_debug'); } return `<script type="text/${ checkIfGoogleTagAssistantIsEnabled(ctx) ? 'javascript' : 'partytown' }">(function(w,d,s,l,i){w[l]=w[l]||[];w[l].p..........
this is great!! very useful!! thanks @phongnguyen0601
I have same issue. I'm using @astrojs/partytown.
Here's how I'm solving this in SvelteKit (not the most dry
, but you barely touch this anyway).
//+layout.server.ts
import type { LayoutServerLoad } from './$types';
export const load = (async (event) => {
const { url } = event;
const gtmDebug = url.searchParams.get('gtm_debug');
return {
gtmDebug: !!gtmDebug
};
}) satisfies LayoutServerLoad;
<script lang="ts">
import type { LayoutData } from './$types';
import { partytownSnippet } from '@builder.io/partytown/integration';
import { onMount } from 'svelte';
import { VERCEL_PROD } from '$lib/shared/utils/environment';
export let data: LayoutData;
$: ({ gtmDebug } = data);
let scriptEl: HTMLScriptElement | null = null;
onMount(() => {
if (scriptEl) {
scriptEl.textContent = partytownSnippet();
}
});
</script>
<svelte:head>
{#if VERCEL_PROD}
<script>
partytown = {
forward: ['dataLayer.push'],
resolveUrl: (url) => {
const siteUrl = 'https://nocode.gallery/fissa';
if (url.hostname === 'www.googletagmanager.com') {
const proxyUrl = new URL(`${siteUrl}/gtm`);
const gtmId = new URL(url).searchParams.get('id');
gtmId && proxyUrl.searchParams.append('id', gtmId);
return proxyUrl;
} else if (url.hostname === 'www.google-analytics.com') {
const proxyUrl = new URL(`${siteUrl}/ga`);
return proxyUrl;
}
return url;
}
};
</script>
<script bind:this={scriptEl}></script>
{#if gtmDebug}
<script>
(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', 'GTM-XXX');
</script>
{:else}
<script type="text/partytown">
(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', 'GTM-XXX');
</script>
{/if}
{/if}
</svelte:head>
<slot />
Just curious, are you trying to use this within react application? I may wrap the code I created in a react component sometime over the next week or two and release it as npm module.
@slawekkolodziej thanks for your great work on exploring implementation of Tag Assistant! Could you please share the implementation you used for GTM beyond the example? we tried the approach here in our GatsbyJS project, but could not get native page views to fire within GTM: https://github.com/slawekkolodziej/partytown/blob/tag-assistant/docs/tag-assistant.md. We are using onRouteChange and sending custom events to GTM to fire tags in preview.
An NPM module would be a huge win for the Gatsby + Partytown side!
@grahamd711, sorry for not responding sooner, I've been super busy lately, will try to wrap this up during the first half of May.
@slawekkolodziej sounds great! I will keep you updated on my progress with GTM events as well
@slawekkolodziej Hey man, do have any updates? 😬
I worked on this more during this week, hoping to have an npm package next week 👍
@slawekkolodziej looking forward to testing! I can deploy on two production sites rather quickly to get some early feedback for you
Pure html implementation
index.html
<head>
<script>
function checkIfGoogleTagAssistantIsEnabled() {
const urlParams = new URLSearchParams(window.location.search);
const gtm_debug = urlParams.get('gtm_debug');
return !!gtm_debug;
}
document.addEventListener('DOMContentLoaded', function() {
var scriptType = checkIfGoogleTagAssistantIsEnabled() ? 'text/javascript' : 'text/partytown';
var script = document.createElement('script');
script.type = scriptType;
script.async = true;
script.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-XXXX';
var firstScript = document.getElementsByTagName('script')[0];
firstScript.parentNode.insertBefore(script, firstScript);
});
</script>
<script type="text/javascript" src="/~partytown/partytown.js">
<script>
partytown = {
forward: ['dataLayer.push'],
};
</script>
<script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXX"></script>
<script type="text/partytown">
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXX');
</script>
<head>
webpack.config.js
...
new CopyPlugin({
patterns: [
{
from: partytown.libDirPath(),
to: path.join(__dirname, 'public', '~partytown'),
},
],
}),
...
I worked on this more during this week, hoping to have an npm package next week 👍
Or next month 😅
I have finally published the npm package for GTM integration. You can find it on npm at @superside-oss/partytown-gtm.
Before you start using the package, please take note of the following:
I have included a sample Next.js integration. In this integration, there are two key files that you should focus on:
amazing work @slawekkolodziej this is great 🤝 ! I'll get this wired up in our nextjs app and let you know how it goes.
I worked on this more during this week, hoping to have an npm package next week 👍
Or next month 😅
I have finally published the npm package for GTM integration. You can find it on npm at @superside-oss/partytown-gtm.
Before you start using the package, please take note of the following:
- The package requires the Tag Assistant Companion browser plugin to work properly.
- I apologize for not having a README file ready at the moment, but I will make sure to create one soon.
- Please be aware that the module is currently in the prerelease stage, use it at your own risk.
I have included a sample Next.js integration. In this integration, there are two key files that you should focus on:
- src/components/ThirdParty.tsx: This file imports the GTMScript component, which takes care of loading GTM and adding the necessary snippets for Partytown integration.
- src/app/api/third-party/route.ts: Some files cannot be loaded by Partytown due to missing CORS headers. This issue affects certain Tag Assistant files as well. To overcome the problem, this API endpoint creates a proxy for problematic files.
@excelsior091224
I have same issue. I'm using [@astrojs/partytown]
To anyone using Astro or something similar:
Create a gtm.astro
component
---
---
<script>
const searchParams = new URL(window.location.href);
const isDebug = searchParams.searchParams.get('gtm_debug');
const scripts = [
{
src: 'https://www.googletagmanager.com/gtm.js?id=google-tag-id',
text: null,
},
{
src: null,
text: `
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID');
`,
},
];
function injectScripts() {
scripts.forEach((s) => {
const script = document.createElement('script');
script.type = isDebug ? 'text/javascript' : 'text/partytown';
if (s.src) script.src = s.src;
if (s.text) script.text = s.text;
document.head.appendChild(script);
});
}
injectScripts();
</script>
proxy the requests in astro.config.mjs
partytown({
config: {
resolveUrl: (url, location) => {
// these were the proxied hosts I wanted to proxy
const proxiedHosts = [
'googletagmanager.com',
'connect.facebook.net',
'googleads.g.doubleclick.net',
]
if (proxiedHosts.includes(url.hostname)) {
const proxyUrl = new URL('proxy path', 'proxy origin');
proxyUrl.searchParams.append('url', url.href);
return proxyUrl;
}
return url;
},
forward: ['dataLayer.push', 'fbq'],
},
}),
``
You can then implement an API endpoint that proxies a request to those proxiedHosts
or whatever you need.
So, anyways to fix the CORS issue and other issue in NextJS Pages Directory version 12-13?
@excelsior091224
I have same issue. I'm using [@astrojs/partytown]
To anyone using Astro or something similar:
1. Create a `gtm.astro` component
--- --- <script> const searchParams = new URL(window.location.href); const isDebug = searchParams.searchParams.get('gtm_debug'); const scripts = [ { src: 'https://www.googletagmanager.com/gtm.js?id=GTM-PCMP3LG', text: null, }, { src: null, text: ` window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', 'GA_MEASUREMENT_ID'); `, }, ]; function injectScripts() { scripts.forEach((s) => { const script = document.createElement('script'); script.type = isDebug ? 'text/javascript' : 'text/partytown'; if (s.src) script.src = s.src; if (s.text) script.text = s.text; document.head.appendChild(script); }); } injectScripts(); </script>
2. proxy the requests in `astro.config.mjs`
partytown({ config: { resolveUrl: (url, location) => { // these were the proxied hosts I wanted to proxy const proxiedHosts = [ 'googletagmanager.com', 'connect.facebook.net', 'googleads.g.doubleclick.net', ] if (proxiedHosts.includes(url.hostname)) { const proxyUrl = new URL('proxy path', 'proxy origin'); proxyUrl.searchParams.append('url', url.href); return proxyUrl; } return url; }, forward: ['dataLayer.push', 'fbq'], }, }), `` You can then implement an API endpoint that proxies a request to those `proxiedHosts` or whatever you need.
Thank you this worked.
@fprl
It works. Thanks!
<!-- New GTM Test 2 -->
<script>
const searchParams = new URL(window.location.href);
const isDebug = searchParams.searchParams.get("gtm_debug");
const scripts = [
{
src: "https://www.googletagmanager.com/gtm.js?id=MY-GTM-ID",
text: null,
},
{
src: null,
text: `
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'MY-ANALYTICS-ID');
`,
},
];
function injectScripts() {
scripts.forEach((s) => {
const script = document.createElement("script");
script.type = isDebug ? "text/javascript" : "text/partytown";
if (s.src) script.src = s.src;
if (s.text) script.text = s.text;
document.head.appendChild(script);
});
}
injectScripts();
</script>
partytown({
// Adds dataLayer.push as a forwarding-event.
config: {
resolveUrl: (url, location) => {
// these were the proxied hosts I wanted to proxy
const proxiedHosts = [
"googletagmanager.com",
"connect.facebook.net",
"googleads.g.doubleclick.net",
];
if (proxiedHosts.includes(url.hostname)) {
const proxyUrl = new URL("proxy path", "proxy origin");
proxyUrl.searchParams.append("url", url.href);
return proxyUrl;
}
return url;
},
forward: ["dataLayer.push", "fbq"],
// forward: ["dataLayer.push"],
},
}),
Thanks for the tips everyone, we've gone with the same solution for now where partytown is disabled when used with Tag assistant. Hoping to see an update to the library to remove that need.
@slawekkolodziej I have tried the same that you have shared, @superside-oss/partytown-gtm. to verify I have replaced my GTM-ID with the next-js implementation, but I am getting below error Could you please help to check?
It seems that the error is in your script. You can see match_utm_source
is not a function. Does it work if you run it with just text/partytown
and not through <GTMScript>
?
@slawekkolodziej I have tried with both text/partytown
and <GTMScript>
but getting same error. However, If I use standard way of GTM script, it does not give any error. Could you please tell why this might be happening?
This PartyTown doesn't seem to work in NextJS. Also, no proper documentation to showcase the errors and solve them either. CORS issue is not as straightforward to solve in the NextJS it seems and even those who managed to solve it are getting some other errors.
@RenuSuresh seems like one of your third-party scripts is not working well in Partytown. This feels unrelated to the GTM. You can debug this by directly importing these scripts into Partytown and disabling them one at a time to isolate the one causing errors. Once you know which one is making troubles, you can try to fix it yourself or create a new Partytown issue.
@geekysaurabh001 are you talking about Partytown in general or the GTM plugin specifically? I've had Partytown and the GTM plugin running smoothly on a production NextJS app for over a year. The recently added README for @superside-oss/partytown-gtm includes setup instructions now. However it has always featured an example NextJS app. This is open source, if you feel that something is missing, feel free to contribute via pull request. 😄
@RenuSuresh seems like one of your third-party scripts is not working well in Partytown. This feels unrelated to the GTM. You can debug this by directly importing these scripts into Partytown and disabling them one at a time to isolate the one causing errors. Once you know which one is making troubles, you can try to fix it yourself or create a new Partytown issue.
@geekysaurabh001 are you talking about Partytown in general or the GTM plugin specifically? I've had Partytown and the GTM plugin running smoothly on a production NextJS app for over a year. The recently added README for @superside-oss/partytown-gtm includes setup instructions now. However it has always featured an example NextJS app. This is open source, if you feel that something is missing, feel free to contribute via pull request. 😄
Yes @slawekkolodziej I am trying that but failing miserably 😂 I'll contribute my solution once I figure it out. I was talking about PartyTown in general though. I am on NextJS 12 and I am unable to figure out an approach that would work.
I am basically stuck at that party. In the GTM preview mode, I also cannot connect.
What steps did you follow to setup partytown with nextjs, if you can let me know, it will be helpful 🙏
Oh, I see, so you're using NextJS built-in Script component with strategy="worker"
. I never tried that really. I added Partytown directly to my app. Regarding CORS errors - most likely third party services you're trying to use do not set proper CORS headers and for that reason have to be proxied (you can learn more about this in Partytown docs: https://partytown.builder.io/proxying-requests)
Yes @slawekkolodziej I am trying to understand how to setup proxy in nextjs for this but cannot figure it out till now.
There's an example proxy endpoint in the GTM plugin NextJS integration: https://github.com/superside-oss/partytown-gtm-plugin/blob/alpha/packages/integration/nextjs/src/app/api/third-party/route.ts
When using Google Tag Assistant to test a Proxytown implementation of Google Tag Manager, it fails to connect: At first there were some CORS errors for the googletagmanager.com domain. After proxying those I can see the iframe getting added to the page, but it fails to load and some Partytown error occurs:
In the page's
<head>
I can see the following scripts:And just before the
</body>
:When switching back to the default GTM implementation (without Partytown), everything works as expected.