skills/onewave-ai/claude-skills/utm-link-generator

utm-link-generator

Installation
SKILL.md

UTM Link Generator

A disciplined UTM link generation system that enforces consistent naming conventions across all campaigns, maintains a registry to prevent duplicates and naming drift, and outputs platform-ready links. This is not a simple URL concatenator -- it is a naming governance system for marketing attribution.

Why This Exists

UTM chaos is the number one cause of broken marketing attribution. When team members use "linkedin" vs "LinkedIn" vs "linked-in" vs "li" as a source, your analytics become useless. This skill enforces a single source of truth: the UTM registry.

Capabilities

  1. Generate UTM-tagged URLs with validated, consistent parameters
  2. Maintain a utm-registry.json file that tracks all generated links and enforces naming conventions
  3. Prevent duplicates -- warns when a similar link already exists in the registry
  4. Platform-specific formatting -- outputs links optimized for LinkedIn, email, social, and ad platforms
  5. Bulk generation -- create multiple variants for A/B testing or multi-channel campaigns
  6. Validation -- rejects malformed URLs, empty parameters, and convention violations
  7. Reporting -- generates campaign tracking summaries from the registry

UTM Parameter Reference

Parameter Required Purpose Example
utm_source Yes Where the traffic comes from linkedin, google, newsletter
utm_medium Yes Marketing medium cpc, email, social, organic
utm_campaign Yes Campaign identifier q1-2026-product-launch
utm_term No Paid keyword (search ads) project-management-software
utm_content No Differentiates similar links hero-cta, sidebar-banner, variant-a
utm_id No Campaign ID for GA4 camp-2026-q1-001

Naming Conventions (Enforced)

These conventions are non-negotiable. The skill will reject or auto-correct any violations.

General Rules

  1. All lowercase -- Never LinkedIn, always linkedin
  2. Hyphens for spaces -- Never product launch, always product-launch
  3. No special characters -- Only alphanumeric and hyphens
  4. No trailing/leading hyphens -- Never -campaign-name-
  5. No double hyphens -- Never my--campaign
  6. Maximum length: 50 characters per parameter value
  7. Date format in campaigns: q[N]-[YYYY] or [YYYY]-[MM] prefix

Source Values (Canonical List)

Only these source values are allowed. Any new source must be explicitly added to the registry.

Canonical Source Aliases (auto-corrected) Platform
google goog, google-ads, adwords Google Ads / Organic
linkedin li, linked-in, linkedin-ads LinkedIn
facebook fb, meta, facebook-ads Facebook / Meta
instagram ig, insta Instagram
twitter x, x-com, tw X (Twitter)
youtube yt, you-tube YouTube
tiktok tt, tik-tok TikTok
reddit rd Reddit
email mail, e-mail, em Email campaigns
newsletter nl, news-letter Newsletter specifically
bing microsoft-ads, msn Bing / Microsoft
direct none, (direct) Direct traffic
referral ref, partner Referral traffic
podcast pod, spotify Podcast channels
slack sl Slack communities
producthunt ph, product-hunt Product Hunt
hackernews hn, hacker-news Hacker News

Medium Values (Canonical List)

Canonical Medium Aliases (auto-corrected) Use Case
cpc ppc, paid-click, cost-per-click Paid search / paid social clicks
cpm display, paid-impression Display / impression campaigns
email e-mail, mail Email campaigns
social social-media, organic-social Organic social posts
organic seo, organic-search Organic search traffic
referral ref, partner, affiliate Referral / partner links
video vid, youtube, pre-roll Video ad placements
retargeting remarketing, retarget Retargeting campaigns
content blog, article, content-syndication Content marketing
webinar web, event, virtual-event Webinar / event registrations
podcast pod, audio Podcast mentions / ads
sms text, mms SMS / text campaigns
qr qr-code, print QR code / print materials
push push-notification, notification Push notifications

Campaign Naming Pattern

Campaigns follow this structure:

[quarter-or-month]-[year]-[campaign-name]-[optional-variant]

Examples:

  • q1-2026-product-launch
  • 2026-03-spring-webinar
  • q2-2026-brand-awareness-linkedin
  • evergreen-demo-request (for always-on campaigns, skip the date prefix)

Execution Protocol

Step 1: Accept Input

The user provides some or all of these:

  • Destination URL (required) -- The page they want to link to
  • Source (required) -- Where the traffic comes from
  • Medium (required) -- The marketing channel type
  • Campaign (required) -- Campaign name
  • Term (optional) -- Keyword for paid search
  • Content (optional) -- Link differentiator
  • Platforms (optional) -- Which platforms to generate links for (default: all relevant)

If the user provides a brief like "I need links for our Q1 product launch campaign on LinkedIn and email pointing to our pricing page," extract the parameters from natural language.

Step 2: Validate and Normalize

For each parameter:

  1. Convert to lowercase -- LinkedIn becomes linkedin
  2. Replace spaces with hyphens -- product launch becomes product-launch
  3. Strip special characters -- Remove anything not [a-z0-9-]
  4. Check against canonical lists -- Auto-correct known aliases (e.g., fb to facebook)
  5. Reject unknown values -- If a source or medium is not in the canonical list and is not a reasonable addition, warn the user and suggest the closest match
  6. Validate URL -- Ensure the destination URL is well-formed (has protocol, valid domain)
  7. Check length -- Ensure no parameter exceeds 50 characters

Report any corrections made:

## Parameter Validation

- Source: "LinkedIn" -> "linkedin" (normalized to lowercase)
- Medium: "paid" -> "cpc" (corrected to canonical value)
- Campaign: "Q1 Product Launch!" -> "q1-product-launch" (normalized)
- URL: https://example.com/pricing -- Valid

Step 3: Check Registry for Duplicates

Read the utm-registry.json file (or create it if it does not exist). Check for:

  1. Exact duplicates -- Same URL + same parameters. Warn and return the existing link.
  2. Near duplicates -- Same URL + same campaign + different content/medium. Warn but allow (this is often intentional for multi-channel tracking).
  3. Naming conflicts -- Same campaign name but different capitalization or hyphenation. Block and show the existing convention.

Step 4: Generate Links

Build the UTM-tagged URL:

{base_url}?utm_source={source}&utm_medium={medium}&utm_campaign={campaign}[&utm_term={term}][&utm_content={content}][&utm_id={id}]

Rules:

  • If the base URL already has query parameters, append with & not ?
  • URL-encode any parameter values that contain special characters
  • Preserve the base URL's existing query parameters and fragment

Step 5: Generate Platform-Specific Variants

For each platform requested, generate an optimized link:

LinkedIn

## LinkedIn

**Post Link** (organic social):
https://example.com/pricing?utm_source=linkedin&utm_medium=social&utm_campaign=q1-2026-product-launch&utm_content=organic-post

**Ad Link** (paid):
https://example.com/pricing?utm_source=linkedin&utm_medium=cpc&utm_campaign=q1-2026-product-launch&utm_content=sponsored-post

**Message Link** (InMail/DM):
https://example.com/pricing?utm_source=linkedin&utm_medium=social&utm_campaign=q1-2026-product-launch&utm_content=inmail

**Profile Link** (bio/featured):
https://example.com/pricing?utm_source=linkedin&utm_medium=social&utm_campaign=q1-2026-product-launch&utm_content=profile-link

Email

## Email

**Primary CTA**:
https://example.com/pricing?utm_source=email&utm_medium=email&utm_campaign=q1-2026-product-launch&utm_content=primary-cta

**Secondary CTA**:
https://example.com/pricing?utm_source=email&utm_medium=email&utm_campaign=q1-2026-product-launch&utm_content=secondary-cta

**Header Link**:
https://example.com/pricing?utm_source=email&utm_medium=email&utm_campaign=q1-2026-product-launch&utm_content=header-link

**Footer Link**:
https://example.com/pricing?utm_source=email&utm_medium=email&utm_campaign=q1-2026-product-launch&utm_content=footer-link

Social (General)

## Social

**Twitter/X**:
https://example.com/pricing?utm_source=twitter&utm_medium=social&utm_campaign=q1-2026-product-launch

**Facebook**:
https://example.com/pricing?utm_source=facebook&utm_medium=social&utm_campaign=q1-2026-product-launch

**Instagram** (bio link):
https://example.com/pricing?utm_source=instagram&utm_medium=social&utm_campaign=q1-2026-product-launch&utm_content=bio-link

**Reddit**:
https://example.com/pricing?utm_source=reddit&utm_medium=social&utm_campaign=q1-2026-product-launch

Ads (Paid)

## Paid Ads

**Google Ads**:
https://example.com/pricing?utm_source=google&utm_medium=cpc&utm_campaign=q1-2026-product-launch&utm_term={keyword}

**LinkedIn Ads**:
https://example.com/pricing?utm_source=linkedin&utm_medium=cpc&utm_campaign=q1-2026-product-launch

**Facebook/Meta Ads**:
https://example.com/pricing?utm_source=facebook&utm_medium=cpc&utm_campaign=q1-2026-product-launch

Note: For Google Ads, use {keyword} as a dynamic placeholder that Google will auto-replace.

Step 6: Update Registry

Append all generated links to utm-registry.json:

{
  "version": "1.0",
  "lastUpdated": "2026-04-10T12:00:00Z",
  "namingConventions": {
    "sources": ["google", "linkedin", "facebook", "instagram", "twitter", "email", "newsletter"],
    "mediums": ["cpc", "cpm", "email", "social", "organic", "referral", "video", "retargeting"]
  },
  "campaigns": [
    {
      "name": "q1-2026-product-launch",
      "createdAt": "2026-04-10T12:00:00Z",
      "description": "Q1 2026 product launch campaign",
      "links": [
        {
          "id": "utm-001",
          "url": "https://example.com/pricing?utm_source=linkedin&utm_medium=social&utm_campaign=q1-2026-product-launch&utm_content=organic-post",
          "source": "linkedin",
          "medium": "social",
          "campaign": "q1-2026-product-launch",
          "content": "organic-post",
          "platform": "linkedin",
          "variant": "organic-post",
          "createdAt": "2026-04-10T12:00:00Z",
          "status": "active"
        }
      ]
    }
  ],
  "stats": {
    "totalLinks": 1,
    "totalCampaigns": 1,
    "sourcesUsed": ["linkedin"],
    "mediumsUsed": ["social"]
  }
}

Step 7: Output Summary

Present the final output in a clean, copy-paste-ready format:

## UTM Links Generated

**Campaign**: q1-2026-product-launch
**Destination**: https://example.com/pricing
**Generated**: 2026-04-10

### Ready-to-Copy Links

| Platform | Variant | Link |
|----------|---------|------|
| LinkedIn (organic) | organic-post | [full URL] |
| LinkedIn (paid) | sponsored-post | [full URL] |
| Email (primary CTA) | primary-cta | [full URL] |
| Email (secondary CTA) | secondary-cta | [full URL] |
| Twitter | default | [full URL] |
| Facebook | default | [full URL] |

### Registry Updated
- New links added: 6
- Total links in registry: 6
- Registry file: ./utm-registry.json

### Validation Report
- All parameters normalized to convention
- No duplicate links found
- No naming conflicts detected

Bulk Generation Mode

For generating links across many campaigns or many URLs at once.

Input Format (Bulk)

The user can provide a table or list:

Generate UTM links for these pages:
- /pricing -- linkedin, email, twitter -- q1-2026-product-launch
- /demo -- linkedin, google-ads -- q1-2026-demo-push
- /case-studies -- email, linkedin -- q1-2026-social-proof

Processing

  1. Parse each line into (URL, platforms, campaign)
  2. Validate and normalize all parameters
  3. Generate all variant links for each URL/platform combination
  4. Deduplicate across the batch
  5. Update registry with all new links
  6. Output a master table

Output Format (Bulk)

## Bulk UTM Generation -- 3 campaigns, 8 platform variants, 24 total links

| Campaign | URL | Platform | Variant | Full Link |
|----------|-----|----------|---------|-----------|
| q1-2026-product-launch | /pricing | linkedin-organic | organic-post | [URL] |
| q1-2026-product-launch | /pricing | linkedin-paid | sponsored-post | [URL] |
| q1-2026-product-launch | /pricing | email | primary-cta | [URL] |
| ... | ... | ... | ... | ... |

Registry updated: 24 new links added.

Registry Management Commands

The user can also invoke this skill for registry operations:

Audit Registry

"Audit my UTM registry"

Reads utm-registry.json and reports:

  • Total campaigns and links
  • Naming convention violations (if any crept in manually)
  • Stale campaigns (older than 6 months with no new links)
  • Unused sources or mediums
  • Duplicate or near-duplicate links

Add Custom Source/Medium

"Add 'partnerstack' as a UTM source"

Adds the new value to the canonical list in the registry and documents it.

Campaign Report

"Show me all links for the q1-2026-product-launch campaign"

Filters the registry and displays all links for that campaign, grouped by platform.

Export for Google Sheets

"Export my UTM registry as CSV"

Generates a CSV file with columns: Campaign, URL, Source, Medium, Content, Term, Full Link, Created Date, Status.

Error Handling

Error Response
Invalid URL (no protocol) Auto-prepend https:// and warn
Unknown source Suggest closest canonical match, ask for confirmation
Unknown medium Suggest closest canonical match, ask for confirmation
Campaign name too long Suggest abbreviated version
Duplicate link exists Show existing link, ask if user wants to create anyway
Registry file missing Create new registry with default conventions
Registry file corrupted Attempt to parse what exists, back up, create fresh
Base URL has existing UTMs Strip existing UTM params, warn user, apply new ones

Integration Notes

  • Google Analytics 4: All parameters map directly to GA4 dimensions. utm_id maps to campaign_id.
  • HubSpot: Source and medium map to HubSpot's Original Source properties.
  • Salesforce: Campaign name can map to Salesforce Campaign records via integration.
  • Mixpanel / Amplitude: UTM params auto-captured on page load via standard SDKs.

Best Practices Embedded in This Skill

  1. One registry, one truth -- All UTM links flow through the registry. No ad-hoc link creation.
  2. Convention over configuration -- Canonical lists prevent naming drift before it starts.
  3. Auto-correction over rejection -- When possible, fix the input rather than blocking the user.
  4. Platform awareness -- Different platforms need different utm_content values to distinguish placements.
  5. Date-prefixed campaigns -- Makes it trivial to filter analytics by time period.
  6. Audit trail -- Every link is timestamped and attributed in the registry.
Weekly Installs
23
GitHub Stars
103
First Seen
Today