diff --git a/.github/workflows/main-build-and-deploy.yml b/.github/workflows/main-build-and-deploy.yml index d54a70cffd..cf73dfdb2c 100644 --- a/.github/workflows/main-build-and-deploy.yml +++ b/.github/workflows/main-build-and-deploy.yml @@ -103,7 +103,7 @@ jobs: uses: ./.github/workflows/template-ui-tests.yml with: deploy_url: ${{ needs.deploy-staging.outputs.url }} - tests_to_run: "images seo-noindex" # staging slot should not be indexed + tests_to_run: "images seo-noindex gtm-tracking" # staging slot should not be indexed swap-staging: name: Swap staging with production diff --git a/.github/workflows/pr-deploy-command.yml b/.github/workflows/pr-deploy-command.yml index 4ef70ee25e..2d66a9cd5f 100644 --- a/.github/workflows/pr-deploy-command.yml +++ b/.github/workflows/pr-deploy-command.yml @@ -205,7 +205,7 @@ jobs: uses: ./.github/workflows/template-ui-tests.yml with: deploy_url: ${{ needs.pr-deploy.outputs.url }} - tests_to_run: "images seo-noindex" + tests_to_run: "images seo-noindex gtm-tracking" prLighthouseInsights: name: Run PR Lighthouse Insights diff --git a/app/components/google-tag-manager.tsx b/app/components/google-tag-manager.tsx new file mode 100644 index 0000000000..2752f1bab0 --- /dev/null +++ b/app/components/google-tag-manager.tsx @@ -0,0 +1,33 @@ +import Script from "next/script"; + +/** + * GTM split out of @next/third-parties' , which only exposes an + * afterInteractive load. The dataLayer is created and `gtm.start` pushed eagerly, so early + * `sendGTMEvent` / `dataLayer.push` calls (e.g. the eventbrite_order_complete conversion) queue + * and flush once GTM arrives — but gtm.js itself loads on idle (lazyOnload) instead of during + * hydration, keeping the container's marketing tags (GA4/Ads/FB/Hotjar) out of the critical window. + * sendGTMEvent from @next/third-parties keeps working: it pushes to window.dataLayer directly and + * doesn't depend on this component rendering. + * Retiming the individual tag triggers is GTM container config, not code — see #4908. + */ +export const GoogleTagManager = ({ gtmId }: { gtmId?: string }) => { + if (!gtmId) return null; + return ( + <> +