URL SyntaxUpdated 2025

URL Encoding Automation Errors: Why Marketing Tools Double-Encode UTMs

Discover how marketing automation platforms, email tools, and APIs create double-encoding errors. Learn to identify and prevent automation-induced URL encoding issues.

8 min readURL Syntax

"Our marketing automation was supposed to save time. Instead, it double-encoded every single URL we sent. 6 months, 200+ campaigns, 450,000 sessions—all tracked with %2520 and %2526 in the campaign names. Our automation was actually destroying our data."

The Automation Paradox

The promise: Automate URL generation → consistent tracking → better data

The reality: Many automation tools inadvertently double-encode URLs, creating worse data than manual processes.

Common Automation Culprits

  1. Email Service Providers (Mailchimp, HubSpot, Constant Contact)
  2. Marketing Automation (Marketo, Pardot, ActiveCampaign)
  3. URL Shorteners (Bitly, TinyURL, Rebrandly)
  4. Social Scheduling (Hootsuite, Buffer, Sprout Social)
  5. CRM Systems (Salesforce, HubSpot CRM)
  6. API Integrations (Zapier, Make, custom scripts)
  7. Analytics Platforms (Google Tag Manager, Segment)

🚨 Not sure what's breaking your tracking?

Run a free 60-second audit to check all 40+ ways UTM tracking can fail.

Scan Your Campaigns Free

✓ No credit card ✓ See results instantly

How Automation Creates Double-Encoding

Email Service Provider Errors

Mailchimp Auto-Encoding

The problem:

Code
Your merge tag: *|CAMPAIGN:SUBJECT|*
Subject: "Summer Sale 2024"

Mailchimp's template:
<a href="https://example.com?utm_campaign=*|CAMPAIGN:SUBJECT|*">

What you think happens:
https://example.com?utm_campaign=Summer Sale 2024

What actually happens:
1. Mailchimp replaces: Summer Sale 2024
2. Mailchimp sees spaces, encodes: Summer%20Sale%202024
3. URL becomes: ...?utm_campaign=Summer%20Sale%202024

If YOU pre-encoded:
Your input: utm_campaign=Summer%20Sale%202024
Mailchimp encodes: utm_campaign=Summer%2520Sale%25202024
Result: Double-encoded!

The fix:

Code
❌ DON'T pre-encode:
utm_campaign=*|CAMPAIGN:SUBJECT|*

✅ DO use clean merge tag:
utm_campaign=*|CAMPAIGN:SLUG|*
(SLUG is already URL-safe)

Or clean the value:
utm_campaign=summer-sale-2024
(No encoding needed)

HubSpot Workflow Encoding

The problem:

Javascript
// HubSpot workflow action: "Create tracking URL"
 
Input (from CRM):
contact.campaign = "Webinar: Marketing Tips"
 
Workflow encodes:
encodedCampaign = "Webinar%3A%20Marketing%20Tips"
 
Your workflow template (already encoded):
"https://example.com?utm_campaign={"{"}{"{"}encodedCampaign{"}"}{"}"}}"
 
HubSpot sees % and encodes AGAIN:
Result: "...?utm_campaign=Webinar%253A%2520Marketing%2520Tips"

The fix:

Code
✅ Use raw property in workflow:
utm_campaign={"{"}{"{"}contact.campaign_slug{"}"}{"}"}}

Where campaign_slug is pre-cleaned:
"webinar-marketing-tips"

😰 Is this your only tracking issue?

This is just 1 of 40+ ways UTM tracking breaks. Most marketing teams have 8-12 critical issues they don't know about.

• 94% of sites have UTM errors

• Average: $8,400/month in wasted ad spend

• Fix time: 15 minutes with our report

✓ Connects directly to GA4 (read-only, secure)

✓ Scans 90 days of data in 2 minutes

✓ Prioritizes issues by revenue impact

✓ Shows exact sessions affected

Get Your Free Audit Report

URL Shortener Encoding

Bitly Double-Encoding Bug

The problem:

Code
Step 1: You create encoded URL
Original: https://example.com?utm_campaign=summer sale
You encode: https://example.com?utm_campaign=summer%20sale

Step 2: Pass to Bitly API
POST /v4/shorten
{
  "long_url": "https://example.com?utm_campaign=summer%20sale"
}

Step 3: Bitly "normalizes" the URL
Sees: ...utm_campaign=summer%20sale
Treats as text to be encoded
Result: ...utm_campaign=summer%2520sale

Step 4: User clicks bit.ly short link
Redirects to: https://example.com?utm_campaign=summer%2520sale
Browser decodes once: utm_campaign=summer%20sale
Analytics stores: "summer%20sale" (literal %)

The fix:

Javascript
// ❌ DON'T send encoded URLs to Bitly
const encodedURL = `https://example.com?utm_campaign=${encodeURIComponent('summer sale')}`;
await bitly.shorten(encodedURL);  // Will double-encode!
 
// ✅ DO send clean URLs
const cleanURL = 'https://example.com?utm_campaign=summer-sale';
await bitly.shorten(cleanURL);  // No encoding needed!

Marketing Automation Platform Errors

Marketo Form Encoding

The problem:

Html
<!-- Marketo form with hidden UTM fields -->
<form>
  <input type="hidden" name="utm_campaign" value="{{my.Campaign Name}}" />
</form>
 
{{my.Campaign Name}} = "Q4 Webinar Series"
 
Marketo inserts: value="Q4 Webinar Series"
Browser form-encodes: Q4+Webinar+Series
Marketo receives and re-encodes: Q4%2BWeber%2BSeries
 
Result: "Q4+Webinar+Series" in analytics (with literal +)

The fix:

Html
<!-- Use URL-safe token -->
<input type="hidden" name="utm_campaign" value="{{my.Campaign Slug}}" />
 
Where Campaign Slug = "q4-webinar-series"

Pardot URL Encoding

The problem:

Code
Pardot email template:
%%tracking_url%%?utm_campaign=%%campaign_name%%

campaign_name = "Demo Request 2024"

Pardot processes:
1. Replaces: ?utm_campaign=Demo Request 2024
2. Encodes: ?utm_campaign=Demo%20Request%202024
3. Stores this as tracking URL

When tracking link clicked:
Pardot redirects through tracker
Tracker encodes again: ?utm_campaign=Demo%2520Request%25202024

The fix:

Code
Use Pardot's URL-safe merge field:
%%tracking_url%%?utm_campaign=%%campaign_slug%%

Or set campaign_slug = "demo-request-2024" in Pardot

API Integration Errors

Zapier Multi-Step Encoding

The problem:

Code
Zap workflow:
1. Trigger: New row in Google Sheets
   Campaign: "Summer Sale"

2. Action: Format URL
   Code: `https://example.com?utm_campaign=${encodeURIComponent(campaign)}`
   Result: https://example.com?utm_campaign=Summer%20Sale

3. Action: Send to Mailchimp
   Mailchimp API receives: ...?utm_campaign=Summer%20Sale
   Mailchimp encodes: ...?utm_campaign=Summer%2520Sale

4. Analytics: "Summer%20Sale" (literal)

The fix:

Javascript
// Step 2: Don't encode, just clean
function cleanCampaign(value) {
  return value
    .toLowerCase()
    .replace(/\s+/g, '-')
    .replace(/[^a-z0-9-_]/g, '');
}
 
// Use: cleanCampaign("Summer Sale") → "summer-sale"
// No encoding needed anywhere!

Custom API Script Error

The problem:

Python
# Python script sending to API
 
import requests
from urllib.parse import urlencode
 
# Create UTM parameters
params = {
    'utm_campaign': 'Summer Sale'
}
 
# Encode manually
encoded_params = urlencode(params)
# Result: 'utm_campaign=Summer+Sale'
 
# Pass to email API
url = f"https://example.com?`{"{"}{"{"}encoded_params{"}"}{"}"}}`"
response = requests.get(url)
# requests library encodes AGAIN
# Final: utm_campaign=Summer%2BSale
 
# Analytics shows: "Summer+Sale" (literal +)

The fix:

Python
# ❌ DON'T encode before passing
params = {'utm_campaign': 'Summer Sale'}
encoded = urlencode(params)  # Encoded once
requests.get(url, params=encoded)  # Encoded twice!
 
# ✅ DO use clean values
params = {'utm_campaign': 'summer-sale'}
requests.get(url, params=params)  # No encoding needed

Detection: Is Your Automation Double-Encoding?

Test Script

Javascript
async function testAutomationEncoding(automationTool, testCampaign) {
  console.log(`\nTesting: ${automationTool.name}`);
  console.log(`Input: "${"{"}{"{"}testCampaign{"}"}{"}"}}"`);
 
  // Step 1: Submit to automation
  const url = await automationTool.generateURL({
    utm_campaign: testCampaign
  });
 
  console.log(`Generated URL: ${"{"}{"{"}url{"}"}{"}"}}`);
 
  // Step 2: Parse result
  const urlObj = new URL(url);
  const campaign = urlObj.searchParams.get('utm_campaign');
 
  console.log(`Campaign parameter: "${"{"}{"{"}campaign{"}"}{"}"}}"`);
 
  // Step 3: Check for encoding
  if (campaign.includes('%')) {
    // Try decoding
    const decoded = decodeURIComponent(campaign);
    console.log(`Decoded once: "${"{"}{"{"}decoded{"}"}{"}"}}"`);
 
    if (decoded !== campaign) {
      // Check if double-encoded
      const decodedTwice = decodeURIComponent(decoded);
      if (decodedTwice !== decoded) {
        console.log(`❌ DOUBLE-ENCODING DETECTED!`);
        console.log(`Original input: "${"{"}{"{"}testCampaign{"}"}{"}"}}"`);
        console.log(`After automation: "${"{"}{"{"}campaign{"}"}{"}"}}"`);
        console.log(`Decoded once: "${"{"}{"{"}decoded{"}"}{"}"}}"`);
        console.log(`Decoded twice: "${"{"}{"{"}decodedTwice{"}"}{"}"}}"`);
        return {
          tool: automationTool.name,
          doubleEncoded: true,
          evidence: { input: testCampaign, output: campaign, decoded, decodedTwice }
        };
      }
    }
 
    console.log(`⚠️ Single-encoded (should use clean values instead)`);
    return {
      tool: automationTool.name,
      doubleEncoded: false,
      singleEncoded: true
    };
  }
 
  console.log(`✅ No encoding (good!)`);
  return {
    tool: automationTool.name,
    doubleEncoded: false,
    singleEncoded: false
  };
}
 
// Test your automation
const testResults = await testAutomationEncoding(mailchimpAdapter, 'Summer Sale 2024');

Platform-Specific Tests

Email platforms:

Code
1. Create test campaign
2. Use merge tag: [CAMPAIGN NAME]
3. Set campaign name: "Test Campaign"
4. Send test email to yourself
5. Check URL in email HTML source
6. Look for %20, %2520, or + characters

URL shorteners:

Javascript
// Test Bitly
const testURL = 'https://example.com?utm_campaign=test-campaign';
const shortLink = await bitly.shorten(testURL);
const destination = await bitly.getDestination(shortLink);
 
console.log('Input:', testURL);
console.log('Destination:', destination);
 
if (destination !== testURL) {
  console.log('❌ URL changed! Check for encoding differences.');
}

Marketing automation:

Code
1. Create test workflow
2. Set variable: campaign = "Test Value"
3. Generate URL with: {`{"{"}{"{"}campaign{"}"}{"}"}}`}
4. Log URL at each step
5. Check final output for encoding

Prevention Strategies

1. Clean Values Only

Javascript
// Universal rule: Never encode values yourself
 
// ❌ DON'T:
const campaign = encodeURIComponent('Summer Sale');
 
// ✅ DO:
const campaign = 'summer-sale';
 
// Let tools handle encoding if needed (they usually won't need to)

2. Platform Configuration

Mailchimp:

Code
Settings → Campaign Defaults
✅ Enable: "Use URL-safe campaign names"
✅ Set default: utm_campaign=*|CAMPAIGN:SLUG|*

HubSpot:

Code
Marketing → Email → Settings
✅ Use: Smart fields (pre-cleaned)
❌ Avoid: Raw contact properties in URLs

Bitly:

Code
API Settings
✅ Send: Un-encoded destination URLs
✅ Expect: Bitly handles encoding if needed

3. Validation at Each Step

Javascript
function validateNoEncoding(url, stepName) {
  if (url.match(/\?.*%[0-9A-Fa-f]{2}/)) {
    throw new Error(`Encoding detected at step: ${"{"}{"{"}stepName{"}"}{"}"}}\nURL: ${"{"}{"{"}url{"}"}{"}"}}`);
  }
 
  return url;
}
 
// Use between automation steps
let url = generateBaseURL();
url = validateNoEncoding(url, 'Initial generation');
 
url = addToEmailTemplate(url);
url = validateNoEncoding(url, 'After email template');
 
url = shortenURL(url);
url = validateNoEncoding(url, 'After shortening');

4. End-to-End Testing

Javascript
async function testCompleteWorkflow() {
  const testCampaign = 'test-automation-encoding';
 
  // Generate URL
  const url = buildURL({ utm_campaign: testCampaign });
 
  // Step through automation
  const emailURL = await emailPlatform.process(url);
  const shortURL = await urlShortener.create(emailURL);
  const finalURL = await urlShortener.resolve(shortURL);
 
  // Validate final result
  const finalCampaign = new URL(finalURL).searchParams.get('utm_campaign');
 
  if (finalCampaign !== testCampaign) {
    throw new Error(`Workflow changed campaign value!\nExpected: ${"{"}{"{"}testCampaign{"}"}{"}"}}\nGot: ${"{"}{"{"}finalCampaign{"}"}{"}"}}`);
  }
 
  console.log('✅ Workflow validated successfully');
}

Common Automation Platforms

How Each Handles Encoding

PlatformDefault BehaviorFix
MailchimpAuto-encodes valuesUse *|CAMPAIGN:SLUG|*
HubSpotEncodes raw propertiesUse smart fields
MarketoForm-encodes hidden fieldsPre-clean values
PardotDouble-encodes on redirectUse slug fields
BitlyEncodes destination URLSend clean URLs
ZapierEach step may encodeClean values, no encoding
ActiveCampaignAuto-encodes in linksUse personalization slugs
Constant ContactEncodes merge fieldsClean campaign names

✅ Fixed this issue? Great! Now check the other 39...

You just fixed one tracking issue. But are your Google Ads doubling sessions? Is Facebook attribution broken? Are internal links overwriting campaigns?

Connects to GA4 (read-only, OAuth secured)

Scans 90 days of traffic in 2 minutes

Prioritizes by revenue impact

Free forever for monthly audits

Run Complete UTM Audit (Free Forever)

Join 2,847 marketers fixing their tracking daily

FAQ

Q: Why do marketing tools double-encode?

A: Most tools assume you're passing raw text that needs encoding. If you pass already-encoded text, they encode it again. The solution: pass clean values that don't need encoding.

Q: Can I disable encoding in my automation platform?

A: Most platforms don't offer this option. Instead, use their "URL-safe" or "slug" fields, which are pre-cleaned and won't be encoded again.

Q: How do I test if my automation double-encodes?

A: Send a test with a space in the campaign name. Check the final URL. If you see %2520, you have double-encoding. If you see %20, you have single-encoding (also suboptimal).

Q: What if I need to pass URLs through multiple systems?

A: Use clean values that never need encoding: lowercase letters, numbers, and hyphens only. Then it doesn't matter how many systems touch the URL.

Q: Should I encode before or after automation?

A: Neither. Don't encode at all. Use clean values: summer-sale-2024 instead of Summer Sale 2024.

Q: Can I fix automation double-encoding without changing my workflow?

A: No. You must fix at the source (clean values) or change how your automation processes URLs. There's no downstream fix that doesn't involve workflow changes.

Q: What's the safest way to integrate with APIs?

A: Pass clean parameter values directly. Don't pre-encode, don't pre-format. Let the API library handle any necessary encoding.

Q: How often should I test my automation?

A: After any workflow changes, platform updates, or integration additions. Also run monthly spot-checks on live campaigns.


Stop automation from breaking your campaign tracking. UTMGuard integrates with your marketing tools to detect and prevent double-encoding before URLs go live. Start your free audit today.

UTM

Get Your Free Audit in 60 Seconds

Connect GA4, run the scan, and see exactly where tracking is leaking budget. No credit card required.

Trusted by growth teams and agencies to keep attribution clean.