"We tag Meta Ads with
utm_medium=social. It's a social platform, right?"
If that's been your team's convention, GA4 has been silently logging your paid clicks as organic traffic for as long as that tag has been in production. This isn't a misconfiguration or a GA4 bug — it's the result of GA4's official Paid Social regex ^(.*cp.*|ppc|retargeting|paid.*)$ OR-ing against the Organic Social rule.
This post walks through what to put into utm_medium for Meta Ads, working from the official regex GA4 actually evaluates.
TL;DR
-
Use
utm_medium=cpc— shortest match for GA4's Paid Social regex -
Never use
social— collides with Organic Social and logs paid ads as organic -
paid_socialandpaid-socialsplit your reports — pick one and lock it across the org
1. The regex GA4 actually evaluates
GA4's Default Channel Group auto-classifies each hit by utm_source + utm_medium. A session lands in Paid Social when both conditions hold:
-
utm_sourcematches GA4's "social sites list" -
utm_mediummatches^(.*cp.*|ppc|retargeting|paid.*)$
The regex chains 4 alternatives with |:
-
.*cp.*— anything containing "cp" (cpc, cpm, cpa, oCPM) -
ppc— exact match -
retargeting— exact match -
paid.*— anything starting with "paid" (paid, paid_social, paid-social)
Values that don't match: social, display, meta, paid social (with a space), blank.
2. How utm_medium breaks
Incident 1: utm_medium=social logs paid ads as organic
GA4's Organic Social rule matches utm_medium against social / social-network / social-media / sm. With utm_source=facebook + utm_medium=social, the Medium-only match wins — the session is classified as Organic Social. Money spent on Meta paid ads gets logged as organic traffic, and reported ROAS is understated.
Incident 2: paid_social / paid-social split, and meta falls into (other)
paid.* matches both paid_social and paid-social. Paid Social classification works, but GA4 stores dimension values with the original punctuation intact. Mixing both in delivery produces two separate Paid Social rows that need manual merge each month.
Separately, naming it utm_medium=meta ("because it's Meta Ads") matches none of the regex alternatives. The session fails the Paid Social condition and lands in (other), disappearing from the Paid Social report.
3. Recommended format and verification
utm_source=facebook
utm_medium=cpc
utm_campaign={{campaign.name}}
utm_content={{ad.name}}
utm_term={{adset.name}}
utm_id={{campaign.id}}
Three reasons utm_medium=cpc is the safest value:
-
Guaranteed regex match: shortest fit for
.*cp.*— near-zero typo risk - Universally readable: short for "Cost Per Click" — anyone glancing at the report instantly recognizes "paid click channel"
-
Aligned across channels: Google Ads / TikTok Ads / LinkedIn Ads all use
cpcby convention — cross-channel reports stay consistent
Here's what happens with values other than cpc:
Two checks before and after launch:
-
Pre-launch URL preview: open the URL parameter field in Meta Ads Manager's ad editor, click "URL preview", confirm
utm_medium=cpcshows up as expected -
Post-launch GA4 realtime: within 30 minutes, open GA4 → Realtime → Source/Medium and confirm
facebook / cpcis showing.facebook / socialor(direct) / (none)= parameter never reached GA4
Wrap-up
There's a long debate online about social vs paid_social vs cpc. But what GA4 actually evaluates is one regex: ^(.*cp.*|ppc|retargeting|paid.*)$. social doesn't match. cpc does. That's the entire story.
If you're seeing surprise rows in Paid Social or Default Channel Group's (other), audit the utm_medium values your delivery is producing.
Originally posted on RevenueScope (with the full reference list and GA4 docs source).


Top comments (0)