Docs · 03 of 07
UTM tagging for Google Ads and Meta
Tagging is what makes the join work. Click IDs are never stored here, so UTMs carry the attribution on their own. An untagged campaign lands as direct and its spend sits unmatched.
The convention
Three parameters do the work. Keep them boring and keep them consistent.
| Parameter | Value | Why |
|---|---|---|
utm_source | google, facebook | The platform. Lowercase, no spaces, never the account name. |
utm_medium | cpc, paid_social | How it was bought. This is what channel rules match on. |
utm_campaign | The platform’s campaign name, templated | The key the spend join is built on. Never type it by hand. |
Use the platform’s own template variables for the campaign, not a string you typed. A hand-typed campaign value stops matching the moment somebody renames the campaign, and nobody will connect the two events.
Google Ads
Set a final URL suffix at account level, so every campaign inherits it and new campaigns are tagged the day they are created. Account level is the whole point: a suffix set per campaign is a suffix somebody forgets.
Settings → Account settings → Tracking → Final URL suffix
utm_source=google&utm_medium=cpc&utm_campaign={campaignid}&utm_content={creative}&utm_term={keyword}{campaignid} resolves to the numeric campaign ID, which never changes when the campaign is renamed. That is what you want as the join key. The dashboard shows the platform’s current campaign name next to the ID, so you get a stable key and a readable label at the same time.
If you would rather read the name in the raw URL, {campaignname} works and is more fragile. Renaming then creates a new UTM value and a new row, and the history splits in two.
Auto-tagging
Leave auto-tagging on. It adds gclid, which Google Ads itself needs, and which this product deliberately does not store: the value is replaced before anything is written, while the parameter name is kept so a paid click is still classified as paid. Auto-tagging and UTMs coexist fine.
Meta
Meta has no account-level equivalent, so the setting lives at ad level under URL parameters. Set it in your ad templates so new ads inherit it, and audit it when somebody duplicates an ad set.
utm_source=facebook&utm_medium=paid_social&utm_campaign={{campaign.id}}&utm_content={{ad.id}}&utm_term={{adset.id}}Use {{campaign.id}} rather than {{campaign.name}}, for the same reason as Google: IDs survive renames.
Keep utm_source=facebook even for ads that run on Instagram. The source is the platform that sold the click and reports the spend, and splitting Meta across two sources means every report has to add them back together.
Mistakes that break the join
- Inconsistent case.
Googleandgoogleare two different sources and will sit as two rows. - A medium nothing matches.
ppc,paid,social-paidandcpc-1all end up as unclassified traffic. Pick one and put it in the template. - Tagging the display URL instead of the final URL. Google Ads will accept it and the parameters will never reach the page.
- Landing pages that strip query strings. A redirect from
/offerto/offer/that drops parameters silently deletes every UTM. Test the actual ad URL, following redirects. - Existing query parameters. If the destination already has a
?, the suffix has to append with&. Both platforms handle this, but hand-built URLs often do not.
Check it before you spend
Paste the final URL into a browser, follow the redirects, and confirm the parameters are still on the address bar at the end. Then open the site and check the session appears in Realtime with the source and medium you expect.
After the first sync, the health panel tells you what is still not matching, in both directions. It is the only place a tagging mistake shows up as a tagging mistake rather than as a slightly disappointing CPA.