Overview
- GCLID capture — reads gclid from landing URL and stores it alongside utk_click_id
- Google Transparency Mode — passes clientId to Google's Consent-Mode compatible endpoint
- Server-side conversions — sends conversion events to Google Ads API from your server, not the browser
- Enhanced Conversions — hashes PII and passes to Google for improved match rates
GCLID Capture
The SDK automatically reads gclid from the landing URL and stores it as utk_gclid in a first-party cookie (30-day TTL). No extra configuration is needed.
var gclid = AffclixSDK.getAttribution().gclid;
console.log(gclid); // e.g. "Cj0KCQj..." Enable auto-tagging in Google Ads under Settings → Account Settings → Auto-tagging so gclid is appended to all ad destination URLs.
Google Transparency Mode
Transparency Mode is Google's Consent Mode v2 compatible approach for advertisers in the EEA and UK. When enabled, the SDK routes conversion events through the Transparency endpoint and includes clientId for modelled conversion support.
AffclixSDK.init({
trackingDomain: 't.yourdomain.com',
useGoogleTransparency: true,
clientId: 'AW-123456789'
}); When useGoogleTransparency is true, client_id is appended to every tracking request. Clicks and conversions still go to the standard /c and /p endpoints on your tracking domain, which handle Google Ads transparency server-side.
Send Conversion to Google Ads
Client-side (gtag)
// 1. Fire the Affclix conversion postback
AffclixSDK.trackConversion({
campaignID: 'YOUR_CAMPAIGN_ID',
eventName: 'purchase',
conversionData: {
txn_id: 'ORDER-1001',
sale: '99.00',
currency: 'USD'
}
}).then(function() {
// 2. Mirror it to Google Ads — fires gtag 'conversion' with your label
AffclixSDK.adPlatforms.google.sendConversionEvent('AW-123456789/AbCdEfGhIjKl', {
value: 99.00,
currency: 'USD',
transaction_id: 'ORDER-1001'
});
}); Server-side postback
GET https://t.yourdomain.com/p
?auth={YOUR_SECURITY_TOKEN}
&c={CAMPAIGN_ID}
&click_id={CLICK_ID}
&txn_id={ORDER_ID}
&sale=99.00
¤cy=USD
&gclid={GCLID} Enhanced Conversions
Pass hashed customer data to improve conversion matching in Google Ads. The SDK automatically SHA-256 hashes PII before sending.
// Forwarded to gtag('set', 'user_data', ...) — Google normalises and
// hashes these values before they leave the browser.
AffclixSDK.adPlatforms.google.setUserData({
email: 'customer@example.com',
phone_number: '+919876543210',
address: {
first_name: 'Arjun',
last_name: 'Sharma',
city: 'Mumbai',
postal_code: '400001',
country: 'IN'
}
});
AffclixSDK.trackConversion({
campaignID: 'YOUR_CAMPAIGN_ID',
eventName: 'purchase',
conversionData: { txn_id: 'ORDER-1001', sale: '99.00', currency: 'USD' }
}); All PII fields are normalised (lowercase, trimmed) and SHA-256 hashed by the SDK before leaving the browser. Raw PII is never sent to Affclix servers.
UTM + Google Attribution Flow
Ad Click
Google appends gclid and your UTM params to the landing URL.
SDK Captures on Landing
AffclixSDK.init() stores gclid, utm_source, utm_campaign, and utk_click_id in cookie + localStorage.
User Converts
On the thank-you page, trackConversion() reads stored attribution from the cookie/localStorage stack and includes it in the postback payload.
Affclix Credits Affiliate
Affclix matches utk_click_id to the affiliate, credits the commission, and forwards gclid to Google Ads via Offline Conversion Import.
Link Tracking & Certified Click Trackers
Everything above covers conversions. This section covers the click — what Google will and will not accept as a tracking template pointing at Affclix.
Google accepts a third-party click tracker only when every host in the redirect chain is one it certifies. A chain like Google → Affclix → partner network → advertiser fails on the middle hop even though the first two are fine, and the disapproval names the ad rather than the host.
One uncertified tracker anywhere in the chain fails the whole chain. Before you add a hop, confirm with that vendor that they are a certified Google Ads click tracker, then add their domain to config/google_ads.php → certified.vendors so the audit stops reporting it as unverified.
Build the template
The Tracking Link Generator builds a compliant template for you: pick the campaign, switch on "Google Ads tracking template", and generate. Three values come back, each labelled with the Google Ads box it belongs in.
https://acme.affclix.com/c?c=101&a=55&url={lpurl}&gclid={gclid}&gbraid={gbraid}&wbraid={wbraid} | Value | Where it goes in Google Ads |
|---|---|
Tracking template | Settings → Campaign URL options → Tracking template |
Final URL suffix | Settings → Campaign URL options → Final URL suffix |
Final URL | The ad itself → Final URL |
%7Blpurl%7D is not a macro. Google substitutes only literal braces, so an encoded template sends that exact text to the tracker. The tracker cannot read a landing page out of it and falls back to the campaign URL — the click is recorded, but it lands somewhere other than the final URL the ad declares, and Google disapproves the ad for a destination mismatch. Paste the template exactly as generated.
Redirect Transparency
When the click passes through anything beyond Affclix, each hop consumes the landing URL instead of forwarding it. Google then loses sight of the destination and disapproves the ad for a destination mismatch — even though the page loads perfectly when you click it yourself.
The transparency flag tells every step of the chain to keep the original {lpurl} visible:
https://acme.affclix.com/c?c=101&a=55&url={lpurl}&gclid={gclid}&force_transparent=true With the flag on, the click is redirected in the browser rather than handled server-side, whatever the campaign's server-to-server configuration says. Conversions that depend on the S2S path stop lining up — and you find out from a reporting gap a week later, not from an error. Tell the generator the campaign uses S2S and the audit will say so up front.
Add the flag only when the click really does redirect onward. On a direct Affclix-to-advertiser link it does nothing.
Destination Matching
Google compares the URL the user actually reaches against the final URL the ad declares. Three rules decide whether they match.
| Rule | What breaks it |
|---|---|
| The landing URL sits in the destination parameter | {lpurl} placed anywhere other than after &url= — the tracker reads the destination from that parameter and nowhere else, so the click has no landing page even though the macro is present. The tracker also honours url= only when the click carries a real Google click ID (gclid, gbraid, wbraid or dclid) or force_transparent=true; with auto-tagging off, and the campaign's deep link setting off, the click goes to the campaign URL instead. |
| Same registrable domain as the display URL | A final URL on a different domain from the one the ad displays. Google matches the registrable domain, so shop.example.com is fine when the display URL is example.com — what breaks it is a display URL naming another domain entirely, or a cross-domain redirect in the chain. |
| Identical parameters on both URLs | A parameter present on only one side, or the same parameter carrying different values. Google counts either as a mismatch, even though the two URLs read as equivalent to a human. |
gclid, gbraid, wbraid, dclid and the utm_* parameters are appended by Google itself, so they are allowed to appear on the final URL without also being on the tracking URL. Everything else is compared.
Parallel Tracking & GCLID Capture
Parallel tracking is mandatory on Google Ads. Instead of redirecting the user through the tracker, Google sends the browser straight to the landing page and fires the tracking URL as a background beacon.
Click
Google opens the final URL in the browser and fetches the tracking template in the background, carrying gclid and your parameters.
Beacon
Nothing renders that response — no browser is watching it. The tracking path must answer with a 302 (/c, /cb, /sl); an interstitial or a JavaScript bounce page is never executed, so the chain stops at the tracker.
Capture on arrival
The gclid reaches the landing page, not the tracker. Capture it on the user's first arrival — the WebSDK stores it as utk_gclid in a first-party cookie for 30 days.
Replay on conversion
On the thank-you page, read the stored gclid back and send it with the conversion so Google can match it to the click that produced it.
A landing URL carrying gclid but no utm_source is attributed to organic traffic by analytics, click id and all, and the conversion is credited to the wrong channel. Set a final URL suffix of utm_source=google&utm_medium=cpc.
On iOS, Google sends gbraid or wbraid instead of gclid. A template that captures only gclid loses iOS attribution completely rather than partially — the clicks arrive with an empty click-id column.
How the Tracker Handles Google Clicks
A click counts as a Google Ads click when it arrives with a real gclid, gbraid, wbraid or dclid, or with force_transparent=true. Ordinary affiliate traffic has none of these and is handled exactly as before.
| Situation | What the tracker does |
|---|---|
| Google's destination checker (AdsBot-Google) requests the template | Answered with the same 302 a person would get — to the url= destination when present, otherwise to the campaign URL. Nothing is recorded: no click row, no capping, no payout. Other bots on the click path, including Googlebot, are still blocked. |
| The template carries url={lpurl} | The click lands on that final URL, whatever the campaign's deep link setting says, and even when the campaign rotates landing pages. Only http and https destinations are followed. |
| Google sends the literal {gclid} | This means auto-tagging is off. The unsubstituted macro is dropped rather than stored, so the click is recorded with an empty gclid instead of one ID shared by every click on the account. |
| The click is sent on to the landing page | gclid, gbraid, wbraid and dclid are added to the outgoing URL when it does not already carry them, so the landing page can capture them even under sequential tracking. |
| force_transparent=true is set | The click is always a plain 302, even when the campaign is set to a referrer-hiding redirect mode that answers with an HTML page. When the next hop is another Affclix tracking link, the flag, the destination and the click IDs are passed on to it; they are never added to an advertiser's offer URL. |
| The click is rejected (cap reached, targeting, fraud rules) | A Google Ads click is still redirected to the declared destination instead of receiving an error, because Google treats an error at the end of a template as a broken destination and disapproves the ad. The click is still recorded as REJECTED, capping does not move and the affiliate earns nothing. |
Each behaviour can be switched off with a GOOGLE_ADS_* environment variable on the tracker (for example GOOGLE_ADS_REDIRECT_REJECTED=false), and GOOGLE_ADS_ENABLED=false turns all of them off. Parameter names such as url and force_transparent must match on the tracker and the dashboard, or templates built in the dashboard stop being recognised.
Operational Guidance
Before you spend
- Auto-tagging is on — Settings → Account Settings → Auto-tagging. Without it Google appends no gclid at all and every {gclid} in every template resolves to nothing.
- The generated audit shows no blocking issues.
- One live test click has run, and the gclid is visible in the landing page URL and stored in the cookie.
- One test conversion has been sent and appears in both Affclix and Google Ads.
Audit what is actually configured
A template built correctly here and then pasted into the wrong Google Ads box — or edited later by whoever runs the ads — is the ordinary way this breaks, and nothing on the Affclix side can see it. With a connected Google Ads integration, read the live account instead:
# Audit every tracking template on a connected account
php artisan google-ads:audit-tracking --integration=12 --final-url=https://example.com/offer
# Pre-flight a tracking URL without calling Google
php artisan google-ads:audit-tracking \
--url="https://acme.affclix.com/c?c=101&a=55" \
--final-url="https://example.com/offer" \
--chain="partner-network.com" --s2s For a connected account the audit reads the account-level tracking template, final URL suffix and auto-tagging setting, then every campaign that is not removed:
- A campaign with no template of its own is audited against the account-level template it inherits, and is labelled as inheriting it.
- A campaign with no template anywhere is listed but not audited — its clicks go straight to the final URL, which is a valid setup.
- Auto-tagging switched off is reported once for the whole account, not repeated as a missing gclid on every campaign.
- Add --json for machine-readable output.
Templates set on an ad group, ad, keyword or sitelink override the campaign template and are not read yet. If you use them, check those levels in Google Ads by hand.
The command exits non-zero when anything blocking is found — including auto-tagging switched off — so it can gate a deploy.
When something is wrong
| Symptom | Usual cause |
|---|---|
| "Destination not working" / "Destination mismatch" | A redirect chain with no transparency flag, a landing page on a different registrable domain from the display URL, or a parameter on the final URL that the tracking URL does not carry. |
| Ad serves, clicks recorded, no conversions | gclid never captured on the landing page, or the cookie expired before the user converted. |
| Clicks recorded, gclid column empty | Auto-tagging is off, so Google sent the literal {gclid} and the tracker dropped it. Turn auto-tagging on. |
| Literal {click_id}-style tokens in a report column | An Affclix token used in a Google template. Google forwards it untouched, so the literal braces land in the report — use the ValueTrack equivalent. |
| Traffic reported as organic | No utm_source on the landing URL. Set the final URL suffix. |
| iOS clicks have no click ID | gbraid and wbraid are not in the template. |
| Nothing recorded at all, ad serving normally | The template was pasted into the wrong Google Ads box, or points at something other than an Affclix tracking path (/c, /cb, /sl). Run the account audit above to see what is actually configured. |
| Clicks recorded, but "Destination mismatch" and traffic landing on the campaign URL | An encoded macro (%7Blpurl%7D), so the tracker never saw a destination. |