<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: toshihiro shishido</title>
    <description>The latest articles on DEV Community by toshihiro shishido (@toshihiro_shishido).</description>
    <link>https://dev.to/toshihiro_shishido</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3893127%2Fe1844984-b7c4-4c47-a3b6-e54b89e78001.png</url>
      <title>DEV Community: toshihiro shishido</title>
      <link>https://dev.to/toshihiro_shishido</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/toshihiro_shishido"/>
    <language>en</language>
    <item>
      <title>The utm_source you should NOT use for Meta Ads (and why GA4 makes it disappear)</title>
      <dc:creator>toshihiro shishido</dc:creator>
      <pubDate>Wed, 22 Apr 2026 22:14:17 +0000</pubDate>
      <link>https://dev.to/toshihiro_shishido/the-utmsource-you-should-not-use-for-meta-ads-and-why-ga4-makes-it-disappear-19a3</link>
      <guid>https://dev.to/toshihiro_shishido/the-utmsource-you-should-not-use-for-meta-ads-and-why-ga4-makes-it-disappear-19a3</guid>
      <description>&lt;p&gt;A lot of marketers — myself included, at first — tag their Meta (Facebook / Instagram) ad URLs with &lt;code&gt;utm_source=meta&lt;/code&gt;. It feels natural: the company is called Meta now, right?&lt;/p&gt;

&lt;p&gt;But if you open Google's officially distributed &lt;strong&gt;GA4 Default Channel Group Source Categories&lt;/strong&gt; spreadsheet and search through all 819 entries, you'll find something strange:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;facebook&lt;/code&gt; is there&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fb&lt;/code&gt; is there&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;facebook.com&lt;/code&gt; is there&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;instagram&lt;/code&gt; is there&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;meta&lt;/code&gt; is not&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That one missing line isn't a trivia item. It's the difference between Meta ad revenue showing up in your &lt;strong&gt;Paid Social&lt;/strong&gt; channel versus quietly falling into &lt;strong&gt;Referral&lt;/strong&gt; or &lt;strong&gt;(other)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This post is a practical, receipts-first walkthrough of what GA4 actually checks, why &lt;code&gt;meta&lt;/code&gt; breaks classification, and the URL format I'd recommend fixing on going forward. No opinion — just the file Google itself publishes.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;utm_source=facebook&lt;/code&gt; (lowercase, fixed). Not &lt;code&gt;meta&lt;/code&gt;, not &lt;code&gt;Facebook&lt;/code&gt;, not &lt;code&gt;fb&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;utm_medium=cpc&lt;/code&gt;. GA4's Paid Social regex matches on &lt;code&gt;.*cp.*|ppc|retargeting|paid.*&lt;/code&gt;. &lt;code&gt;cpc&lt;/code&gt; is the safest pick.&lt;/li&gt;
&lt;li&gt;The 80% of bad-data incidents I see are &lt;em&gt;casing and variant drift&lt;/em&gt;: &lt;code&gt;facebook&lt;/code&gt; / &lt;code&gt;Facebook&lt;/code&gt; / &lt;code&gt;fb&lt;/code&gt; / &lt;code&gt;meta&lt;/code&gt; splitting one campaign across four rows.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. What GA4 actually checks when deciding "Paid Social"
&lt;/h2&gt;

&lt;p&gt;Per Google's public documentation on default channel groups[1], the &lt;strong&gt;Paid Social&lt;/strong&gt; classification requires &lt;strong&gt;both&lt;/strong&gt; of these to be true (for manual UTM tagging):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source&lt;/strong&gt; matches a regex list of social sites&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Medium&lt;/strong&gt; matches the regex &lt;code&gt;^(.*cp.*|ppc|retargeting|paid.*)$&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That "regex list of social sites" isn't a mystery. Google actually publishes it as a downloadable spreadsheet[2]. It's an 819-row file mapping source strings to categories like &lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt;, &lt;code&gt;SOURCE_CATEGORY_SEARCH&lt;/code&gt;, and so on.&lt;/p&gt;

&lt;p&gt;Here's what it contains for the major Meta-related entries:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;utm_source value&lt;/th&gt;
&lt;th&gt;Official classification&lt;/th&gt;
&lt;th&gt;Counts as Paid Social?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;facebook&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;facebook.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;m.facebook.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;instagram&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;instagram.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;l.instagram.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;twitter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;meta&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not in the file&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;❌ No&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;Meta&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not in the file&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;❌ No&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;meta&lt;/code&gt; as a string does not appear anywhere in Google's classification file. Traffic tagged &lt;code&gt;utm_source=meta&lt;/code&gt; is evaluated against the social list, misses every entry, and falls through to &lt;strong&gt;Referral&lt;/strong&gt; or &lt;strong&gt;(other)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;"But the company rebranded to Meta" — true, and completely irrelevant to the classification engine. Google Analytics did not update its source file when the corporate rebrand happened. The file still references the long-standing industry-standard string &lt;code&gt;facebook&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Brand names and classification tokens are independent layers. Confusing them costs money.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Four failure modes I keep seeing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Failure 1: &lt;code&gt;utm_source=meta&lt;/code&gt; silently erases Paid Social
&lt;/h3&gt;

&lt;p&gt;Since &lt;code&gt;meta&lt;/code&gt; doesn't match the social list, these sessions land in Referral with source/medium &lt;code&gt;meta / cpc&lt;/code&gt;. From the monthly report you'll see "Paid Social revenue dropped." Nothing dropped. The classification box moved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failure 2: Case sensitivity splits one campaign into two rows
&lt;/h3&gt;

&lt;p&gt;GA4 stores &lt;code&gt;utm_source&lt;/code&gt; values case-sensitively. &lt;code&gt;facebook&lt;/code&gt; and &lt;code&gt;Facebook&lt;/code&gt; are two distinct dimension values and two distinct rows in your report. One campaign, two boxes, each showing half the revenue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failure 3: &lt;code&gt;utm_medium=social&lt;/code&gt; promotes paid traffic to Organic Social
&lt;/h3&gt;

&lt;p&gt;GA4's Organic Social rule[1] is: &lt;strong&gt;Source matches social list OR Medium is one of &lt;code&gt;social | social-network | social-media | sm&lt;/code&gt;&lt;/strong&gt;. That's an &lt;strong&gt;OR&lt;/strong&gt;. If you use &lt;code&gt;utm_source=facebook&lt;/code&gt; with &lt;code&gt;utm_medium=social&lt;/code&gt;, the medium matches Organic Social before the logic ever reaches "but wait, this is paid." Your paid budget gets counted as organic, and ROAS looks worse than reality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failure 4: Dynamic parameter macros confirmed late
&lt;/h3&gt;

&lt;p&gt;Meta's own [URL Dynamic Parameter feature][3] lets you embed macros like &lt;code&gt;{{campaign.name}}&lt;/code&gt; / &lt;code&gt;{{adset.name}}&lt;/code&gt; / &lt;code&gt;{{ad.name}}&lt;/code&gt; in destination URLs, resolved at delivery time. Useful, but: &lt;strong&gt;at insertion time the preview still shows the raw macros&lt;/strong&gt;, so skipping the post-launch GA4 check means you only discover empty &lt;code&gt;utm_campaign&lt;/code&gt; values or unexpected characters (spaces, Japanese text, uppercase) once real money has shipped.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The URL format I'd fix on
&lt;/h2&gt;

&lt;p&gt;Given the constraints above, this is what I tag Meta ads with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;utm_source&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;facebook&lt;/span&gt;
&lt;span class="py"&gt;utm_medium&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;cpc&lt;/span&gt;
&lt;span class="py"&gt;utm_campaign&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;{{campaign.name}}&lt;/span&gt;
&lt;span class="py"&gt;utm_content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;{{ad.name}}&lt;/span&gt;
&lt;span class="py"&gt;utm_term&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;{{adset.name}}&lt;/span&gt;
&lt;span class="py"&gt;utm_id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;{{campaign.id}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why each value
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;utm_source=facebook&lt;/code&gt;&lt;/strong&gt; — matches &lt;code&gt;SOURCE_CATEGORY_SOCIAL&lt;/code&gt; in GA4's file, lowercase for casing stability, the industry-canonical value. &lt;code&gt;fb&lt;/code&gt; works too (same category), but pick one and stop the drift&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;utm_medium=cpc&lt;/code&gt;&lt;/strong&gt; — matches Paid Social's regex, does not collide with Organic Social's &lt;code&gt;social*&lt;/code&gt; list. Safest minimum overlap&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;utm_campaign={{campaign.name}}&lt;/code&gt;&lt;/strong&gt; — delivered-time substitution; verify values populate correctly once campaigns are live&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;utm_content={{ad.name}}&lt;/code&gt; / &lt;code&gt;utm_term={{adset.name}}&lt;/code&gt;&lt;/strong&gt; — gives you ad-level and ad-set-level drill-down inside GA4's campaign dimension, without needing custom dimensions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "What about Instagram-only?"
&lt;/h3&gt;

&lt;p&gt;If you want Instagram campaigns to appear as their own row, switch &lt;code&gt;utm_source&lt;/code&gt; from &lt;code&gt;facebook&lt;/code&gt; to &lt;code&gt;instagram&lt;/code&gt;. This is a reporting trade-off: you gain Instagram visibility, you lose the "all Meta ad revenue in one row" view. The cleaner pattern: keep &lt;code&gt;utm_source=facebook&lt;/code&gt; (platform-level) and put placement detail in a separate &lt;code&gt;placement={{placement}}&lt;/code&gt; custom-dimension — your Meta vs Instagram split survives even when campaign naming changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Verifying after you ship
&lt;/h2&gt;

&lt;p&gt;Two checks that catch 90% of breakage:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pre-launch URL preview&lt;/strong&gt; — in Meta Ads Manager, check the URL preview panel on the ad edit screen. Confirm macros resolve to expected values and no unexpected whitespace / CJK / uppercase slipped in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-launch GA4 realtime&lt;/strong&gt; — within 30 minutes of first impression, check &lt;strong&gt;Realtime → Traffic source&lt;/strong&gt; (or classic Acquisition). You should see &lt;code&gt;facebook / cpc&lt;/code&gt;. If you see &lt;code&gt;meta / cpc&lt;/code&gt; or &lt;code&gt;(direct) / (none)&lt;/code&gt;, the URL didn't deliver what you expected&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Skipping these two is the single biggest reason "our attribution looks weird this month" reports exist.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. One-time cleanup check (10 minutes)
&lt;/h2&gt;

&lt;p&gt;If you inherited a GA4 property and don't know what's been tagged, this is a fast audit:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GA4 → Reports → Acquisition → Traffic acquisition&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Switch dimension to &lt;strong&gt;Session source / medium&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;facebook&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you see multiple rows among &lt;code&gt;facebook&lt;/code&gt; / &lt;code&gt;Facebook&lt;/code&gt; / &lt;code&gt;fb&lt;/code&gt; / &lt;code&gt;meta&lt;/code&gt; — your campaigns are fragmented&lt;/li&gt;
&lt;li&gt;Standardize going forward, and (if your stack allows) normalize historical data downstream&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If &lt;code&gt;meta / cpc&lt;/code&gt; exists as an independent row with meaningful volume, your Paid Social number is currently understated by exactly that amount.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;The "correct" &lt;code&gt;utm_source&lt;/code&gt; for Meta ads isn't a matter of opinion, agency convention, or vendor recommendation. It's whatever Google's classification file says it is — and Google publishes that file.&lt;/p&gt;

&lt;p&gt;Opening an 819-row spreadsheet and searching for &lt;code&gt;meta&lt;/code&gt; is maybe three minutes of work. It's strange how often the answer to a recurring "which is right?" argument is sitting in a publicly downloadable CSV.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm building &lt;a href="https://www.revenuescope.jp/" rel="noopener noreferrer"&gt;RevenueScope&lt;/a&gt;, a revenue-first analytics layer that sits next to GA4 and normalizes UTM drift (e.g. auto-merges &lt;code&gt;facebook&lt;/code&gt; / &lt;code&gt;Facebook&lt;/code&gt; / &lt;code&gt;fb&lt;/code&gt; / &lt;code&gt;meta&lt;/code&gt; into one Paid Social row) so you can read channel-level revenue, AOV, and RPS from a single dashboard.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post originally appeared in Japanese on the &lt;a href="https://www.revenuescope.jp/news/meta-ads-utm-source-guide" rel="noopener noreferrer"&gt;RevenueScope blog&lt;/a&gt;. Canonical source link is set accordingly.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Google Analytics Help — &lt;a href="https://support.google.com/analytics/answer/9756891" rel="noopener noreferrer"&gt;Default channel group&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Google — GA4 Default Channel Group Source Categories (official downloadable spreadsheet, linked from [1])&lt;/li&gt;
&lt;li&gt;Meta Business Help Center — URL Dynamic Parameters specification&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>marketing</category>
      <category>webdev</category>
      <category>analytics</category>
    </item>
  </channel>
</rss>
