Smart UTM-Based Content Swapper
Dynamic Content Personalization
Intelligent content personalization system that dynamically swaps page elements, headlines, and CTAs based on UTM parameters for campaign-specific messaging and improved conversion rates.
Key Features
Script Overview
What It Does
This script enables dynamic content personalization based on UTM parameters, allowing you to show different headlines, CTAs, images, or entire sections based on the traffic source, campaign, or medium. Perfect for creating targeted landing page experiences.
Use Case
Ideal for campaign-specific landing pages and personalized user experiences. Perfect for showing different content based on traffic source or campaign type.
Key Benefits
- •Campaign-specific content personalization
- •Improved conversion rates through relevance
- •Dynamic A/B testing capabilities
- •Enhanced user experience matching
- •Reduced bounce rates from targeted content
- •Automated content optimization
JavaScript Code
<script>
// Smart UTM-Based Content Swapper Script
// Version: 1.0
// Last Updated: 2025-09-09
(function() {
'use strict';
var config = {
// Content mapping based on UTM parameters
contentMappings: {
// Example mappings - customize for your needs
utm_source: {
'google': {
headline: 'Found Us on Google? Get 20% Off!',
cta: 'Claim Google Discount',
description: 'Special offer for Google visitors'
},
'facebook': {
headline: 'Facebook Exclusive: Limited Time Offer',
cta: 'Get Facebook Deal',
description: 'Exclusive offer for Facebook users'
},
'linkedin': {
headline: 'Professional Solution for LinkedIn Users',
cta: 'Try Professional Plan',
description: 'Business-focused features for professionals'
}
},
utm_medium: {
'email': {
headline: 'Welcome Back! Continue Where You Left Off',
cta: 'Resume Journey',
description: 'Thanks for clicking from our email'
},
'cpc': {
headline: 'Limited Time: Special Paid Ad Pricing',
cta: 'Get Ad Pricing',
description: 'Exclusive pricing for ad visitors'
},
'social': {
headline: 'Social Media Special Offer',
cta: 'Claim Social Bonus',
description: 'Special offer for social media visitors'
}
},
utm_campaign: {
'summer2024': {
headline: 'Summer Sale: 30% Off Everything!',
cta: 'Shop Summer Sale',
description: 'Limited time summer promotion'
},
'holiday': {
headline: 'Holiday Special: Gift Bundles Available',
cta: 'View Holiday Deals',
description: 'Perfect gifts for the holiday season'
}
}
},
// Element selectors to replace content
elementSelectors: {
headline: '[data-utm-headline], .utm-headline, h1.hero-title',
cta: '[data-utm-cta], .utm-cta, .cta-button',
description: '[data-utm-description], .utm-description, .hero-description',
image: '[data-utm-image], .utm-image'
},
// Fallback content if no UTM match
fallbackContent: {
headline: null, // Keep original if no match
cta: null,
description: null
},
// Storage key for UTM data
storageKey: 'utm_data',
// Animation settings
animation: {
enabled: true,
duration: 300, // milliseconds
easing: 'ease-in-out'
},
debug: false
};
var swappedElements = [];
function debugLog(message, data) {
if (config.debug) {
console.log('[Content Swapper] ' + message, data || '');
}
}
function getUTMParameters() {
// First try current URL
var urlParams = new URLSearchParams(window.location.search);
var params = {};
['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'].forEach(function(param) {
var value = urlParams.get(param);
if (value) {
params[param] = value.toLowerCase();
}
});
// If no UTM in URL, try stored data
if (Object.keys(params).length === 0) {
try {
var stored = localStorage.getItem(config.storageKey);
if (stored) {
var data = JSON.parse(stored);
['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'].forEach(function(param) {
if (data[param]) {
params[param] = data[param].toLowerCase();
}
});
}
} catch (e) {
debugLog('Error reading stored UTM data:', e);
}
}
return params;
}
function findContentMatch(utmParams) {
var matchedContent = {};
// Check each UTM parameter for content mappings
Object.keys(utmParams).forEach(function(param) {
var value = utmParams[param];
if (config.contentMappings[param] && config.contentMappings[param][value]) {
var paramContent = config.contentMappings[param][value];
// Merge content, with later params taking precedence
Object.keys(paramContent).forEach(function(contentType) {
matchedContent[contentType] = paramContent[contentType];
});
debugLog('Content match found:', { param: param, value: value, content: paramContent });
}
});
return matchedContent;
}
function animateElementChange(element, newContent, contentType) {
if (!config.animation.enabled) {
updateElementContent(element, newContent, contentType);
return;
}
// Fade out
element.style.transition = 'opacity ' + config.animation.duration + 'ms ' + config.animation.easing;
element.style.opacity = '0';
setTimeout(function() {
updateElementContent(element, newContent, contentType);
// Fade in
element.style.opacity = '1';
// Clean up transition
setTimeout(function() {
element.style.transition = '';
}, config.animation.duration);
}, config.animation.duration);
}
function updateElementContent(element, newContent, contentType) {
var originalContent = element.getAttribute('data-original-' + contentType) ||
(contentType === 'image' ? element.src : element.textContent);
// Store original content if not already stored
if (!element.getAttribute('data-original-' + contentType)) {
element.setAttribute('data-original-' + contentType, originalContent);
}
// Update content based on type
switch (contentType) {
case 'image':
if (element.tagName === 'IMG') {
element.src = newContent;
element.alt = 'Personalized content based on traffic source';
}
break;
case 'headline':
case 'cta':
case 'description':
element.textContent = newContent;
break;
default:
element.innerHTML = newContent;
}
// Mark as swapped
element.setAttribute('data-utm-swapped', 'true');
element.setAttribute('data-utm-type', contentType);
swappedElements.push({
element: element,
contentType: contentType,
originalContent: originalContent,
newContent: newContent
});
debugLog('Content updated:', {
contentType: contentType,
element: element,
original: originalContent,
new: newContent
});
}
function swapContent(matchedContent) {
Object.keys(matchedContent).forEach(function(contentType) {
var newContent = matchedContent[contentType];
var selector = config.elementSelectors[contentType];
if (!selector || !newContent) return;
var elements = document.querySelectorAll(selector);
Array.prototype.forEach.call(elements, function(element) {
// Skip if already swapped
if (element.getAttribute('data-utm-swapped') === 'true') return;
if (config.animation.enabled) {
animateElementChange(element, newContent, contentType);
} else {
updateElementContent(element, newContent, contentType);
}
});
});
}
function trackContentSwap(utmParams, matchedContent) {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'utm_content_swapped',
utm_parameters: utmParams,
swapped_content: matchedContent,
swapped_elements_count: swappedElements.length,
page_url: window.location.href
});
debugLog('Content swap tracked:', {
utm: utmParams,
content: matchedContent,
elements: swappedElements.length
});
}
function revertContent() {
swappedElements.forEach(function(item) {
var element = item.element;
var contentType = item.contentType;
var originalContent = item.originalContent;
// Revert content
switch (contentType) {
case 'image':
if (element.tagName === 'IMG') {
element.src = originalContent;
}
break;
default:
element.textContent = originalContent;
}
// Remove attributes
element.removeAttribute('data-utm-swapped');
element.removeAttribute('data-utm-type');
element.removeAttribute('data-original-' + contentType);
});
swappedElements = [];
debugLog('Content reverted to original');
}
function initContentSwapping() {
debugLog('Initializing UTM Content Swapper');
var utmParams = getUTMParameters();
if (Object.keys(utmParams).length === 0) {
debugLog('No UTM parameters found, keeping original content');
return;
}
debugLog('UTM parameters found:', utmParams);
var matchedContent = findContentMatch(utmParams);
if (Object.keys(matchedContent).length === 0) {
debugLog('No content matches found for UTM parameters');
return;
}
debugLog('Content matches found:', matchedContent);
// Wait for DOM to be fully loaded
setTimeout(function() {
swapContent(matchedContent);
trackContentSwap(utmParams, matchedContent);
}, 100);
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initContentSwapping);
} else {
initContentSwapping();
}
// Expose utility functions
window.utmContentSwapper = {
getCurrentUTM: function() {
return getUTMParameters();
},
getSwappedElements: function() {
return swappedElements;
},
revertContent: function() {
revertContent();
},
refreshSwapping: function() {
revertContent();
initContentSwapping();
},
addContentMapping: function(param, value, content) {
if (!config.contentMappings[param]) {
config.contentMappings[param] = {};
}
config.contentMappings[param][value] = content;
debugLog('Content mapping added:', { param: param, value: value, content: content });
}
};
})();
</script>
💡 Pro Tip: Copy the entire code block above and paste it directly into a GTM Custom HTML tag. The script is self-contained and ready to use immediately.