Systems Library / Marketing Automation / How to Automate UTM Parameter Generation for Ads
Marketing Automation paid advertising

How to Automate UTM Parameter Generation for Ads

Generate consistent UTM tags for every ad automatically to fix attribution.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

When you automate UTM parameters for ad campaigns, you fix the attribution mess that comes from inconsistent manual tagging. I have seen accounts where the same campaign had five different UTM formats because different people built the ads. One system, one format, zero confusion.

This takes 20 minutes to build and saves hours of debugging analytics later.

What You Need Before Starting

Step 1: Define Your UTM Convention

UTM_CONFIG = {
    "source_map": {
        "meta": "facebook",
        "google": "google",
        "tiktok": "tiktok",
        "linkedin": "linkedin",
    },
    "medium_map": {
        "paid": "cpc",
        "organic": "organic",
        "email": "email",
    },
    "separator": "_",
}

Step 2: Build the UTM Generator

from urllib.parse import urlencode, urlparse, urlunparse, parse_qs

def generate_utm(base_url, platform, campaign_name, adset_name, ad_name, medium="paid"):
    source = UTM_CONFIG["source_map"].get(platform, platform)
    medium_val = UTM_CONFIG["medium_map"].get(medium, medium)
    sep = UTM_CONFIG["separator"]
    
    # Clean names for UTM use
    def clean(name):
        return name.lower().replace(" | ", sep).replace(" ", sep).replace("--", sep).strip(sep)
    
    utm_params = {
        "utm_source": source,
        "utm_medium": medium_val,
        "utm_campaign": clean(campaign_name),
        "utm_content": clean(adset_name),
        "utm_term": clean(ad_name),
    }
    
    # Parse existing URL and append UTMs
    parsed = urlparse(base_url)
    existing_params = parse_qs(parsed.query)
    existing_params.update(utm_params)
    
    new_query = urlencode(existing_params, doseq=True)
    final_url = urlunparse(parsed._replace(query=new_query))
    
    return final_url

Step 3: Batch Generate for All Ads

def generate_all_utms(ads_config, base_url):
    results = []
    
    for ad in ads_config:
        url = generate_utm(
            base_url=base_url,
            platform=ad["platform"],
            campaign_name=ad["campaign"],
            adset_name=ad["adset"],
            ad_name=ad["ad_name"],
        )
        results.append({
            "ad_name": ad["ad_name"],
            "platform": ad["platform"],
            "tagged_url": url,
        })
    
    return results

# Example usage
ads = [
    {"platform": "meta", "campaign": "JB | Lead | UK | Assessment", "adset": "Broad | 28-55 | Lead", "ad_name": "01 | iMessage | Native | TomAgency"},
    {"platform": "meta", "campaign": "JB | Lead | UK | Assessment", "adset": "Broad | 28-55 | Lead", "ad_name": "02 | Salary | PASTOR | CostMath"},
    {"platform": "google", "campaign": "JB | Lead | US | Quiz", "adset": "Broad | 25-45 | Lead", "ad_name": "01 | Search | DR | AIAudit"},
]

tagged = generate_all_utms(ads, "https://jaybanlasan.com/assessment/")
for t in tagged:
    print(f"{t['ad_name']}:\n  {t['tagged_url']}\n")

Step 4: Validate UTMs Before Launch

def validate_utm(url):
    parsed = urlparse(url)
    params = parse_qs(parsed.query)
    
    required = ["utm_source", "utm_medium", "utm_campaign"]
    missing = [p for p in required if p not in params]
    
    issues = []
    if missing:
        issues.append(f"Missing required params: {missing}")
    
    for key, values in params.items():
        if key.startswith("utm_"):
            val = values[0]
            if " " in val:
                issues.append(f"{key} contains spaces: '{val}'")
            if val != val.lower():
                issues.append(f"{key} has uppercase: '{val}'")
    
    return {"valid": len(issues) == 0, "issues": issues, "url": url}

# Validate all generated URLs
for t in tagged:
    result = validate_utm(t["tagged_url"])
    if not result["valid"]:
        print(f"INVALID: {t['ad_name']}: {result['issues']}")

Step 5: Export for Ads Manager

import csv

def export_utm_sheet(results, output_path="utm_tags.csv"):
    with open(output_path, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=["ad_name", "platform", "tagged_url"])
        writer.writeheader()
        writer.writerows(results)
    print(f"Exported {len(results)} URLs to {output_path}")

Hand this CSV to whoever builds the ads, or feed it directly into your campaign creation API. Every ad gets the right UTM, every time, with zero manual typing.

What to Build Next

Connect this to your Meta campaign creation script so UTMs are applied automatically during ad creation. Then build a UTM audit tool that scans all live ads and flags any with missing or malformed tags.

Related Reading

Want this system built for your business?

Get a free assessment. We will map every system your business needs and show you the ROI.

Get Your Free Assessment

Related Systems