URL Special Characters Guide: Complete Encoding Reference for UTM
Special characters in URLs break tracking if not encoded correctly.
This is your complete reference for encoding special characters in UTM parameters.
🚨 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
Reserved Characters (Must Encode in Values)
These characters have special meaning in URLs. When used in UTM parameter values, they MUST be encoded:
| Character | Purpose | Encoded | Example Value → Encoded |
|---|---|---|---|
| Space | Whitespace | %20 | "spring sale" → spring%20sale |
| & | Parameter separator | %26 | "save&win" → save%26win |
| = | Key-value separator | %3D | "2+2=4" → 2%2B2%3D4 |
| ? | Query start | %3F | "what?" → what%3F |
| # | Fragment identifier | %23 | "#1 brand" → %231%20brand |
| % | Encoding prefix | %25 | "20% off" → 20%25%20off |
| + | Space alternative | %2B | "google+ads" → google%2Bads |
| / | Path separator | %2F | "web/mobile" → web%2Fmobile |
Why These Characters Are Reserved
& (Ampersand)
✅ CORRECT USAGE (separator):
?utm_source=facebook&utm_medium=cpc
↑
Separates parameters
❌ WRONG (in value, unencoded):
?utm_campaign=buy&save
↑
Breaks parameter parsing
✅ RIGHT (in value, encoded):
?utm_campaign=buy%26save
= (Equals)
✅ CORRECT USAGE (key-value separator):
?utm_source=facebook
↑
Assigns value to key
❌ WRONG (in value, unencoded):
?utm_campaign=2+2=4
↑
Confuses parser
✅ RIGHT (in value, encoded):
?utm_campaign=2%2B2%3D4
? (Question Mark)
✅ CORRECT USAGE (query start):
https://site.com?utm_source=google
↑
Starts query string
❌ WRONG (in value, unencoded):
?utm_campaign=what?
↑
Breaks URL structure
✅ RIGHT (in value, encoded):
?utm_campaign=what%3F
# (Hash/Fragment)
✅ CORRECT USAGE (fragment):
?utm_source=facebook#section
↑
Marks fragment
❌ WRONG (in value, unencoded):
?utm_campaign=#1offer
↑
Terminates query string
✅ RIGHT (in value, encoded):
?utm_campaign=%231offer
😰 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
Unsafe Characters (Always Encode)
These characters should be encoded even though they might work unencoded:
| Character | Encoded | Why Unsafe |
|---|---|---|
| < | %3C | HTML/XML conflict |
| > | %3E | HTML/XML conflict |
| " | %22 | Attribute delimiter |
| ' | %27 | String delimiter |
| | | %7C | Reserved |
| \ | %5C | Path separator |
| ^ | %5E | Reserved |
| [ | %5B | Reserved |
| ] | %5D | Reserved |
| { | %7B | Reserved |
| } | %7D | Reserved |
| ` | %60 | Reserved |
Safe Characters (No Encoding Needed)
These can be used directly in UTM parameters:
SAFE: A-Z a-z 0-9 - _ . ~
Examples:
✅ utm_campaign=spring-sale-2024
✅ utm_source=my_email_list
✅ utm_medium=social.paid
✅ utm_content=banner~1
No encoding required
Common Scenarios
Scenario 1: Campaign Names with Spaces
Original: "Spring Sale 2024"
❌ WRONG:
utm_campaign=Spring Sale 2024
✅ RIGHT Option 1 (encode):
utm_campaign=Spring%20Sale%202024
✅ RIGHT Option 2 (underscores):
utm_campaign=Spring_Sale_2024
✅ RIGHT Option 3 (hyphens):
utm_campaign=spring-sale-2024
Scenario 2: Promotional Copy with &
Original: "Buy 1 & Get 1 Free"
❌ WRONG:
utm_campaign=Buy 1 & Get 1 Free
✅ RIGHT Option 1 (encode):
utm_campaign=Buy%201%20%26%20Get%201%20Free
✅ RIGHT Option 2 (replace):
utm_campaign=Buy-1-and-Get-1-Free
✅ RIGHT Option 3 (abbreviate):
utm_campaign=buy1get1free
Scenario 3: Percentages
Original: "20% Off"
❌ WRONG:
utm_campaign=20% Off
✅ RIGHT Option 1 (encode):
utm_campaign=20%25%20Off
✅ RIGHT Option 2 (replace):
utm_campaign=20pct-off
✅ RIGHT Option 3 (remove):
utm_campaign=20off
Scenario 4: Questions/Exclamations
Original: "Why wait?"
❌ WRONG:
utm_campaign=Why wait?
✅ RIGHT Option 1 (encode):
utm_campaign=Why%20wait%3F
✅ RIGHT Option 2 (remove):
utm_campaign=why-wait
Scenario 5: Dates with Slashes
Original: "2024/01/15"
❌ WRONG:
utm_content=2024/01/15
✅ RIGHT Option 1 (encode):
utm_content=2024%2F01%2F15
✅ RIGHT Option 2 (replace):
utm_content=2024-01-15
✅ RIGHT Option 3 (remove):
utm_content=20240115
Scenario 6: Email Addresses
Original: "user@example.com"
❌ PROBLEMATIC:
utm_content=user@example.com
✅ RIGHT Option 1 (encode):
utm_content=user%40example.com
✅ RIGHT Option 2 (hash):
utm_content=user_12ab34cd
(hash or anonymize for privacy)
Encoding Methods
JavaScript: encodeURIComponent()
// ✅ RECOMMENDED for UTM values
const value = "Spring Sale & Save 20%!";
const encoded = encodeURIComponent(value);
console.log(encoded);
// Spring%20Sale%20%26%20Save%2020%25!
// Build URL
const url = `https://site.com?utm_campaign=${"{"}{"{"}encoded{"}"}{"}"}}`;JavaScript: URLSearchParams
// ✅ AUTOMATIC encoding
const params = new URLSearchParams();
params.set('utm_campaign', 'Spring Sale & Save 20%!');
const url = `https://site.com?${params.toString()}`;
console.log(url);
// https://site.com?utm_campaign=Spring+Sale+%26+Save+20%25%21
// Note: + for spaces is valid alternative to %20Python: urllib.parse.quote()
from urllib.parse import quote
value = "Spring Sale & Save 20%!"
encoded = quote(value)
print(encoded)
# Spring%20Sale%20%26%20Save%2020%25%21
# Build URL
url = f"https://site.com?utm_campaign=`{"{"}{"{"}encoded{"}"}{"}"}}`"PHP: urlencode() / rawurlencode()
$value = "Spring Sale & Save 20%!";
// urlencode() - uses + for spaces
$encoded1 = urlencode($value);
echo $encoded1;
// Spring+Sale+%26+Save+20%25%21
// rawurlencode() - uses %20 for spaces
$encoded2 = rawurlencode($value);
echo $encoded2;
// Spring%20Sale%20%26%20Save%2020%25%21
// Recommendation: Use rawurlencode() for UTMsValidation Script
function validateSpecialCharacters(url) {
const issues = [];
try {
const urlObj = new URL(url);
const params = urlObj.searchParams;
const rawQuery = url.split('?')[1] || '';
// Characters that MUST be encoded in values
const mustEncode = {
' ': '%20',
'&': '%26',
'=': '%3D',
'?': '%3F',
'#': '%23',
'%': '%25',
'+': '%2B' // If used as literal +, not space
};
// Check each UTM parameter
['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'].forEach(key => {
const value = params.get(key);
if (value) {
// Check raw query string for unencoded characters
const paramPattern = new RegExp(`${"{"}{"{"}key{"}"}{"}"}}=([^&]*)`);
const match = rawQuery.match(paramPattern);
if (match) {
const rawValue = match[1];
// Check each special character
Object.entries(mustEncode).forEach(([char, encoded]) => {
if (rawValue.includes(char) && !rawValue.includes(encoded)) {
issues.push({
parameter: key,
character: char,
encoding: encoded,
message: `Contains unencoded "${"{"}{"{"}char{"}"}{"}"}}" - should be "${"{"}{"{"}encoded{"}"}{"}"}}"`
});
}
});
}
}
});
} catch (error) {
issues.push({ error: 'Invalid URL', message: error.message });
}
return {
valid: issues.length === 0,
issues
};
}
// Usage
const url = 'site.com?utm_campaign=spring sale&save';
const result = validateSpecialCharacters(url);
if (!result.valid) {
console.log('❌ Issues found:');
result.issues.forEach(issue => {
console.log(` ${issue.parameter}: ${issue.message}`);
});
}Quick Reference Table
Character Encoding Quick Lookup
Character | Encoded | Use Case
-----------|-----------|---------------------------
(space) | %20 | "spring sale" → spring%20sale
& | %26 | "save&win" → save%26win
= | %3D | "2+2=4" → 2%2B2%3D4
? | %3F | "what?" → what%3F
# | %23 | "#1" → %231
% | %25 | "20%" → 20%25
+ | %2B | "C++" → C%2B%2B
/ | %2F | "web/mobile" → web%2Fmobile
: | %3A | "sale:2024" → sale%3A2024
; | %3B | "a;b" → a%3Bb
< | %3C | "a<b" → a%3Cb
> | %3E | "a>b" → a%3Eb
" | %22 | "say\"hi\"" → say%22hi%22
' | %27 | "it's" → it%27s
| | %7C | "a|b" → a%7Cb
\ | %5C | "a\b" → a%5Cb
^ | %5E | "a^b" → a%5Eb
[ | %5B | "a[b]" → a%5Bb%5D
] | %5D | "a[b]" → a%5Bb%5D
{ | %7B | "a`{"{"}{"{"}b{"}"}{"}"}}`" → a%7Bb%7D
} | %7D | "a`{"{"}{"{"}b{"}"}{"}"}}`" → a%7Bb%7D
` | %60 | "a`b" → a%60b
Testing Process
// Test character encoding
function testEncoding(value) {
console.log('Original:', value);
console.log('Encoded:', encodeURIComponent(value));
// Build and test URL
const url = `https://site.com?utm_campaign=${encodeURIComponent(value)}`;
console.log('URL:', url);
// Verify decoding
const decoded = new URL(url).searchParams.get('utm_campaign');
console.log('Decoded:', decoded);
console.log('Match:', value === decoded ? '✅' : '❌');
}
// Test various special characters
testEncoding('Spring Sale & Save 20%!');
testEncoding('Buy 1 + Get 1 = 2 Free?');
testEncoding('Category: Electronics / Computers');
testEncoding('#1 Best Seller');✅ 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
Join 2,847 marketers fixing their tracking daily
FAQ
Should I encode safe characters (A-Z, 0-9, -, _)?
No. These don't need encoding and encoding them makes URLs less readable.
What's the difference between %20 and + for spaces?
Both are valid. %20 is more explicit. + is shorter but can be ambiguous if you need literal + sign. Use %20 for consistency.
Can I use emoji in UTM parameters?
Technically yes (they'll be encoded), but not recommended. Use ASCII characters for better compatibility and readability.
Do all platforms handle encoded characters correctly?
Most do, but test. Some older systems may have issues with heavily encoded URLs.
Conclusion
Special characters in UTM parameters must be encoded to prevent tracking errors.
Key Rules:
- Reserved characters (&, =, ?, #, %, +) MUST be encoded in values
- Use
encodeURIComponent()to automatically encode all special characters - Safe characters (A-Z, 0-9, -, _, ., ~) don't need encoding
- Test encoded URLs across platforms before launch
When in doubt: encode. Better safe than corrupted data.
Technical Reference: Ampersand Not Encoded Validation Rule