Fix Duplicate UTM Params: Remove Redundant Parameters in 3 Steps

UTMGuard Team
5 min readtroubleshooting

Your URL has utm_source=facebook appearing twice. GA4 tracking is unpredictable.

Here's the 3-step fix to remove duplicates and restore reliable tracking.

🚨 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

The Problem

❌ DUPLICATE:
?utm_source=facebook&utm_medium=cpc&utm_source=instagram
 ↑                                   ↑
 Same parameter twice

Result: GA4 behavior unpredictable

Quick Fix (3 Steps)

Step 1: Find Which Value to Keep (60 seconds)

Look at your URL:
?utm_source=facebook&utm_medium=cpc&utm_source=instagram

Ask: Which value is correct?
- facebook (first occurrence)?
- instagram (last occurrence)?
- Neither (need different value)?

Decision determines which to keep

Step 2: Remove Duplicate (30 seconds)

❌ BEFORE:
?utm_source=facebook&utm_medium=cpc&utm_source=instagram

✅ AFTER (keeping first):
?utm_source=facebook&utm_medium=cpc

✅ AFTER (keeping last):
?utm_source=instagram&utm_medium=cpc

Manual edit: Delete the incorrect parameter occurrence.

Step 3: Verify in GA4 Real-Time (30 seconds)

1. Visit corrected URL
2. Open GA4 → Realtime
3. Check "Traffic acquisition"
4. Verify source shows single correct value

Done.

😰 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

Automated Fix (JavaScript)

For Single URL

function removeDuplicateUtm(url, keepFirst = true) {
    const urlObj = new URL(url);
    const params = new URLSearchParams();
    const seen = new Set();
 
    for (const [key, value] of urlObj.searchParams.entries()) {
        if (!seen.has(key)) {
            params.append(key, value);
            seen.add(key);
        } else if (!keepFirst) {
            // Update to last value if keepFirst=false
            params.set(key, value);
        }
    }
 
    urlObj.search = params.toString();
    return urlObj.toString();
}
 
// Usage
const broken = 'https://site.com?utm_source=facebook&utm_campaign=spring&utm_source=instagram';
 
// Keep first occurrence
console.log(removeDuplicateUtm(broken, true));
// Output: https://site.com?utm_source=facebook&utm_campaign=spring
 
// Keep last occurrence
console.log(removeDuplicateUtm(broken, false));
// Output: https://site.com?utm_source=instagram&utm_campaign=spring

For Multiple URLs (Batch Processing)

function batchFixDuplicates(urls) {
    return urls.map(url => {
        try {
            return removeDuplicateUtm(url, true);
        } catch (error) {
            console.error(`Failed to process: ${"{"}{"{"}url{"}"}{"}"}}`, error);
            return url; // Return original if fix fails
        }
    });
}
 
// Usage
const brokenUrls = [
    'site.com?utm_source=fb&utm_source=ig',
    'site.com?s=email&utm_campaign=a&utm_campaign=b',
    'site.com?utm_medium=cpc&other=x&utm_medium=paid'
];
 
const fixed = batchFixDuplicates(brokenUrls);
console.log(fixed);
// All duplicates removed, first occurrence kept

Browser Console Quick Fix

// Paste this in browser console when on the broken URL
(function() {
    const url = new URL(window.location.href);
    const params = new URLSearchParams();
    const seen = new Set();
 
    for (const [key, value] of url.searchParams.entries()) {
        if (!seen.has(key)) {
            params.append(key, value);
            seen.add(key);
        }
    }
 
    url.search = params.toString();
    window.location.href = url.toString();
})();
 
// Automatically redirects to cleaned URL

Platform-Specific Fixes

Problem: Value Tracking template duplicates UTMs

Fix:
1. Final URL: https://site.com?utm_source=google&utm_medium=cpc
2. Tracking template: `{"{"}{"{"}lpurl{"}"}{"}"}}`?gclid=`{"{"}{"{"}gclid{"}"}{"}"}}`
   (Don't add utm_source again in tracking template)

✅ Result: site.com?utm_source=google&utm_medium=cpc&gclid=123

Facebook Ads

Problem: URL Parameters field duplicates existing UTMs

Fix:
1. Destination URL: https://site.com?utm_source=facebook
2. URL Parameters: utm_medium=paid&utm_campaign=spring
   (Don't repeat utm_source)

✅ Result: site.com?utm_source=facebook&utm_medium=paid&utm_campaign=spring

Email Platforms (Mailchimp, Klaviyo)

Problem: Template concatenation duplicates parameters

Fix:
Check if base URL has UTMs before adding:

❌ WRONG:
<a href="{`{"{"}{"{"}landing_page{"}"}{"}"}}`}?utm_source=email&utm_campaign={"{"}{"{"}campaign_name{"}"}{"}"}}">
     If landing_page already has utm_source, you get duplicates

✅ RIGHT:
Use platform's merge tags correctly, or ensure landing_page is clean base URL

Common Patterns

Pattern 1: First Correct, Second Wrong

?utm_source=facebook&utm_campaign=spring&utm_source=social

Fix: Remove second utm_source
Result: ?utm_source=facebook&utm_campaign=spring

Pattern 2: First Wrong, Second Correct

?utm_source=website&utm_campaign=spring&utm_source=facebook

Fix: Remove first utm_source
Result: ?utm_source=facebook&utm_campaign=spring

Or manually reorder:
?utm_source=facebook&utm_campaign=spring

Pattern 3: Both Wrong

?utm_source=abc&utm_campaign=spring&utm_source=xyz

Fix: Remove both, add correct value
Result: ?utm_source=facebook&utm_campaign=spring

Pattern 4: Multiple Duplicates

?utm_source=a&utm_source=b&utm_campaign=x&utm_campaign=y&utm_source=c

Fix: Remove all duplicates systematically
Result: ?utm_source=a&utm_campaign=x
(Keeps first occurrence of each)

Validation After Fix

// Verify no duplicates remain
function verifyNoDuplicates(url) {
    const params = new URL(url).searchParams;
    const counts = {};
 
    for (const [key] of params.entries()) {
        counts[key] = (counts[key] || 0) + 1;
    }
 
    const duplicates = Object.entries(counts)
        .filter(([, count]) => count > 1)
        .map(([key]) => key);
 
    if (duplicates.length > 0) {
        console.error('❌ Duplicates still exist:', duplicates);
        return false;
    }
 
    console.log('✅ No duplicates found');
    return true;
}
 
// Usage
const url = 'https://site.com?utm_source=facebook&utm_campaign=spring';
verifyNoDuplicates(url);
// ✅ No duplicates found

Prevention (After Fixing)

1. Use URLSearchParams .set() Method

// ✅ CORRECT: .set() replaces instead of duplicating
const url = new URL('https://site.com');
url.searchParams.set('utm_source', 'facebook');
url.searchParams.set('utm_medium', 'cpc');
 
// If you call .set() again with same key, it replaces:
url.searchParams.set('utm_source', 'instagram'); // Replaces 'facebook'
 
console.log(url.toString());
// https://site.com?utm_source=instagram&utm_medium=cpc

2. Check Before Adding

// ✅ CORRECT: Check existence before appending
function safeAddUtm(url, key, value) {
    const urlObj = new URL(url);
 
    if (urlObj.searchParams.has(key)) {
        console.warn(`${"{"}{"{"}key{"}"}{"}"}} already exists, replacing...`);
        urlObj.searchParams.set(key, value);
    } else {
        urlObj.searchParams.append(key, value);
    }
 
    return urlObj.toString();
}

3. Validate Before Launch

// Add to pre-launch checklist
function preLaunchCheck(url) {
    const checks = [];
 
    // Check for duplicates
    const params = new URL(url).searchParams;
    const utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
 
    utmParams.forEach(param => {
        const count = params.getAll(param).length;
        if (count > 1) {
            checks.push(`❌ Duplicate ${"{"}{"{"}param{"}"}{"}"}} (${"{"}{"{"}count{"}"}{"}"}} occurrences)`);
        } else if (count === 1) {
            checks.push(`✅ ${"{"}{"{"}param{"}"}{"}"}} OK`);
        }
    });
 
    return checks;
}

✅ 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

Which value should I keep if both are different?

Choose the value that matches your campaign intent. If utm_source=facebook and utm_source=instagram, keep the one matching where the link is actually placed.

Can I use regex to fix duplicates?

URLSearchParams is safer. Regex can break if URL structure varies.

What if the duplicate has the same value?

?utm_source=facebook&utm_campaign=spring&utm_source=facebook

Still remove one. Having duplicates, even with same value, can cause parsing inconsistencies.

How do I prevent this in URL builders?

Use .set() instead of .append() in URLSearchParams. .set() automatically replaces duplicates.

Conclusion

Fix duplicate UTM parameters in 3 steps:

  1. Identify which value to keep (first, last, or neither)
  2. Remove duplicate parameter
  3. Verify in GA4 Real-Time

Prevention: Use URLSearchParams.set() method, which replaces instead of duplicating.

url.searchParams.set('utm_source', 'facebook'); // Never creates duplicates

Technical Reference: Duplicate UTM Parameters Validation Rule