feat(analytics): add the Google Ads conversion tag to the gtag loader - #7466
Merged
Conversation
Adds AW-17916292239 as a second `config` destination on the existing GA4 gtag.js loader rather than a second `gtag/js` script tag, which is Google's documented pattern for sending one page to multiple Google products. It loads on every hosted route through GLOBAL_CONSENT_SCRIPTS, so conversion attribution is not split across a partial page set. Consent is unchanged in shape: Consent Mode v2 already maps ad_storage, ad_user_data, and ad_personalization to the `marketing` category, so a visitor who accepts measurement but declines marketing gets a cookieless ping instead of conversion tracking. Also allows the googleadservices/doubleclick origins the Ads tag reaches in script-src, connect-src, and frame-src; without them the tag would load and its conversion pings would be silently blocked.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
Greptile SummaryThe PR adds a Google Ads destination to the existing consent-managed Google tag loader and extends the hosted CSP to permit the required Ads endpoints.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/sim/lib/consent/scripts.ts | Adds the Google Ads destination to the existing consent-managed gtag initialization. |
| apps/sim/lib/consent/scripts.test.ts | Verifies that GA4 and Google Ads share one gtag loader. |
| apps/sim/lib/core/security/csp.ts | Adds the required Google Ads origins and correctly gates all new permissions to hosted deployments. |
Reviews (2): Last reviewed commit: "fix(csp): gate the Google Ads frame orig..." | Re-trigger Greptile
The script-src and connect-src entries for the Ads tag were already inside the hosted-only branch, but the frame-src ones were not. The consent provider that loads the tag never mounts off hosted, so a self-hosted or dev deployment was permitting frames it can never use.
Collaborator
Author
Collaborator
Author
|
@cubic-dev-ai review this PR |
Contributor
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
This was referenced Sep 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
AW-17916292239) site-wide, so it renders on every hosted route rather than a hand-maintained page list — partial coverage breaksgclidcapture between the ad landing page and the conversion pageconfigdestination on the existing GA4 gtag.js loader instead of adding a secondgtag/jsscript. That's Google's documented pattern for sending one page to multiple Google products, and a second loader would re-run the library and collide on thegtagelement id that c15t derives from the vendor namegoogleadservices+googleads.g.doubleclick.netinscript-src,googleadservicesinconnect-src, andtd.doubleclick.net+googleadservicesinframe-src(the conversion linker writes its cookie from a hidden iframe). Without these the tag loads and its pings are silently blockedConsent behavior is unchanged in shape. The tag rides the existing consent-managed loader, where Consent Mode v2 already maps
ad_storage,ad_user_data, andad_personalizationto themarketingcategory — so someone who accepts measurement but declines marketing gets a cookieless ping, not conversion tracking. No new consent category, no unconditional script.SPA page views are unaffected:
GoogleAnalyticsPageViewTrackersends withsend_topinned to the GA4 id, so route changes don't fan out to the Ads destination.This installs the tag only. Firing a conversion on signup or demo-booked still needs a
send_to: AW-17916292239/<label>event with a label from the Ads UI.Type of Change
Testing
Tested manually.
bun run type-checkclean;bun run lint,bun run check:audits(45 audits), block-registry check, anddocs-manifest:checkall pass. Added a unit test asserting both IDs configure on the single loader and that no secondgtag/jssrc is registered — verified it fails when theconfigline is removed.Checklist