# UTM vocabulary template. Propose the filled version as the UTM section of
# martech-context/naming-rules.md. Approved source/medium pairs, their expected
# channels and test results live in allowed-pairs.csv, which the link builder
# reads. Re-check expected channels against the live default channel group page
# before approval and record the date.
checked_against: https://support.google.com/analytics/answer/9756891
checked_on: "2026-10-17"
owner: marketing_ops

format:
  value_pattern: "^[a-z0-9_]+$"
  medium_pattern: "^[a-z0-9_-]+$"
  campaign_pattern: "^20[0-9]{2}_(0[1-9]|1[0-2])_[a-z0-9_]+$"
  campaign_max_length: 60
  utm_id_pattern: "^[A-Za-z0-9_-]+$"
  registry_id_format: "cmp_yyyy_nnn"
  initiative_id_format: "ini_yyyy_nnn, or the initiative IDs campaign-naming-convention already minted"
  required: [utm_source, utm_medium, utm_campaign, utm_id]
  never_in_parameters: [email address, name, phone number, CRM contact ID, per-click random value]
  unknown_value_policy: flag for review; never invent a new value during a build

campaign_names:
  non_paid: registry name yyyy_mm_initiative, plus a qualifier only when it changes a decision
  paid_platforms: the platform campaign name by the platform's name macro; name platform campaigns with the registry name plus a qualifier, or by campaign-naming-convention
  always_on: the month the program started, never changed (2024_03_onboarding_flow); a change of purpose or audience is a new initiative

mediums:
  - value: cpc
    use_for: paid search and other pay-per-click
    default_channel: Paid Search with a search-list source; Paid Other with a source on no list
  - value: paid_social
    use_for: paid social platforms
    default_channel: Paid Social with a social-list source; Paid Other with a source on no list
  - value: paid_video
    use_for: paid video platforms with a source on Google's video list only
    default_channel: Paid Video with a video-list source
    rejected_combination: any source off the video list; the medium also matches the Organic Video regex, so the channel is a test result, not a prediction
  - value: display
    use_for: banners and programmatic display, with the DSP or publisher as source
    default_channel: Display; test required if the source is on a Google list
  - value: email
    use_for: owned newsletters, lifecycle email, partner newsletters
    default_channel: Email
  - value: sms
    use_for: text messages
    default_channel: SMS
  - value: push
    use_for: app and web push
    default_channel: Mobile Push Notifications
  - value: audio
    use_for: podcast and radio reads with a vanity URL
    default_channel: Audio
  - value: social
    use_for: unpaid posts by the brand or its staff
    default_channel: Organic Social
  - value: referral
    use_for: unpaid partner, integration and directory links
    default_channel: Referral; test required if the source is on a Google list
  - value: affiliate
    use_for: affiliate networks and commission links
    default_channel: Affiliates; test required if the source is on a Google list
  - value: ai-assistant
    use_for: links the team publishes inside an assistant surface it controls, with its own app slug as source
    default_channel: AI Assistant
  - value: offline
    use_for: QR codes, print, events, vanity URLs on physical media
    default_channel: Unassigned
    custom_channel: Offline

content_slots:
  email: [hero_button, article_1, article_2, article_3, footer_link, ps_link]
  web_partner: [review_page, listing, sponsor_slot]
  offline: [qr, vanity]
  social: [company_post, employee_post, profile_link, newsletter_article]
  ai_assistant: [help_link, answer_link]

custom_channel_rules:
  - group: Acme channels
    channel: Offline
    condition: medium exactly matches offline
    position: first

rejected_values:
  - value: li
    reason: not in Google's 2023 source file; with a paid medium predicted Paid Other; confirm with a test visit before relying on it
  - value: meta
    reason: not in Google's 2023 source file; predicted Paid Other with a paid medium; use facebook
  - value: newsletter
    reason: not an email medium value; lands in Unassigned when the source is on no list
  - value: affiliates
    reason: untested; the rule reads Medium = affiliate and may not match the plural, so it may land in Unassigned
  - value: qr
    reason: use offline with utm_content qr
  - value: ai_assistant
    reason: the AI Assistant rule expects ai-assistant
  - value: email (as a source)
    reason: the Email rule also fires on the source; use the publication or program
  - value: sms (as a source)
    reason: the SMS rule also fires on the source; use the program or sender
