Fix Plus Sign UTM Error: Replace + with %2B or Alternative

UTMGuard Team
5 min readtroubleshooting

Your UTM has a + sign. GA4 shows inconsistent values across sessions.

Here's the 3-step fix to encode + correctly and restore consistent 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

❌ INCONSISTENT:
?utm_campaign=google+ads

GA4 shows randomly:
- "google ads" (+ decoded as space)
- "google+ads" (+ kept as +)

One URL, two different campaign values

Quick Fix (3 Steps)

Step 1: Decide on Approach (30 seconds)

Choose one:

Option A: Encode + as %2B
→ Preserves + symbol in GA4

Option B: Replace with hyphen
→ Simpler, no encoding

Option C: Remove +
→ Shortest option

Step 2: Apply Fix (60 seconds)

Option A: Encode as %2B

❌ BEFORE:
?utm_campaign=google+ads

✅ AFTER:
?utm_campaign=google%2Bads

GA4 shows: "google+ads"

Option B: Replace with Hyphen

❌ BEFORE:
?utm_campaign=google+ads

✅ AFTER:
?utm_campaign=google-ads

GA4 shows: "google-ads"

Option C: Remove +

❌ BEFORE:
?utm_campaign=google+ads

✅ AFTER:
?utm_campaign=googleads

GA4 shows: "googleads"

Step 3: Test (30 seconds)

1. Visit fixed URL
2. Check browser console:
   new URL(location.href).searchParams.get('utm_campaign')
3. Verify consistent value
4. Check GA4 Real-Time

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 Script

function fixPlusSign(url, method = 'encode') {
    const urlObj = new URL(url);
 
    ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'].forEach(key => {
        let value = urlObj.searchParams.get(key);
 
        if (value && value.includes('+')) {
            switch(method) {
                case 'encode':
                    // Encode + as %2B
                    value = value.replace(/\+/g, '%2B');
                    break;
                case 'hyphen':
                    // Replace + with -
                    value = value.replace(/\+/g, '-');
                    break;
                case 'remove':
                    // Remove + entirely
                    value = value.replace(/\+/g, '');
                    break;
            }
 
            urlObj.searchParams.set(key, value);
        }
    });
 
    return urlObj.toString();
}
 
// Usage
const broken = 'site.com?utm_campaign=google+ads';
 
console.log(fixPlusSign(broken, 'encode'));
// site.com?utm_campaign=google%2Bads
 
console.log(fixPlusSign(broken, 'hyphen'));
// site.com?utm_campaign=google-ads
 
console.log(fixPlusSign(broken, 'remove'));
// site.com?utm_campaign=googleads

Common Scenarios & Fixes

Scenario 1: Product Names

Product: C++ Programming

❌ INCONSISTENT:
utm_content=C++

✅ FIX Option 1:
utm_content=C%2B%2B
→ GA4: "C++"

✅ FIX Option 2:
utm_content=cpp
→ GA4: "cpp"

Scenario 2: Brand Names

Brand: Google+

❌ INCONSISTENT:
utm_source=google+

✅ FIX Option 1:
utm_source=google%2B
→ GA4: "google+"

✅ FIX Option 2:
utm_source=googleplus
→ GA4: "googleplus"

Scenario 3: Multiple + Symbols

Campaign: C++ for C# Developers

❌ INCONSISTENT:
utm_campaign=c++for-c#-devs

✅ FIX:
utm_campaign=cpp-for-csharp-devs
→ Simple, readable, no encoding

Bulk Fix Script

// Fix multiple URLs at once
function bulkFixPlusSign(urls, method = 'encode') {
    return urls.map(url => {
        try {
            return fixPlusSign(url, method);
        } catch (error) {
            console.error(`Failed to fix: ${"{"}{"{"}url{"}"}{"}"}}`, error);
            return url;
        }
    });
}
 
// Usage
const urls = [
    'site.com?utm_campaign=google+ads',
    'site.com?utm_source=bing+search',
    'site.com?utm_content=c++'
];
 
const fixed = bulkFixPlusSign(urls, 'encode');
console.log(fixed);
// All + encoded as %2B

Platform-Specific Application

Tracking Template:
`{"{"}{"{"}lpurl{"}"}{"}"}}`?utm_campaign=google%2Bads&gclid=`{"{"}{"{"}gclid{"}"}{"}"}}`
                          ↑
                    Encode + as %2B

Facebook Ads

URL Parameters:
utm_source=facebook&utm_campaign=product%2Bads
                                      ↑
                                Encode + as %2B

Email HTML

<a href="site.com?utm_campaign=product%2Bpromo&utm_source=email">
    Shop Now
</a>

Validation After Fix

function validatePlusFix(url) {
    const urlObj = new URL(url);
    const rawQuery = url.split('?')[1] || '';
 
    // Check if any unencoded + remains in UTM values
    const utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
 
    const issues = utmParams
        .filter(param => {
            const paramPattern = new RegExp(`${"{"}{"{"}param{"}"}{"}"}}=([^&]*)`);
            const match = rawQuery.match(paramPattern);
            return match && match[1].includes('+') && !match[1].includes('%2B');
        })
        .map(param => ({
            parameter: param,
            issue: 'Contains unencoded +'
        }));
 
    return {
        valid: issues.length === 0,
        issues
    };
}
 
// Usage
const url = 'site.com?utm_campaign=google%2Bads';
const result = validatePlusFix(url);
 
if (result.valid) {
    console.log('✅ All + signs properly encoded');
} else {
    console.log('❌ Issues found:', result.issues);
}

Decision Matrix

Original ValueMethodResultWhen to Use
google+adsEncodegoogle%2BadsNeed to preserve +
google+adsHyphengoogle-adsDon't need +
google+adsRemovegoogleadsShort URLs needed
C++EncodeC%2B%2BBrand/product name
C++ReplacecppAbbreviation OK

Testing Checklist

After fixing:

✅ Visual check
   URL contains %2B (or alternative), not raw +

✅ Browser test
   new URL('url').searchParams.get('utm_campaign')
   Shows consistent value

✅ Cross-browser test
   Chrome, Firefox, Safari, Mobile
   All show same value

✅ GA4 Real-Time test
   Campaign appears with expected value
   No data fragmentation

✅ 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

Should I always encode + as %2B?

If you need literal + in GA4, yes. Otherwise, consider simpler alternatives (hyphen, remove).

What if + appears multiple times?

Encode or replace ALL occurrences:

value.replace(/\+/g, '%2B') // All + → %2B

Will this break existing campaigns?

If changing mid-campaign, you'll create new campaign value in GA4. Better to fix before launch.

Can I use + for spaces?

Not recommended. Use %20 or underscores for better reliability.

Conclusion

Fix + in UTM parameters in 3 steps:

  1. Choose approach: encode, replace, or remove
  2. Apply fix using script or manual edit
  3. Test in browser and GA4
❌ utm_campaign=google+ads (inconsistent)
✅ utm_campaign=google%2Bads (encoded)
✅ utm_campaign=google-ads (alternative)

Encode + as %2B for consistent tracking across all platforms.


Technical Reference: Plus Sign in Value Validation Rule