The ₹2.6 Lakh Mistake
Let me tell you about a Diwali campaign that went perfectly wrong.
A skincare D2C brand ran three Instagram campaigns during the festive season. The paid ads team tagged their links with 'IG_Diwali'. The content team used 'instagram'. The influencer agency they hired used 'social_festive' because that's what their template said.
All three campaigns ran on Instagram. Same platform. Same week. Same product line.
When the founder asked "which Instagram campaign performed best?", GA4 showed her this:
Source in GA4 | Conversions | Revenue |
|---|---|---|
IG_Diwali | 47 | ₹94,000 |
23 | ₹46,000 | |
social_festive | 61 | ₹1.22L |
Total (same platform, invisible) | 131 | ₹2.62L |
Same campaign. Same platform. Three names. Which one do you optimize?
They looked at the fragmented data and made a call. They killed what looked like the weakest performer ('instagram' with ₹46K). It was actually the strongest per-rupee campaign. They doubled down on what seemed like a moderate winner. They never saw the full ₹2.62 lakh picture because their data was speaking three different languages.
Lost revenue: ₹2.6 lakhs. Not because the campaigns failed. Because the naming broke the reporting.
What UTMs Actually Do (and How They Break)
UTM parameters are those query strings at the end of your campaign URLs. They tell GA4 where traffic came from. Simple enough.
Here's what should happen:
Parameter | What It Should Track | What It Actually Becomes |
|---|---|---|
utm_source | Platform name | 'ig', 'Insta', 'instagram', 'IG_paid', 'meta' |
utm_medium | Traffic type | 'social', 'paid', 'cpc', 'ppc', 'ad', 'Paid_Social' |
utm_campaign | Campaign name | 'diwali', 'diwali2024', 'diwali_sale', 'Festive_Nov' |
utm_term | Keyword/audience | (ignored 90% of the time) |
utm_content | Creative variant | 'v1', 'version1', 'test_a', 'creative_1', 'A' |
But brands don't have naming standards. So every person launching a campaign invents their own convention. Your marketing manager uses 'instagram'. Your ads agency uses 'IG'. Your intern writes 'Insta'. Your influencer manager copies whatever the influencer sends.
GA4 doesn't fix this for you. It treats every variation as a separate source.
Here's what breaks everything:
GA4 is case-sensitive. 'Email' and 'email' are two different channels. 'Instagram' and 'instagram' split your reporting. No, I'm not kidding.
Spaces in UTMs break URLs. utm_campaign=Diwali Sale becomes Diwali%20Sale. It works, but now you have URL-encoded garbage in your reports.
There's no undo. Once bad UTMs hit GA4, the data is fragmented forever. You can't go back and rename historical traffic sources. The mess compounds month after month.
Your data has a vocabulary problem before it has a math problem.
The System: Our Complete UTM Naming Convention
Here's the naming standard we use. Bookmark this. Screenshot it. Send it to every person who creates campaign links.
The Rules
Always lowercase. No exceptions. Ever.
Underscores between words. Matches GA4 defaults like 'paid_social'. No hyphens, no spaces.
Full platform names. Never abbreviations. 'instagram' not 'ig'. 'facebook' not 'fb'. 'google' not 'goog'.
Campaign names include timing. 'diwali24_sale' not just 'sale'. You'll thank yourself in six months when you're looking at year-over-year data.
utm_content tracks placement + creative variant. Format: placement_format_variant. Example: 'feed_video_a', 'story_static_b'.
The Cheat Sheet
This is the table you print and stick on your wall:
Channel | utm_source | utm_medium | utm_campaign example | utm_content example |
|---|---|---|---|---|
Meta Paid (Facebook) | paid_social | diwali24_sale | feed_carousel_a | |
Meta Paid (Instagram) | paid_social | diwali24_sale | story_video_b | |
Google Search | paid_search | jan25_running_shoes | kw_nike_alternative | |
Google Shopping | paid_shopping | feb25_bestsellers | pmax_topsellers | |
Google Display | display | mar25_retarget | banner_300x250_v1 | |
Email (Klaviyo) | klaviyo | abandoned_cart_flow | email_reminder_2 | |
SMS | klaviyo | sms | flash_sale_sms_mar25 | sms_v1 |
Influencer (Instagram) | influencer | mar25_sarah_collab | reel_unboxing | |
Organic Social | organic_social | jan25_ugc_contest | feed_post_v1 | |
messaging | cart_recovery_apr25 | wa_reminder_1 | ||
QR Code (Packaging) | packaging | qr_code | repeat_purchase_2025 | insert_card_v1 |
Affiliate | affiliate_partnername | affiliate | q4_referral_program | blog_banner |
Why these specific choices:
'instagram' and 'facebook' as separate sources: Even though both are Meta platforms, you want to see performance by placement. Feed vs Stories vs Reels behave completely differently. Keep them separate.
'paid_social' as medium: Matches GA4's default channel grouping. Makes cross-platform comparison easier.
Date in campaign name: 'jan25_running_shoes' beats 'running_shoes' because next January you'll run another shoe campaign. You need to distinguish them without opening the date filter every time.
'influencer' as medium: Not 'social' or 'paid'. Influencer traffic behaves differently. Track it separately so you can calculate influencer ROI accurately.
Placement + format + variant in content: 'story_video_b' tells you exactly which creative this was. You can compare Stories vs Feed. Video vs Static. Version A vs Version B. All in one parameter.
Before vs. After
Here's what bad UTMs look like next to good ones:
Bad UTM | Problem | Good UTM |
|---|---|---|
utm_source=IG&utm_medium=social&utm_campaign=Sale | Abbreviation, generic, no date, uppercase | utm_source=instagram&utm_medium=paid_social&utm_campaign=diwali24_sale&utm_content=feed_video_a |
utm_source=Google&utm_medium=CPC&utm_campaign=Shoes | Uppercase, generic campaign | utm_source=google&utm_medium=paid_search&utm_campaign=jan25_running_shoes&utm_term=kw_nike_alternative |
utm_source=meta&utm_medium=ad&utm_campaign=Test | 'meta' hides platform, 'ad' too vague | utm_source=facebook&utm_medium=paid_social&utm_campaign=feb25_retarget&utm_content=carousel_a |
utm_source=social&utm_medium=influencer (no name) | Can't attribute to specific influencer | utm_source=instagram&utm_medium=influencer&utm_campaign=mar25_sarah_collab&utm_content=reel |
(no UTM at all, relying on Meta fbclid) | fbclid doesn't track campaign/content | Full UTM: source, medium, campaign, content all specified |
The difference between the first and second column is the difference between "we think Instagram is working" and "Instagram Stories with video creative B drove ₹1.4 lakhs in the Diwali campaign."
One is a guess. The other is a decision.
Platform Gotchas Nobody Tells You
Every platform has traps. Here's where your UTMs break even when you think you're doing it right.
Meta auto-tagging (fbclid)
Meta adds fbclid automatically to every ad click. This is good. It helps GA4 identify that traffic came from a Meta platform.
But fbclid only identifies the click source. It does NOT track campaign name, creative variant, or placement. You still need manual UTMs for those.
Both can coexist on the same URL. Your link will look like this:
Don't rely on fbclid alone. Add your own UTMs.
Google auto-tagging (gclid)
Google Ads adds gclid automatically. If your GA4 and Google Ads are linked, gclid auto-tags source and medium.
Great for basic attribution. But for campaign name, keyword, and creative variant, you still need manual UTMs or ValueTrack parameters in your tracking template.
Keep auto-tagging ON. Add manual UTMs as backup. When both exist, GA4 prioritizes manual UTMs for campaign-level data. This gives you control over naming while keeping auto-tagging benefits for conversion import.
Shopify's checkout domain
This is the silent killer for D2C brands on Shopify.
When a customer moves from your store domain (yourstore.com) to Shopify's checkout domain (yourstore.myshopify.com or checkout.shopify.com), the session can break. UTM data gets lost.
GA4 sees it as a new session from a new domain. Your paid Instagram traffic that added to cart? Suddenly looks like direct traffic at checkout.
Fix: Use server-side tracking tools like Analyzify, Elevar, or Littledata. These store UTM data in cart attributes and order metafields. Even if the session breaks, UTM data persists through checkout and gets written to the order.
Don't rely on client-side GA4 alone for Shopify stores. You'll massively undercount paid channel conversions.
Email platforms (Klaviyo/Mailchimp)
Most ESPs auto-append UTMs to links in your emails. This is usually helpful.
Klaviyo, for example, automatically adds utm_source=klaviyo and utm_medium=email to every link. Great.
But check what your ESP adds by default. Does it set the campaign name? Does it match your naming convention?
In Klaviyo, the campaign name defaults to the flow name or campaign name you set in the platform. If your flow is called "Abandoned Cart - Reminder 2", your utm_campaign will be "Abandoned Cart - Reminder 2" with spaces and capital letters.
Override it. Set custom UTM values in Klaviyo's email settings. Make it 'abandoned_cart_flow' and 'email_reminder_2'. Match your convention.
The truth table
Platform | What Auto-Tags | What You Must Add Manually |
|---|---|---|
Meta Ads | source (via fbclid) | medium, campaign, content |
Google Ads | source, medium (via gclid) | campaign, term, content (or use ValueTrack) |
Klaviyo | source, medium | campaign (flow name), content (variant) |
Instagram Bio Link | nothing | everything (source, medium, campaign) |
Influencer Posts | nothing | everything (give them the pre-built link) |
When in doubt, add manual UTMs. Redundancy is better than missing data.
Audit Your Current Mess in 30 Minutes
You already have UTM chaos. Let's quantify it.
Step 1: Export your GA4 traffic acquisition data
Go to GA4 > Reports > Acquisition > Traffic acquisition. Set date range to last 90 days. Export the table. Filter by session source.
Count how many variations exist for each platform.
If you find 'instagram', 'Instagram', 'ig', 'IG', 'insta', 'IG_paid', 'ig_organic', 'ig_influencer', and 'social_ig', congratulations. You have nine invisible Instagram campaigns.
Real example from a beauty brand we audited:
Platform | Variations Found | Revenue Hidden in Fragments |
|---|---|---|
9 | ₹3.4L (AI tool reported only ₹82K as "Instagram") | |
6 | ₹2.1L | |
4 | ₹89K |
The AI attribution tool they were using looked at 'instagram' (lowercase) as the primary source and ignored the other eight variations. It said Instagram drove ₹82K. The real number was ₹3.4 lakhs.
Their entire channel strategy was based on underreported Instagram performance. They almost cut the budget.
Step 2: Create a mapping sheet
Open a spreadsheet. Column A: old UTM values you found in the audit. Column B: new standardized values.
Example:
Old Value | New Value |
|---|---|
IG | |
ig_paid | |
insta | |
social_festive |
Share this sheet with every person who creates campaign links. Ads manager, email manager, influencer coordinator, agency partners. Make it a living document.
Step 3: Set a UTM cutoff date
Pick a date. Today, next Monday, first of the month. Doesn't matter.
Before this date: old naming chaos. After this date: new convention only.
Don't try to retroactively fix old campaigns. GA4 data can't be changed. Historical mess stays messy. Accept it and move forward clean.
Announce the cutoff in Slack. Pin the naming convention table. Reject any campaign link that doesn't follow the new standard.
Seems harsh. But three months from now when your reporting is clean, you'll wish you started sooner.
What Happens When You Get This Right
Clean UTMs change what questions you can answer.
"Which Instagram campaign worked?" becomes answerable. You're not guessing. You're not merging three different sources manually in a spreadsheet. GA4 just shows you.
You can compare Feed vs Stories vs Reels. Same platform, different placements, different performance. You see it clearly.
You can see which influencer drove revenue, not just traffic. utm_campaign=mar25_sarah_collab shows exactly what Sarah's post contributed. You know if you should work with her again.
Your ROAS calculations become accurate. When paid social revenue isn't split across six different source names, you can actually calculate return on ad spend. You can see if you're profitable or bleeding money.
You stop killing winning campaigns because they're invisible. That ₹2.6 lakh Diwali mistake? Doesn't happen anymore.
Clean data means confident decisions. You know what's working. You double down correctly. You cut what's actually failing, not what's misreported.
Clean UTMs are the foundation. But even with perfect discipline, variations creep in. Someone abbreviates because they're in a hurry. A new hire doesn't read the doc. An agency partner uses their own convention because "that's how we've always done it."
This is exactly what Predflow's semantic layer automates. It maps every variation to a single source of truth. 'ig', 'instagram', 'IG_Paid', 'insta'. They all resolve to one clean channel. You set the rules once. Every report, every dashboard, every analysis uses unified data. But it starts with UTMs. Get the discipline right first. Then automate the cleanup. 👇
Improve Ad performance with Predflow
Diagnose performance drops, creative fatigue, and attribution shifts







