How to Fix Spaces in UTM Parameters: Complete 2024 Guide
"We had spaces in our UTM parameters for eight months. When I finally fixed them, our conversion attribution improved by 43%. I wish someone had told me this on day one."
Lisa Chen, Growth Marketing Manager at a SaaS startup, discovered this after a frustrating audit revealed 278 fragmented campaign entries—all from a single issue: spaces in UTM parameters.
This comprehensive guide will show you exactly how to identify, fix, and prevent space-related UTM issues that are fragmenting your analytics data.
Quick Diagnosis: Do You Have Space Issues?
Check #1: Your Current URLs
Look at your tracking links. Do you see ANY of these?
❌ PROBLEM URLS:
?utm_campaign=Black Friday Sale
?utm_source=email newsletter
?utm_medium=social media
?utm_content=hero banner
?utm_term=running shoes
✅ CORRECT URLS:
?utm_campaign=black-friday-sale
?utm_source=email-newsletter
?utm_medium=social-media
?utm_content=hero-banner
?utm_term=running-shoes
If you see spaces, you have a problem.
Check #2: Your Analytics Data
Google Analytics 4 fragmentation symptoms:
- Open Reports → Acquisition → Traffic Acquisition
- Look at "Session campaign" dimension
- Do you see entries like:
- "Black Friday Sale"
- "Black%20Friday%20Sale"
- "Black+Friday+Sale"
- "Black"
If yes, you have space-induced fragmentation.
🚨 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 Complete Fix: 5-Step Process
Step 1: Audit All Current Campaigns
Create a comprehensive inventory:
// JavaScript audit script for your analytics export
function auditCampaignNames(data) {
const problemCampaigns = [];
data.forEach(row => {
const campaign = row.campaign;
// Check for spaces or encoded spaces
if (campaign.includes(' ') ||
campaign.includes('%20') ||
campaign.includes('+')) {
problemCampaigns.push({
original: campaign,
sessions: row.sessions,
revenue: row.revenue,
severity: calculateSeverity(row.sessions)
});
}
});
return problemCampaigns.sort((a, b) => b.sessions - a.sessions);
}
function calculateSeverity(sessions) {
if (sessions > 1000) return 'CRITICAL';
if (sessions > 100) return 'HIGH';
if (sessions > 10) return 'MEDIUM';
return 'LOW';
}Export from Google Analytics:
- Reports → Acquisition → Traffic Acquisition
- Add dimensions: Campaign, Source, Medium, Content, Term
- Date range: Last 90 days
- Export to CSV
- Run audit script on exported data
Expected output:
CRITICAL Issues (>1000 sessions):
- "Summer Sale 2024" (1,245 sessions, $18,900 revenue)
- "Email Newsletter" (1,120 sessions, $8,450 revenue)
HIGH Issues (100-1000 sessions):
- "Facebook Campaign" (456 sessions, $3,200 revenue)
- "Product Launch" (234 sessions, $5,100 revenue)
... (full list)
Step 2: Create Corrected Versions
For each problematic entry, create the fixed version:
function createFixedVersion(originalName) {
return originalName
.toLowerCase() // Convert to lowercase
.trim() // Remove leading/trailing spaces
.replace(/\s+/g, '-') // Replace spaces with hyphens
.replace(/[^a-z0-9-_]/g, '') // Remove special characters
.replace(/-+/g, '-') // Replace multiple hyphens with single
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
}
// Examples
console.log(createFixedVersion('Black Friday Sale 2024'));
// Output: black-friday-sale-2024
console.log(createFixedVersion('Email Newsletter Campaign'));
// Output: email-newsletter-campaign
console.log(createFixedVersion('SUMMER SALE!!'));
// Output: summer-saleCreate a mapping document:
| Original (with spaces) | Fixed Version | Sessions | Revenue | Priority |
|---|---|---|---|---|
| Summer Sale 2024 | summer-sale-2024 | 1,245 | $18,900 | 1 |
| Email Newsletter | email-newsletter | 1,120 | $8,450 | 2 |
| Facebook Campaign | facebook-campaign | 456 | $3,200 | 3 |
Step 3: Update Active Campaigns
For each active campaign, replace URLs systematically:
😰 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
Email Marketing Platforms
Mailchimp:
- Go to Campaigns → All campaigns
- Search for campaigns with spaces in UTM parameters
- Clone campaign
- Update all tracking links with fixed versions
- Test with seed list
- Schedule/send new version
- Archive old campaign
HubSpot:
- Marketing → Email
- Filter by "Active" campaigns
- Edit each email
- Use Find & Replace for UTM parameters
- Update all instances
- Review in preview mode
- Re-test and republish
Social Media Platforms
Facebook Ads:
1. Ads Manager → All Campaigns
2. Click into Ad Set
3. Edit → Ad Creative
4. Update "Website URL"
5. Replace:
OLD: ?utm_campaign=Black Friday Sale
NEW: ?utm_campaign=black-friday-sale
6. Review and publish changes
LinkedIn Campaign Manager:
1. Campaign Manager → Campaigns
2. Select campaign → Ads
3. Edit each ad
4. Update destination URL
5. Test link in preview
6. Activate updated ads
Google Ads
Using Ads Editor (bulk update):
- Download Google Ads Editor
- Get Latest → Select account
- Keywords → Add/update tracking templates
- Find:
utm_campaign=Black Friday Sale - Replace:
utm_campaign=black-friday-sale - Review changes
- Post changes
Manual update:
1. Google Ads → Campaigns
2. Settings → Campaign URL options
3. Update tracking template:
OLD: `{"{"}{"{"}lpurl{"}"}{"}"}}`?utm_source=google&utm_medium=paid search&utm_campaign=Black Friday
NEW: `{"{"}{"{"}lpurl{"}"}{"}"}}`?utm_source=google&utm_medium=paid-search&utm_campaign=black-friday
4. Save and apply to all ad groups
Step 4: Fix UTM Generation Process
Implement a proper URL builder:
<!DOCTYPE html>
<html>
<head>
<title>UTM URL Builder (Space-Free)</title>
<style>
.error { color: red; }
.success { color: green; }
.url-output {
background: #f5f5f5;
padding: 15px;
margin: 15px 0;
border-radius: 5px;
word-break: break-all;
}
</style>
</head>
<body>
<h1>UTM URL Builder</h1>
<form id="utmForm">
<label>Website URL *</label>
<input type="url" id="baseUrl" required placeholder="https://example.com">
<label>Campaign Source *</label>
<input type="text" id="source" required placeholder="facebook">
<label>Campaign Medium *</label>
<input type="text" id="medium" required placeholder="paid-social">
<label>Campaign Name *</label>
<input type="text" id="campaign" required placeholder="summer-sale-2024">
<label>Campaign Content (optional)</label>
<input type="text" id="content" placeholder="header-banner">
<label>Campaign Term (optional)</label>
<input type="text" id="term" placeholder="running-shoes">
<button type="submit">Generate URL</button>
</form>
<div id="validation"></div>
<div id="output"></div>
<script>
document.getElementById('utmForm').addEventListener('submit', function(e) {
e.preventDefault();
const baseUrl = document.getElementById('baseUrl').value;
const params = {
utm_source: document.getElementById('source').value,
utm_medium: document.getElementById('medium').value,
utm_campaign: document.getElementById('campaign').value,
utm_content: document.getElementById('content').value,
utm_term: document.getElementById('term').value
};
// Validate for spaces
const validation = validateParams(params);
displayValidation(validation);
if (validation.hasErrors) {
return; // Stop if errors found
}
// Build URL
const finalUrl = buildURL(baseUrl, params);
displayResult(finalUrl);
});
function validateParams(params) {
const errors = [];
const warnings = [];
Object.keys(params).forEach(key => {
const value = params[key];
if (!value) return; // Skip empty values
// Check for spaces
if (value.includes(' ')) {
errors.push(`${"{"}{"{"}key{"}"}{"}"}} contains spaces: "${"{"}{"{"}value{"}"}{"}"}}"`);
}
// Check for uppercase
if (value !== value.toLowerCase()) {
warnings.push(`${"{"}{"{"}key{"}"}{"}"}} contains uppercase: "${"{"}{"{"}value{"}"}{"}"}}"`);
}
// Check for special characters
if (!/^[a-z0-9-_]*$/i.test(value)) {
warnings.push(`${"{"}{"{"}key{"}"}{"}"}} contains special characters: "${"{"}{"{"}value{"}"}{"}"}}"`);
}
});
return {
hasErrors: errors.length > 0,
errors,
warnings
};
}
function buildURL(baseUrl, params) {
const url = new URL(baseUrl);
Object.keys(params).forEach(key => {
let value = params[key];
if (!value) return;
// Clean the value
value = value
.toLowerCase()
.trim()
.replace(/\s+/g, '-')
.replace(/[^a-z0-9-_]/g, '')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
url.searchParams.set(key, value);
});
return url.toString();
}
function displayValidation(validation) {
const div = document.getElementById('validation');
if (validation.hasErrors) {
div.innerHTML = '<div class="error"><strong>Errors Found:</strong><ul>' +
validation.errors.map(e => '<li>' + e + '</li>').join('') +
'</ul><p>URL will be automatically corrected when generated.</p></div>';
} else if (validation.warnings.length > 0) {
div.innerHTML = '<div class="warning"><strong>Warnings:</strong><ul>' +
validation.warnings.map(w => '<li>' + w + '</li>').join('') +
'</ul><p>Values will be normalized.</p></div>';
} else {
div.innerHTML = '<div class="success">✓ All parameters valid!</div>';
}
}
function displayResult(url) {
document.getElementById('output').innerHTML =
'<h2>Generated URL:</h2>' +
'<div class="url-output">' + url + '</div>' +
'<button onclick="copyToClipboard(\'' + url + '\')">Copy to Clipboard</button>';
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text);
alert('URL copied to clipboard!');
}
</script>
</body>
</html>Save this as utm-builder.html and use it for all campaign URL generation.
Step 5: Implement Validation Checks
Pre-launch validation script:
// Add to your campaign deployment checklist
function validateCampaignURLs(urls) {
const report = {
passed: [],
failed: [],
total: urls.length
};
urls.forEach(url => {
const issues = [];
try {
const urlObj = new URL(url);
const params = urlObj.searchParams;
// Check each UTM parameter
['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'].forEach(param => {
const value = params.get(param);
if (!value) return;
// Space check
if (value.includes(' ')) {
issues.push(`${"{"}{"{"}param{"}"}{"}"}} has spaces: "${"{"}{"{"}value{"}"}{"}"}}"`);
}
// Encoding check
if (value.includes('%20') || value.includes('+')) {
issues.push(`${"{"}{"{"}param{"}"}{"}"}} has encoded spaces: "${"{"}{"{"}value{"}"}{"}"}}"`);
}
// Case check
if (value !== value.toLowerCase()) {
issues.push(`${"{"}{"{"}param{"}"}{"}"}} not lowercase: "${"{"}{"{"}value{"}"}{"}"}}"`);
}
});
if (issues.length > 0) {
report.failed.push({ url, issues });
} else {
report.passed.push(url);
}
} catch (e) {
report.failed.push({ url, issues: ['Invalid URL format'] });
}
});
return report;
}
// Usage
const campaignURLs = [
'https://example.com?utm_campaign=Black Friday',
'https://example.com?utm_campaign=black-friday',
'https://example.com?utm_source=Email'
];
const report = validateCampaignURLs(campaignURLs);
console.log(`Total URLs: ${report.total}`);
console.log(`Passed: ${report.passed.length}`);
console.log(`Failed: ${report.failed.length}`);
if (report.failed.length > 0) {
console.log('\nFailed URLs:');
report.failed.forEach(item => {
console.log(`\nURL: ${item.url}`);
console.log('Issues:');
item.issues.forEach(issue => console.log(` - ${"{"}{"{"}issue{"}"}{"}"}}`));
});
}Prevention: Never Have Spaces Again
1. Style Guide
Create and enforce this standard:
# UTM Parameter Style Guide
## Rules
1. All lowercase
2. No spaces ever
3. Use hyphens for word separation
4. No special characters except hyphens and underscores
## Examples
✅ CORRECT:
- utm_source=facebook
- utm_medium=paid-social
- utm_campaign=summer-sale-2024
- utm_content=hero-banner-v2
- utm_term=running-shoes-men
❌ WRONG:
- utm_source=Facebook (uppercase)
- utm_medium=paid social (space)
- utm_campaign=Summer Sale! (space + special char)
- utm_content=hero banner (space)
- utm_term=running shoes (space)
## Approved Sources
Copy these exactly:
- facebook
- instagram
- twitter
- linkedin
- email
- google
- tiktok
- pinterest
## Approved Mediums
Copy these exactly:
- paid-social
- organic-social
- email
- newsletter
- paid-search
- organic-search
- display
- referral
- affiliate2. Team Training
30-minute training module:
-
Why spaces matter (10 min)
- Show real fragmented data example
- Calculate cost of fragmentation
- Demonstrate impact on decisions
-
How to fix (10 min)
- Walk through URL builder tool
- Practice creating clean URLs
- Review common mistakes
-
Prevention (10 min)
- Introduce style guide
- Set up validation checklist
- Assign accountability
3. Monthly Audits
Recurring audit schedule:
Week 1: Export GA4 data, run audit script
Week 2: Review new campaigns for issues
Week 3: Update style guide if needed
Week 4: Team refresher training
Audit script output to track:
| Month | Problem URLs | Sessions Affected | Revenue Affected | Status |
|---|---|---|---|---|
| Jan | 23 | 4,567 | $8,900 | Fixed |
| Feb | 7 | 1,234 | $2,100 | Fixed |
| Mar | 2 | 345 | $650 | Fixed |
| Apr | 0 | 0 | $0 | Clean ✓ |
✅ 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
Q: Can I use a find-and-replace to fix spaces in Google Analytics?
A: No, you can't edit historical data in GA4. You can only fix URLs going forward and create custom dimensions to normalize data in reports.
Q: What if I have 100+ campaigns with spaces?
A: Use the bulk update methods for each platform (Google Ads Editor, Facebook Ads Manager bulk edit, etc.). Prioritize by traffic volume using the audit script.
Q: Will fixing spaces break my existing tracked links?
A: The old links will still work but track separately. This is desired—you want clean new data going forward. Keep historical data for reference.
Q: Should I use underscores or hyphens instead of spaces?
A: Hyphens are the industry standard and more readable. Choose one and be consistent. Both work equally well technically.
Q: How long does it take to fix spaces in UTM parameters?
A: For a medium-sized operation (50 active campaigns): 4-8 hours for initial fix, 1 hour/month for ongoing maintenance.
Q: Do spaces in URL fragments (after #) matter?
A: UTM parameters should be in the query string (after ?), not the fragment (after #). Fragments aren't sent to the server and won't be tracked.
Q: What about spaces in the utm_content for A/B testing?
A: Same rules apply. Use hyphens: utm_content=header-banner-v1 and utm_content=header-banner-v2 instead of spaces.
Q: Can I automate space detection in our workflow?
A: Yes! Add the validation script to your campaign deployment process. Make it a required check before launch, like spell-check for emails.
Ready to eliminate spaces from your UTM parameters once and for all? UTMGuard automatically detects, flags, and helps you fix space-related issues before they fragment your data. Start your free audit today.