Google Publisher Tags (GPT) Integration
Category: Ad Serving Status: Production Type: First-Party Ad Tag Delivery
Overview
The GPT integration enables first-party delivery of Google Publisher Tags by proxying GPT's entire script cascade through the publisher's domain. This eliminates third-party script loads, improving performance and reducing exposure to ad blockers and browser privacy restrictions.
What is GPT?
Google Publisher Tags (GPT) is the JavaScript library publishers use to define and render ad slots served by Google Ad Manager. GPT loads scripts in a cascade:
gpt.js-- the thin bootstrap loaderpubads_impl.js-- the main GPT implementation (~640 KB)pubads_impl_*.js-- lazy-loaded sub-modules (page-level ads, side rails, etc.)- Auxiliary scripts -- viewability, monitoring, error reporting
All of these are served from securepubads.g.doubleclick.net.
How It Works
Publisher HTML
│
├─ <script src="securepubads.g.doubleclick.net/tag/js/gpt.js">
│ ↓ (attribute rewriter)
│ <script src="publisher.com/integrations/gpt/script">
│
├─ Server fetches gpt.js from Google, serves it verbatim
│
├─ Client-side shim intercepts dynamic script insertions
│ ↓ (script guard)
│ securepubads.g.doubleclick.net/pagead/…
│ → publisher.com/integrations/gpt/pagead/…
│
└─ Server proxies cascade scripts from Google, serves verbatimThere are three layers:
HTML attribute rewriting (server-side) -- Rewrites
src/hrefattributes on the initialgpt.js<script>tag to the first-party endpoint/integrations/gpt/script.Script proxy (server-side) -- Fetches scripts from Google and serves them through the publisher's domain. Script bodies are served verbatim with no modification.
Client-side shim -- A script guard (
script_guard.ts) uses six interception layers --document.writeinterception,HTMLScriptElement.prototype.srcproperty descriptor,setAttributepatch,document.createElementpatch, DOM insertion patches, and aMutationObserver-- to catch GPT script URLs regardless of how they are set or inserted. Thedocument.writelayer is the most critical, as GPT's primary loading path usesdocument.writeto synchronously injectpubads_impl.jsinto the HTML parser stream. This is the sole mechanism that routes GPT's cascaded script loads back through the proxy.
Configuration
Add GPT configuration to trusted-server.toml:
[integrations.gpt]
enabled = true
script_url = "https://securepubads.g.doubleclick.net/tag/js/gpt.js"
cache_ttl_seconds = 3600
rewrite_script = trueConfiguration Options
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
enabled | boolean | No | true | Enable/disable the integration |
script_url | string | No | https://securepubads.g.doubleclick.net/tag/js/gpt.js | URL for the GPT bootstrap script |
cache_ttl_seconds | integer | No | 3600 | Cache TTL for proxied scripts (60--86400s) |
rewrite_script | boolean | No | true | Whether to rewrite GPT script URLs in HTML |
Endpoints
GET /integrations/gpt/script-- Serves the GPT bootstrap script (gpt.js)GET /integrations/gpt/pagead/*-- Proxies secondary GPT scripts and resourcesGET /integrations/gpt/tag/*-- Proxies tag-path resources
Successful proxy responses include the X-GPT-Proxy: true header for debugging.
Features
- Full cascade proxying: Every script in GPT's loading chain is served first-party
- Verbatim script delivery: No server-side script modification -- scripts are proxied as-is
- Client-side interception: DOM-level script guard catches all dynamic script insertions
- Configurable caching: Tune TTL per deployment (default 1 hour, range 60s--24h)
- HTML attribute rewriting: Automatic rewrite of
src/hrefattributes in publisher HTML - Protocol-aware: The client-side shim matches the page's protocol (HTTP for local dev, HTTPS for production)
Client-Side Shim
The GPT integration includes a TypeScript module bundled into the unified TSJS bundle. It provides two capabilities:
Script Guard
The script guard uses six interception layers to catch GPT script URLs regardless of how they are set or inserted into the DOM:
document.write/document.writeln-- GPT's primary loading mechanism. Whengpt.jsloads synchronously, it usesdocument.writeto inject<script src="...pubads_impl.js">directly into the HTML parser stream. The guard intercepts these calls and rewrites URLs whose hostname issecurepubads.g.doubleclick.netinside the HTML string before passing it to the native method.- Property descriptor on
HTMLScriptElement.prototype.src-- interceptsscript.src = urlassignments. This catches GPT's async fallback path (used whendocument.writeis unavailable, e.g. after page load or withasyncscripts). setAttributepatch onHTMLScriptElement.prototype-- catchesscript.setAttribute('src', url)calls that bypass the property setter.document.createElementpatch -- tags every newly created<script>element with a per-instancesrcdescriptor, ensuring coverage even if the prototype-level descriptor cannot be installed.- DOM insertion patches on
appendChild/insertBefore-- catches scripts and<link rel="preload">elements whosesrc/hrefis already set at insertion time. MutationObserver-- catches elements added viainnerHTML,.append(), or other DOM methods, as well as attribute mutations on existing elements.
Intercepts scripts from securepubads.g.doubleclick.net and rewrites them to the first-party proxy.
Command Queue Patch
Takes over googletag.cmd so every queued callback is wrapped before GPT executes it. This enables future hook points for:
- EC ID injection as page-level key-value targeting
- Consent gating of ad requests
- Ad-unit path rewriting for A/B testing
Use Cases
First-Party Ad Delivery
Problem: Third-party script loads from Google's domains are blocked by ad blockers and browser privacy features.
Solution: GPT integration routes all scripts through the publisher's domain, making them indistinguishable from first-party resources.
Local Development
Problem: GPT scripts fail to load or behave differently in local development environments.
Solution: The integration works with both HTTP and HTTPS schemes. When running locally with Viceroy, the client-side shim produces http:// URLs matching the dev server.
Troubleshooting
Scripts Not Loading Through Proxy
Symptoms: Network tab shows requests to securepubads.g.doubleclick.net instead of first-party domain.
Solutions:
- Verify
rewrite_scriptistruein config - Check that the TSJS bundle with the GPT shim is loaded before GPT
- Inspect console for "GPT guard: installing interception for Google ad scripts" log message
Ads Not Rendering
Symptoms: Ad slots remain empty after proxying.
Solutions:
- Check the proxy responses have
200status (look forX-GPT-Proxy: trueheader) - Verify the
script_urlconfig points to the correct GPT endpoint - Review server logs for upstream fetch failures
Implementation
- Rust: crates/trusted-server-core/src/integrations/gpt.rs
- TypeScript: crates/trusted-server-js/lib/src/integrations/gpt/
Next Steps
- Review Integrations Overview for comparison with other integrations
- Check Configuration Reference for advanced options
- Learn about First-Party Proxy architecture
- See Google Ad Manager for the planned direct GAM integration