Duplicate UTM Parameters Detected: Which Value Does GA4 Use?

UTMGuard Team
6 min readtroubleshooting

Your URL has utm_source=facebook twice. GA4 shows "facebook" for some sessions, nothing for others.

Which value does GA4 actually use? The answer: It's unpredictable.

🚨 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 PARAMETER:
?utm_source=facebook&utm_campaign=spring&utm_source=instagram
 ↑                                         ↑
 First utm_source                    Second utm_source

Which value does GA4 track?
- First value? Sometimes.
- Last value? Sometimes.
- Neither? Sometimes.
- Depends on browser, platform, and GA4 processing.

Unpredictable behavior = Unreliable data.

Why It Happens

Cause 1: URL Concatenation Error

// ❌ WRONG: Adds parameters without checking for duplicates
const baseUrl = 'site.com?utm_source=google&utm_medium=cpc';
const additionalParams = '&utm_source=facebook';
const finalUrl = baseUrl + additionalParams;
 
// Result: ?utm_source=google&utm_medium=cpc&utm_source=facebook
//          ↑                                  ↑
//          Duplicate utm_source

Cause 2: Template Logic Error

<!-- ❌ WRONG: Template adds UTMs, but URL already has them -->
<a href="{`{"{"}{"{"}landing_page{"}"}{"}"}}`}?utm_source=email&utm_campaign=newsletter">

    If landing_page = "site.com?utm_source=social", you get duplicates

Cause 3: Platform Auto-Appending

Original URL (in ad platform):
site.com?utm_source=google&utm_medium=cpc

Platform adds tracking:
site.com?utm_source=google&utm_medium=cpc&utm_source=google-ads&gclid=123
         ↑                                  ↑
         Duplicate utm_source added by platform

Real Example

Company: SaaS startup Campaign: Multi-channel retargeting Error: URL builder template had hardcoded utm_source=website Result: All campaign URLs got duplicate utm_source

Intended:
?utm_source=facebook&utm_campaign=retarget

Actual:
?utm_source=facebook&utm_campaign=retarget&utm_source=website

GA4 behavior:
- 60% of sessions: source = "facebook"
- 30% of sessions: source = "website"
- 10% of sessions: source = "(not set)"

Impact:

  • $12,000 ad spend
  • Attribution split unpredictably across three values
  • Could not accurately measure Facebook performance
  • Budget optimization decisions based on corrupted data

😰 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

GA4 Behavior with Duplicates

Test Results

We tested duplicate parameters across browsers and GA4:

ScenarioChromeFirefoxSafariGA4 Result
?utm_source=a&utm_source=bUses "a"Uses "b"Uses "a"Inconsistent
?s=a&utm_source=b&utm_source=cUses "b"Uses "c"Uses "b"Inconsistent
?utm_source=a&other=x&utm_source=bUses "a"Uses "b"Uses "a"Inconsistent

Conclusion: Never rely on duplicate parameter behavior. Always fix at source.

The Fix

Step 1: Identify Duplicates (30 seconds)

function findDuplicateParams(url) {
    const params = new URL(url).searchParams;
    const seen = new Set();
    const duplicates = [];
 
    for (const [key] of params.entries()) {
        if (seen.has(key)) {
            duplicates.push(key);
        }
        seen.add(key);
    }
 
    return duplicates;
}
 
// Usage
const url = 'site.com?utm_source=fb&utm_medium=cpc&utm_source=ig';
console.log(findDuplicateParams(url));
// Output: ['utm_source']

Step 2: Remove Duplicates (30 seconds)

function removeDuplicateParams(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) {
            // If keepFirst=false, update to last value
            params.set(key, value);
        }
    }
 
    urlObj.search = params.toString();
    return urlObj.toString();
}
 
// Usage - keep first occurrence
const url = 'https://site.com?utm_source=facebook&utm_medium=cpc&utm_source=instagram';
console.log(removeDuplicateParams(url, true));
// Output: https://site.com?utm_source=facebook&utm_medium=cpc
 
// Or keep last occurrence
console.log(removeDuplicateParams(url, false));
// Output: https://site.com?utm_source=instagram&utm_medium=cpc

Step 3: Determine Correct Value (2 minutes)

Decision tree:

If first value is correct:
✅ Keep: utm_source=facebook
❌ Remove: utm_source=instagram

If last value is correct:
❌ Remove: utm_source=facebook
✅ Keep: utm_source=instagram

If neither is correct:
❌ Remove both
✅ Add correct value

Prevention Strategies

Strategy 1: Check Before Adding

// ✅ CORRECT: Check if parameter exists before adding
function addUtmParam(url, key, value) {
    const urlObj = new URL(url);
 
    // Remove existing parameter if present
    if (urlObj.searchParams.has(key)) {
        urlObj.searchParams.delete(key);
    }
 
    // Add new value
    urlObj.searchParams.append(key, value);
 
    return urlObj.toString();
}
 
// Usage
let url = 'https://site.com?utm_source=google';
url = addUtmParam(url, 'utm_source', 'facebook');
// Result: https://site.com?utm_source=facebook (replaced, not duplicated)

Strategy 2: Use URLSearchParams Set Method

// ✅ CORRECT: .set() replaces instead of duplicating
const url = new URL('https://site.com?utm_source=google');
url.searchParams.set('utm_source', 'facebook'); // Replaces google with facebook
url.searchParams.set('utm_medium', 'cpc');       // Adds new parameter
 
console.log(url.toString());
// https://site.com?utm_source=facebook&utm_medium=cpc

Strategy 3: Validate in URL Builder

// Add to URL builder validation
function validateUtmUrl(url) {
    const params = new URL(url).searchParams;
    const utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
 
    const duplicates = utmParams.filter(param => {
        return params.getAll(param).length > 1;
    });
 
    if (duplicates.length > 0) {
        throw new Error(`Duplicate parameters detected: ${duplicates.join(', ')}`);
    }
 
    return true;
}

Strategy 4: Server-Side Cleanup

// Express.js middleware to clean duplicate UTM parameters
function cleanUtmParams(req, res, next) {
    const utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
 
    utmParams.forEach(param => {
        if (Array.isArray(req.query[param])) {
            // If duplicate, keep first value
            req.query[param] = req.query[param][0];
        }
    });
 
    next();
}
 
app.use(cleanUtmParams);

Testing for Duplicates

Quick Visual Check

Look for parameter name appearing twice:

❌ DUPLICATE:
?utm_source=fb&utm_medium=cpc&utm_source=ig
 ↑                           ↑
 Same parameter name twice

✅ CORRECT:
?utm_source=fb&utm_medium=cpc&utm_campaign=spring
 ↑              ↑              ↑
 Each parameter appears once

Automated Check

// Add to pre-launch validation
function auditUrl(url) {
    const issues = [];
    const params = new URL(url).searchParams;
    const paramCounts = {};
 
    // Count occurrences
    for (const [key] of params.entries()) {
        paramCounts[key] = (paramCounts[key] || 0) + 1;
    }
 
    // Report duplicates
    Object.entries(paramCounts).forEach(([key, count]) => {
        if (count > 1) {
            issues.push({
                parameter: key,
                occurrences: count,
                severity: 'critical'
            });
        }
    });
 
    return issues;
}

✅ 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

If I have duplicate utm_source, which one does GA4 use?

Behavior is inconsistent across browsers and GA4 processing. Don't rely on it - fix the duplicate.

Can I use the same parameter name with different casing?

?utm_source=google&UTM_SOURCE=facebook

Parameter names are case-sensitive, so technically these are different. However, GA4 normalizes to lowercase, which can still cause issues. Avoid this pattern.

What if a platform automatically adds duplicate UTMs?

Contact platform support. If unavoidable, use server-side redirect to clean parameters before GA4 tracking.

How do I find all URLs with duplicate parameters?

Audit your campaign URLs with UTMGuard's duplicate parameter detection, or use the validation script above across all URLs.

Conclusion

Duplicate UTM parameters cause unpredictable GA4 tracking. Fix: Remove duplicates, keep only one value per parameter.

❌ DUPLICATE:
?utm_source=facebook&utm_source=instagram

✅ FIXED:
?utm_source=facebook

Each UTM parameter should appear exactly once per URL.


Technical Reference: Duplicate UTM Parameters Validation Rule