River
Y CombinatorBacked by Y Combinator
FREE TEMPLATE

Campaign Naming Convention Template

A convention derived from the names you already use, with every medium token checked against the published rules that decide which channel it lands in.

Free download  ·  No account needed

One published rule files a campaign under Shopping based on its name. Six real names, tested.

  • shopfront-refreshShoppingshop at the start of the name
  • q1-shop-launchShoppinga hyphen precedes shop
  • eshop-relaunchShoppinge sits outside the excluded letter range
  • 2026-shopping-weekShoppingshopping anywhere matches
  • workshop-seriesSafek is inside the excluded range
  • bookshop-partnershipSafesame reason

The first four were email and paid search campaigns. All four reported as Shopping, and nothing raised an error.

Every naming convention template hands you the same two things: a token order and a delimiter. Date, channel, region, campaign, lowercase, joined by underscores. It is reasonable advice and it treats the name as a label. The name is not a label. It is a classification input, the classification rules are published and cannot be edited, and two of them read the campaign name itself. Name a campaign shopfront-refresh and it is filed under Shopping, whatever it was.

The medium token is a controlled vocabulary you do not own. Google's default channel group is a fixed rule set: newsletter matches nothing, so the email rule wants the literal value email. The push rule matches a medium that ends with push, so mobile_push works and push_notification does not. The affiliate rule is an exact match, so partner and affiliates both fall out. Sixteen approved tokens sit on one sheet with the rule each satisfies.

Then the standard gets derived from what you already have rather than invented, because a convention that cannot parse your history splits every report at the changeover date. The register ranks your existing patterns by traffic and adopts the dominant one, delimiter and date format included. Corrections come from the published rules, not from taste, and the mapping from old name to new is what makes a historical rebuild possible. It sits alongside survivorship rules and a field dictionary.

The tokens that classify, and the ones that quietly do not

Every rule quoted on the vocabulary sheet is from the published default channel group. None of it is editable, which is why the token has to change instead.

Medium Vocabulary

Illustrative rows for a fictional outdoor retailer, Fellgate Outdoor. Every rule is quoted from the published default channel group.

Our tokenLands inPublished rule it matchesWrong token people reach forWhere the wrong token lands
cpcPaid SearchMedium matches the paid regex, source is a search siteadwordsUnassigned
paid_socialPaid SocialMedium matches the paid regex, source is a social sitesocial-paidOrganic Social
cpvPaid VideoMedium matches the paid regex, source is a video sitevideoOrganic Video
emailEmailMedium is email, e-mail, e_mail or email with a spacenewsletterUnassigned
affiliateAffiliatesMedium is exactly affiliatepartnerUnassigned
mobile_pushMobile PushMedium ends with pushpush_notificationUnassigned
displayDisplayMedium is one of display, banner, expandable, interstitial, cpmprogrammaticUnassigned
organicOrganic SearchMedium is exactly organic, or source is a known search siteseoUnassigned
ai-assistantAI AssistantMedium is exactly ai-assistantchatgptUnassigned
retargetingPaid OtherMedium matches the paid regexremarketingUnassigned

Two of these are worse than Unassigned. A medium of social-paid or video lands in a real organic channel, so paid budget reports as free traffic and the return on ad spend looks infinite. Unassigned is at least visibly wrong.

Naming Register

The existing names, parsed and ranked by traffic. The dominant pattern is adopted rather than replaced, which is what makes the other rows mappable.

Existing nameSessionsMediumCurrent channelCompliant nameMapping
2026q1-boot-launch-uk96,331cpcPaid Searchno changeAlready compliant. 61% of traffic uses this pattern.
2026q2-tent-clearance-de44,117social-paidOrganic Social2026q2-tent-clearance-deRetag medium to paid_social
shopfront-refresh41,208emailOrganic Shopping2026q1-storefront-refresh-ukRename. The name triggers the shopping rule.
Q1_ShopTheSale_UK28,640paid_socialPaid Shopping2026q1-sale-launch-ukRename. Shop after an underscore still triggers it.
(not set)22,470variousvariousn/aUntagged. A tagging problem, not a naming one.
spring-newsletter19,004newsletterUnassigned2026q2-spring-edit-ukRename and retag medium to email
eshop-relaunch15,630cpcPaid Shopping2026q3-web-relaunch-ukRename. The e before shop triggers it.
workshop-series-autumn11,286emailEmail2026q3-workshop-series-ukSafe. Renamed for pattern only.
2026q3-app-push-uk8,815push_notificationUnassigned2026q3-app-push-ukRetag medium to mobile_push
2026q1-boot-launch-UK7,742cpcPaid Search2026q1-boot-launch-ukMerge. Case only, so it splits one campaign into two rows.

95,163 of 346,244 sessions are currently classified wrongly. The capitalised row on the bottom line is correctly classified and still splitting one campaign's spend across two report lines, which is the failure nobody spots.

Convention by Object

Hyphens rather than underscores because the existing names already used them four to one. The standard adopts the habit rather than correcting it.

Object or fieldPatternCaseAllowed valuesRead by a classification ruleEnforced where
utm_source{platform}lowerControlled list of 19 platformsYesLink builder
utm_medium{channel}lowerThe 16 vocabulary tokens and nothing elseYesLink builder
utm_campaign{yyyyqq}-{initiative}-{market}lowerInitiative from the register, market from the listYes, two rulesLink builder plus monthly scan
utm_content{creative}-{variant}lowerFree within the patternNoLink builder
utm_term{keyword}lowerPaid search onlyNoAd platform template
utm_id{campaign_id}as issuedThe id the ad platform issuesNoAd platform export
CRM campaign name{yyyyqq}-{initiative}-{market}lowerIdentical to utm_campaignNoCreation form validation
CRM list name{type}-{initiative}-{yyyymm}lowerType from a five-value listNoCreation form validation
CRM deal name{account}-{product}-{yyyyqq}title on accountAccount from the legal entity fieldNoCreation form validation
Ad platform campaign{yyyyqq}-{initiative}-{market}-{objective}lowerObjective from the platform's own listIndirectlyPlatform naming template
File and asset names{yyyymmdd}-{initiative}-{asset}-v{n}lowerFree within the patternNoConvention only

Four of eleven fields feed a classification rule, and those four cannot carry free text whatever anybody prefers. The other seven are labels, and the file naming row is deliberately unenforced because asset names feed no report.

What the pack does that a token order does not

01

Turns the published rules into typeable tokens

Sixteen approved medium values, each with the channel it lands in, the published rule it satisfies, and the wrong token people reach for instead. The rules cannot be edited, so the token is the only thing that can change, and the sheet is where that gets decided once.

02

Flags the tokens that land in a real wrong channel

A medium of social-paid against a social source satisfies the organic social rule, so paid budget reports as free traffic. A medium of video does the same to a paid video buy. Those are worse than Unassigned, because the number looks plausible and the total is right.

03

Tests every campaign name against the rule that reads names

The shopping pattern is precise rather than vague: shopping anywhere triggers it, and shop triggers it at the start of a name or after anything outside the lower-case a-to-d and f-to-z ranges. So shopfront and eshop trigger it and workshop does not.

04

Derives the standard from your dominant pattern

The register ranks your existing patterns by traffic and adopts the one carrying the most, delimiter and date format included. That is what lets the remaining names be mapped rather than abandoned, and a convention that cannot parse your history puts a step in every chart.

05

Separates the case rule from the vocabulary rule

Parameter values are case sensitive in reports and channel definitions are not, so a capitalisation mistake never breaks classification and always splits a report into two rows nobody notices. Two problems, two rules, instead of one instruction to be consistent.

06

Logs what each violation actually broke

An email report showing no email traffic. One campaign's spend divided across two rows. A suppression list sorted into the nurture lists and mailed twice. The recurring column separates a one-off retag from the link builder or validation rule that keeps producing them.

How the pack runs

  1. 1

    Send the names

    Campaign names with volumes, the full source and medium report rather than the top rows, and your CRM campaign and list names.

  2. 2

    Parse and rank

    River extracts the tokens genuinely present, ranks the patterns by traffic rather than by count, and reports the dominant pattern's share.

  3. 3

    Check against the rules

    Every medium value and campaign name is tested against the published channel rules, and the ones landing in the wrong channel are ranked by how dangerous the error is.

  4. 4

    Standard and mapping

    The convention lands per object with the enforcement point named, and the register carries the old-name-to-new-name mapping for a historical rebuild.

Frequently asked questions

Is this not just an argument about hyphens and underscores?

No, and the pack rejects that request explicitly. Both delimiters classify identically and fragment identically, so there is no reporting argument either way and one is worth more than two teams' habits. The content is the vocabulary and the two rules that read your campaign name.

What is the shop thing exactly?

One of Google's published channel rules classifies a campaign as Shopping based on the campaign name. The pattern is exact: shopping anywhere matches, and shop matches at the start of a name or after anything outside the lower-case a-to-d and f-to-z ranges. So eshop triggers it and bookshop does not.

Why derive the convention instead of writing a good one?

Because a convention invented from a blank page cannot parse the names you already have, so every report gets a step in it at the changeover date and nobody rebuilds years of history by hand. Adopting your dominant pattern is what makes the other names mappable.

Can we fix the historical data once the names are right?

You can rebuild a report by grouping old names under new ones, and the register's mapping exists for exactly that. You cannot reclassify the channel, because classification happens when the session is recorded. Naming mistakes are cheap forward and impossible backward, which is the argument for doing this now.

Does capitalisation actually matter?

For two different reasons that need two different rules. Parameter values are case sensitive, so utm_source=google differs from utm_source=Google, and one campaign becomes two report rows. Channel definitions ignore case, so nothing looks broken and both rows classify correctly.

Our CRM has its own campaign records. Does this cover those?

Yes, and the join is the point: a CRM campaign name that differs from the analytics campaign name by one character does not error, it simply fails to join and no offline conversion attaches. The pack sets both patterns identically and validates at creation. Stage definitions get the same treatment on the deal side.

What about the naming inside the ad platforms themselves?

Covered as a documented exception. Ad platform names carry an extra objective token that buyers need, and it is dropped from the campaign parameter through dynamic insertion so the two still join. Reporting across platforms afterwards is what a cross-platform paid report handles.

Find out which names are in the wrong channel

Send your campaign names and a full source and medium report, and get the vocabulary, the register and the mapping back.

Get the template