---
name: utm_tracking_taxonomy
description: Set and govern a UTM naming system a whole team can follow: source, medium, and campaign rules tied to GA4 default channel definitions, a versioned registry of approved values with an approval and deprecation process, a builder and validator CLI that catches typos, case splits, and unregistered values before links ship, and a cleanup workflow that maps a messy campaign history to canonical values. Use when setting up UTM conventions, naming or auditing campaign links, fixing split or Unassigned GA4 traffic, approving a new source or medium, or cleaning up inconsistent historical tagging. For attribution models and incrementality, use marketing-attribution instead; this skill owns the tagging taxonomy only.
---

# UTM Tracking Taxonomy

## Purpose

GA4 reads UTM values exactly as they arrive. Values are case sensitive, so one channel spelled three ways becomes three report rows, and a medium GA4 does not recognise falls into Unassigned. The fix is governance, not care: a small registry of approved values, one way to build links, a validator that checks every link against the registry, and a recurring audit that maps old values and fixes them at the source. This skill sets that system up and runs it.

The closest other skill, marketing-attribution, covers which model gets credit for a conversion and folds UTM hygiene into one short reference. This skill is the layer underneath it: the taxonomy, the registry, and the checks that keep the raw values clean enough to model at all.

## Workflow

1. **Start from the registry, or create it.** Copy `assets/registry-template.csv` to the team's shared location and edit the rows to the team's real platforms, partners, and senders. One row per approved source and medium, each with a status, the GA4 channel it should land in, an owner, and a note when a spelling is easy to confuse. If a registry already exists, work from it and never from memory or last quarter's spreadsheet.
2. **Set the taxonomy before approving any values.** Read `references/taxonomy.md` and settle four things as a team: the separator (hyphen or underscore), the campaign pattern (the default is `yyyy-qN_objective_theme`), the closed objective list inside campaign names, and the medium picks from the documented GA4 channel table. Medium is constrained by GA4; source and campaign are the team's to name once and then hold.
3. **Approve new values through the gate, not around it.** Follow the approval step in `references/governance.md`: check for an existing value or an alias case first, confirm a new medium names the channel it lands in, check near-duplicates, then add the row with an owner before any link uses it. Anyone can request a value; the registry owner approves it.
4. **Build every link with the builder.** Run `python3 scripts/utm_tools.py build --base <url> --source <v> --medium <v> --campaign <v> --registry <registry.csv>`, adding `--content`, `--term`, `--id`, or `--source-platform` only when they apply. The builder refuses unregistered values, case errors, and bad characters, and prints the predicted GA4 default channel. Hand-built links are where splits start.
5. **Validate links you did not build.** Run `python3 scripts/utm_tools.py validate <url> --registry <registry.csv>`, or pass `--file urls.txt` for a batch from a partner, an agency, or an email tool. Fix every error before the link ships. Read the warnings too: a deprecated value or an Unassigned prediction on a live link is a decision a person should make, not a detail to wave through.
6. **Check the places that tag without asking.** Ad platform templates, email tool defaults, shorteners, and QR generators all append or strip parameters on their own. Work the four spots in `references/governance.md` whenever a platform changes and at least quarterly, and test one live link from each end to end.
7. **Audit history on a cadence and clean up on two tracks.** Export session source, medium, and campaign, then run `python3 scripts/utm_tools.py audit --file history.csv --registry <registry.csv> --aliases <aliases.csv>`. The output maps each observed value to a canonical value with sessions and a reason. Apply the map in reporting, and fix each value at its tagging source so new sessions arrive clean. `references/cleanup-worked-example.md` walks a full cleanup: 19,508 sessions, sources collapsing from 9 values to 5, campaigns from 3 spellings to 1.
8. **Report the state plainly.** Name the registry location and owner, the values added or deprecated this round, the audit's top mapped values by sessions, the current Unassigned share if it was measured, and any tagging source still producing rogue values.

## Output Contract

- Every deliverable that includes a tagged link includes only registry-approved values, built or validated with the CLI output to show for it, plus the predicted GA4 channel for each distinct source and medium pair.
- A taxonomy setup delivers: the registry file (CSV with parameter, value, status, channel_hint, owner, notes), the alias file, the settled separator and campaign pattern stated in words, and the approval and audit routine from `references/governance.md` with a named owner.
- A cleanup delivers the mapping table the audit command produced (observed value, canonical value, sessions, reason, action), the list of tagging sources to fix, and a clear split between what was mapped in reporting and what was fixed going forward.
- Numbers in any deliverable come from an export or a CLI run in hand. Session counts are never estimated to make a split look bigger or smaller.
- A value with no approved match is reported as unmapped and routed to approval. It is never silently renamed in a report.

## Operating Rules

1. Lowercase everything, one separator, no spaces, no personal data in any value. GA4 treats `google` and `Google` as different sources, and UTM values end up in shared links and logs.
2. Always use utm_source, utm_medium, and utm_campaign together. Google states this directly, and a partial tag produces (not set) values and a channel guess.
3. Never invent a medium. Pick from the documented channel table in `references/taxonomy.md`, and treat an Unassigned prediction as a stop sign unless the team accepts Unassigned for that traffic on purpose and records it.
4. Never tag internal links. A UTM on a link inside the team's own site overwrites the session source and medium that actually brought the visitor in. Use click events for internal movement.
5. One campaign, one name, for its whole life, across every channel. Variants and creatives belong in utm_content; keywords belong in utm_term, on paid search only.
6. utm_creative_format and utm_marketing_tactic are not currently reported in GA4. Do not promise reporting on them.
7. Deprecate, never delete. A removed registry row makes old reports unreadable and breaks the audit mapping. Mark the status, name the replacement, add the alias.
8. Fix tagging at the source during cleanup. A mapping table without a template, tool, or partner fix behind it guarantees the same cleanup next quarter.
9. Keep the heavy rules in the references and the checks in the CLI. If a rule cannot be checked by the validator or read off the registry, rewrite it until it can.
