Event forwarding
Forward events to Google Ads, Google Analytics, Meta CAPI and PostHog with first-party proxying and consent gating.
Forward the same events you capture with vTilt to Google Ads, Google Analytics 4, Meta and PostHog. Google destinations run through a first-party proxy on your vTilt domain so ad blockers don't break measurement; Meta and PostHog are server-to-server. Credentials are stored encrypted and every destination is gated by a consent category.
#Where to configure
In the dashboard, open Project Settings → Event destinations. Add a destination, paste credentials, assign a consent category, and enable forwarding. You can filter events and remap event names or parameters per platform.
#Proxy model
Tags that execute in the browser (Google Tag today; Meta and TikTok pixels in the future) can route through your vTilt api_host instead of hitting the vendor directly. That one switch solves three problems at once: ad blockers stop matching the vendor hostname, first-party cookies (gclid, _ga, _fbp) work cross-subdomain, and client IP / User-Agent are forwarded upstream.
| Mode | Behaviour |
|---|---|
| Proxied (default) | Loader and measurement traffic flow through https://{api_host}/<prefix>/*. For Google Tag the prefix is /gt; future destinations will reserve their own (/fb, /tt, …) under the same api_host. |
| Direct | Bypass the proxy; gtag.js loads straight from www.googletagmanager.com. Useful when you want a vanilla Google install for comparison. |
#Self-hosting the proxy
vTilt ships a reference gateway on managed hosts. To run the proxy on your own infrastructure (for compliance, CDN colocation, or to reuse an existing sGTM / Cloudflare Worker deployment), set the SDK's api_host to your proxy's origin and implement the routes below. Keep the destination's proxy mode on Proxied — the mode describes intent ("proxy this"), not who runs the proxy.
# Google Tag Gateway spec (prefix: /gt)
GET /gt/gtag/js?id=... -> https://www.googletagmanager.com/gtag/js?id=...
GET /gt/gtag/destination?... -> https://www.googletagmanager.com/gtag/destination?...
GET /gt/gtag/event/... -> https://www.googletagmanager.com/gtag/event/...
POST /gt/g/collect[/...] -> https://www.google-analytics.com/g/collect[/...]
POST /gt/pagead/conversion/... -> https://www.googleadservices.com/pagead/conversion/...
GET /gt/sw_iframe.html | sw.html -> 200 empty (service-worker stubs)The proxy must rewrite Google hostnames inside the gtag.js body to point back at your domain, forward the real client IP via X-Forwarded-For, and strip any vTilt cookies from the upstream request. A complete reference implementation lives at app/app/gt/[...path]/route.ts in the vTilt source repository; it ports cleanly to Cloudflare Workers, sGTM custom templates, or any Node/Express server.
#Destinations
#Google Tag (Ads + Analytics)
Unified destination for Google Ads and Google Analytics 4. One gtag.js load covers AW-* and G-* IDs; proxied through your api_host by default.
In Event destinations you can add Google Analytics (gtag) and/or Google Ads (gtag) as separate rows for clarity; the browser SDK still loads one gtag.js and merges both. Add any mix of Ads (AW-XXXXXXXXX) and Analytics (G-XXXXXXXXX) tag IDs — vTilt configures each one automatically. Traffic is routed through /gt on your api_host by default ("Proxied" mode), so ad-blocker lists targeting www.google-analytics.com and www.googleadservices.com don't break collection.
Forwarding waits until remote configuration from /api/d has committed (__remote_config_loaded), matching HTTP ingest behaviour. Only that pre-commit window uses an SDK-side FIFO (capped at 100 events); after the gtag shim exists, Google's dataLayer queues calls until gtag.js loads.
| Credential | Detail |
|---|---|
| Tag IDs (required) | Comma-separated list. Google Ads: Google Ads UI → Tools → Data manager → Google tag. Google Analytics: Admin → Data streams → Measurement ID (G-XXXXXXXXXX). |
| Proxy mode (optional) | Proxied (default) routes gtag.js through your api_host/gt/*; Direct loads it from www.googletagmanager.com. To self-host the proxy, keep Proxied and point api_host at your own domain. |
| Ads conversion mappings (optional) | Pick a vTilt event (e.g. purchase) and a send_to value (AW-XXXXXXXXX/abcDEFghIJ). Matching captures automatically fire gtag("event", "conversion", …) with value, currency, and transaction_id pulled from the event payload. |
| Enhanced Conversions (optional) | The SDK normalises and SHA-256-hashes email, phone, name, and address in the browser before pushing gtag("set", "user_data", …). No raw PII leaves the device. |
| Conversion Linker and cross-domain (optional) | Enable conversion_linker and list auto-linker domains so _gcl_* first-party cookies are written and shared across your apex/subdomains. |
| Consent Mode v2 overrides (optional) | By default vTilt maps its three consent categories (analytics, marketing, advertising) to Google's four keys (ad_storage, ad_user_data, ad_personalization, analytics_storage). Override any key from the destination detail page. |
What you get out of the box:
- First-party proxy —
gtag.js,/g/collect, and/pagead/conversionare all served fromhttps://{api_host}/gt/*. - Automatic event bridge — any event you configure in the admin UI is forwarded to
gtagwithout writing code. - Manual escape hatch — call
vt.gtag(…)from anywhere; a small in-memory queue replays calls once the API is bound to the dataLayer shim. - Debug mode — flip one toggle in the destination to send
debug_mode: trueto Google's Tag Assistant and DebugView.
Official references:
- Set up conversion tracking for your website
- Enhanced conversions for the web
- Google Consent Mode v2
- gtag.js installation guide
#Meta (Facebook) Conversions API
Server-side only — no Meta Pixel required. Uses your Pixel ID and a Conversions API access token.
| Credential | Detail |
|---|---|
| Pixel ID (required) | Meta Events Manager → your data source (Pixel) → Settings. Also labelled Dataset ID in some views. |
| Access token (required) | Events Manager → Settings → Conversions API → Generate access token (or a system user token with ads_management). |
| Test event code (optional) | Events Manager → Test events. When set in vTilt, events go to the test panel instead of production. |
Official references:
#PostHog
Sends events to the PostHog capture API — same project key as the snippet or server SDKs.
| Credential | Detail |
|---|---|
| Project API key (required) | PostHog → Project settings → Project API Key (starts with phc_). |
| Instance host (optional) | Defaults to US cloud (https://us.i.posthog.com). EU: https://eu.i.posthog.com. Self-hosted: your instance origin. |
Official references:
#Optional: Google Analytics 4 (server)
The Google Analytics 4 (server) destination sends events to GA4 over the Measurement Protocol. It does not load gtag.js in the browser. For the usual Ads + Analytics setup, prefer Google Analytics (gtag) and/or Google Ads (gtag) so attribution and cookies stay in the client Google Tag flow.
If you enable the same G-XXXXXXXXX on both a client gtag destination and server GA4, hits can be duplicated. The dashboard surfaces warnings when that overlap is detected; resolve it by using only one path for that measurement ID unless you have a deliberate split (for example, different event subsets).
#Consent
Every destination is tied to a consent category so forwarding honours your remote configuration and the user's current consent state. Categories are analytics, marketing, and advertising. The Google Tag destination also pushes Consent Mode v2 defaults to gtag.js before the script runs and sends an update whenever the user changes consent, so Google sees the signal even when forwarding is blocked.