惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

有赞技术团队
有赞技术团队
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
aimingoo的专栏
aimingoo的专栏
IT之家
IT之家
G
Google Developers Blog
爱范儿
爱范儿
博客园 - 司徒正美
Recent Announcements
Recent Announcements
The Register - Security
The Register - Security
J
Java Code Geeks
The Cloudflare Blog
M
MIT News - Artificial intelligence
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Security Blog
Microsoft Security Blog
博客园 - Franky
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
Blog — PlanetScale
Blog — PlanetScale
Vercel News
Vercel News
宝玉的分享
宝玉的分享
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
B
Blog
小众软件
小众软件
Microsoft Azure Blog
Microsoft Azure Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
T
Troy Hunt's Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
H
Hacker News: Front Page
H
Help Net Security
S
Security @ Cisco Blogs
V
V2EX
Security Archives - TechRepublic
Security Archives - TechRepublic
Stack Overflow Blog
Stack Overflow Blog
O
OpenAI News
L
LINUX DO - 最新话题
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
S
Secure Thoughts
Help Net Security
Help Net Security
F
Full Disclosure
博客园 - 叶小钗
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Jina AI
Jina AI
K
Kaspersky official blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
V
Vulnerabilities – Threatpost
P
Privacy International News Feed
Scott Helme
Scott Helme

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
UTM parameters: how to use them correctly and the 4 patterns that break GA4 channel grouping
toshihiro sh · 2026-04-27 · via DEV Community

I keep running into the same Meta-ads UTM setup at startups: utm_source=meta. Once Meta rebranded, this looks natural — except meta is not in GA4's official source list, so the campaign falls into Referral instead of Paid Social. The monthly report then shows "Paid Social dropped sharply" when really the classification just fell off.

UTMs look fire-and-forget but they aren't. The moment you put a value GA4's classification logic doesn't recognize, the channel grouping is meaningless from that point on. Below is the short version of the rules I wish I'd known earlier, plus the 4 failure patterns I keep seeing in production EC accounts.

TL;DR

  1. There are 5 UTM parameters; source / medium / campaign are required. All values lowercase, hyphen-separated
  2. 4 patterns break GA4 channel grouping: ① values not in the official list, ② case-sensitivity drift, ③ medium=social + source=facebook OR-condition collision, ④ UTM stripped through redirects / referrer policy
  3. Use Campaign URL Builder, not hand-typed URLs. Verify in DebugView and Realtime before launch
  4. UTMs identify the source, not the revenue efficiency. To compare channels, you need a session-level metric (RPS) layered on top

The 5 UTM parameters and what they actually map to

Five parameters, three of them required for any paid URL:

Parameter Required Maps to
utm_source Yes The traffic source ("Source" in GA4)
utm_medium Yes The traffic type ("Medium")
utm_campaign Yes Campaign name ("Campaign")
utm_term No Search keyword ("Keyword") — auto-populated by Google Ads
utm_content No Creative variant ID ("Ad content") — useful for A/B tests

GA4 reads the combination of utm_source and utm_medium, then matches it against Google's "Default Channel Group" rules. That's how a session gets labeled Paid Search vs Paid Social vs Referral. Get the values wrong and the entire channel report stops being meaningful for that visit.

The conceptual split that prevents most problems:

  • utm_source = where the visit came from (specific platform / site / service)
  • utm_medium = what type it is (paid / organic / email / social / etc.)

Naming rules that prevent campaign-name fragmentation

The most frequent UTM mistake isn't a technical bug — it's inconsistency between operators. A team of four Meta-ad operators can produce facebook, Facebook, fb, and meta in the same campaign. GA4 will then split that one campaign across four rows, each showing roughly a quarter of the real number, and the row labeled meta falls out of Paid Social entirely.

Three rules eliminate most of this:

  1. Always lowercase. GA4 stores utm_source case-sensitively. Facebook and facebook are tracked as separate sources
  2. Hyphen-separated, never spaces. spring sale 2026 becomes spring%20sale%202026 after URL encoding, and that's exactly what GA4 displays in the campaign name field
  3. Generate URLs via Google's Campaign URL Builder, not by hand. This structurally prevents whitespace, full-width characters, and typos

The 4 patterns that break GA4 channel grouping

The 4 patterns that break GA4 channel grouping — example UTM input vs what GA4 actually shows

When UTMs are set but the GA4 channel report doesn't show traffic in the intended channel, the cause almost always falls into one of these 4 patterns.

Pattern 1: utm_source value not in GA4's official source list

GA4 channel classification matches utm_source values against Google's "Default Channel Group Source Categories" list, which contains roughly 820 source names as of April 2026. facebook maps to SOURCE_CATEGORY_SOCIAL, google to SOURCE_CATEGORY_SEARCH, youtube to SOURCE_CATEGORY_VIDEO, and so on.

Use a value not in the list (the classic example: utm_source=meta) and the traffic ends up in Referral or (other). Lock major sources to: google / yahoo / bing / facebook / instagram / twitter / line / youtube / tiktok. If you must use something outside the list, define a custom channel group in GA4 instead.

Pattern 2: case sensitivity and operator-driven naming drift

Even when everyone uses values from the list, mixing facebook / Facebook / fb in the same campaign splits it across multiple rows. Document the naming convention once, store it where every operator references it, and make Campaign URL Builder the only sanctioned URL-generation flow. Two-step approval before going live catches the rest.

Pattern 3: medium/source combination collides with GA4's regex

Less obvious. GA4's Paid Social requires both utm_source matching the social-source list AND utm_medium matching ^(.*cp.*|ppc|retargeting|paid.*)$. But Organic Social is defined with an OR condition: utm_medium matches social / social-network / social-media / sm OR utm_source matches the social list.

This means utm_source=facebook + utm_medium=social — a seemingly natural combination — gets classified as Organic Social purely on the medium match. Paid revenue ends up labeled organic, the Paid Social report goes empty, and ad ROAS is understated. Fix: lock utm_medium=cpc for paid social channels (Meta, X, LINE), and reserve utm_medium=social exclusively for organic posts.

Pattern 4: UTM lost through redirects, referrer policy, etc.

The UTM is set correctly at launch but gets stripped before the user lands on the LP. Common causes:

  • Some URL shorteners drop query strings on redirect
  • HTTPS → HTTP redirects strip the referrer (and the UTM with it)
  • <meta name="referrer" content="no-referrer"> on the LP makes referrer-based source detection impossible
  • In-app browsers (LINE, Facebook) drop referrer / UTM depending on implementation

When the UTM is gone, what was originally a paid visit ends up classified as Direct / (none) or (not set). If your Direct rate is over 30% of traffic, you almost certainly have 10–20% paid CV hidden in there.

Pre-launch checklist (this is the part most teams skip)

A bug caught after launch means losing that period's data permanently. Routinizing pre-launch verification is the single best investment in long-term report quality:

  • [ ] All three of utm_source, utm_medium, utm_campaign are set
  • [ ] All values are lowercase, hyphen-separated, no spaces
  • [ ] utm_source is in GA4's official source list, or a custom channel group covers it
  • [ ] utm_medium resolves to the intended channel under GA4's classification logic
  • [ ] URL generated via Campaign URL Builder, not hand-typed
  • [ ] DebugView confirms source / medium / campaign values
  • [ ] Realtime confirms classification into the intended channel
  • [ ] For shortener-mediated URLs, the UTM survives to the final LP

What UTMs cannot show

UTMs identify "what this visit came from." They are not a measure of revenue efficiency. None of these questions can be answered by UTMs alone:

  • Which produces higher revenue per session — Paid Social or Organic Search?
  • How many times higher is email-sourced CV rate vs. paid-search-sourced?
  • If the same budget was redirected to blog SEO, how would long-term revenue efficiency shift?

To answer them, you need a layer above UTMs that compares revenue per channel — sessions × CV rate × AOV decomposed per channel. I've started calling this RPS (Revenue Per Session) in my own work, and it's the second axis I always wanted next to ROAS but never had cleanly in GA4. ROAS for ad-platform efficiency, RPS for whole-site efficiency. Two axes, much more confident budget decisions.

UTM hygiene is the prerequisite for computing this correctly. Broken UTMs distort channel classification, which corrupts both the denominator (sessions) and the numerator (revenue). The naming rules and 4 failure patterns above have to be in place first — only then does channel-level revenue efficiency become measurable.

What I'd love to hear in the comments: what's the most surprising UTM-related incident you've had to fix? My own version of this story was a Paid Social report that "dropped" 60% in a month — turned out one operator had switched to utm_source=meta.