Weather/Geo-based Personalizer
Location & Climate-Aware Content
Sophisticated location-based personalization system using OpenWeatherMap API and geolocation services to deliver weather-aware, location-specific content and messaging for maximum relevance and engagement.
Key Features
Script Overview
What It Does
This advanced script uses geolocation and weather APIs to personalize content based on visitor location and current weather. Perfect for businesses with location-specific offerings or weather-dependent products.
Use Case
Perfect for retail, travel, food delivery, or any business with location-specific offers. Show umbrella ads when it's raining, winter coats when it's cold.
Key Benefits
- •Location-specific messaging
- •Weather-relevant content
- •Higher relevance and engagement
- •Regional offer customization
- •Enhanced user experience
- •Seasonal content automation
JavaScript Code
<script>
// Weather/Geo-based Personalizer Script
// Version: 1.0
// Last Updated: 2025-09-09
(function() {
'use strict';
var config = {
// OpenWeatherMap API key (get free at openweathermap.org)
weatherApiKey: 'YOUR_API_KEY_HERE', // Replace with your API key
// Location-based content mappings
locationContent: {
'US': {
'New York': { headline: 'NYC Special: Fast Delivery Available!', cta: 'Order Now' },
'Los Angeles': { headline: 'LA Exclusive: Same-Day Service!', cta: 'Get Started' },
'Chicago': { headline: 'Chicago Deal: Winter Special Pricing!', cta: 'Learn More' }
},
'CA': {
'Toronto': { headline: 'Toronto Local: Canadian Pricing!', cta: 'Shop CAD' },
'Vancouver': { headline: 'West Coast Special!', cta: 'Explore' }
}
},
// Weather-based content mappings
weatherContent: {
'Clear': { message: 'Perfect weather for outdoor activities!', offer: 'Outdoor gear sale' },
'Rain': { message: 'Stay dry with our rain protection!', offer: 'Umbrella & raincoat deals' },
'Snow': { message: 'Winter weather essentials available!', offer: 'Winter clothing sale' },
'Clouds': { message: 'Great day for indoor comfort!', offer: 'Cozy home essentials' },
'Cold': { message: 'Stay warm with our winter selection!', offer: 'Heating & warm clothing' },
'Hot': { message: 'Beat the heat with cooling solutions!', offer: 'AC & summer essentials' }
},
// Element selectors
selectors: {
headline: '[data-geo-headline], .geo-headline',
message: '[data-weather-message], .weather-message',
offer: '[data-weather-offer], .weather-offer',
location: '[data-user-location], .user-location'
},
// Fallback content
fallback: {
headline: 'Welcome! Special Offers Available',
message: 'Check out our latest deals',
location: 'Visitor'
},
// Privacy and consent
privacy: {
askConsent: true,
consentMessage: 'We'd like to show you location-relevant content. Allow location access?',
storeConsent: true
},
// Cache settings (to avoid excessive API calls)
cache: {
locationExpiry: 24 * 60 * 60 * 1000, // 24 hours
weatherExpiry: 30 * 60 * 1000, // 30 minutes
storageKey: 'geo_weather_data'
},
debug: false
};
var geoData = null;
function debugLog(message, data) {
if (config.debug) {
console.log('[Geo-Weather Personalizer] ' + message, data || '');
}
}
function getCachedData() {
try {
var stored = localStorage.getItem(config.cache.storageKey);
if (stored) {
var data = JSON.parse(stored);
var now = Date.now();
// Check if location data is still valid
var locationValid = data.location && data.locationTimestamp &&
(now - data.locationTimestamp) < config.cache.locationExpiry;
// Check if weather data is still valid
var weatherValid = data.weather && data.weatherTimestamp &&
(now - data.weatherTimestamp) < config.cache.weatherExpiry;
return {
location: locationValid ? data.location : null,
weather: weatherValid ? data.weather : null,
consent: data.consent || false
};
}
} catch (e) {
debugLog('Error reading cached data:', e);
}
return { location: null, weather: null, consent: false };
}
function saveToCache(location, weather, consent) {
try {
var data = {
location: location,
locationTimestamp: location ? Date.now() : null,
weather: weather,
weatherTimestamp: weather ? Date.now() : null,
consent: consent
};
localStorage.setItem(config.cache.storageKey, JSON.stringify(data));
} catch (e) {
debugLog('Error saving to cache:', e);
}
}
function requestLocationConsent() {
if (!config.privacy.askConsent) return Promise.resolve(true);
return new Promise(function(resolve) {
var consent = confirm(config.privacy.consentMessage);
resolve(consent);
});
}
function getCurrentLocation() {
return new Promise(function(resolve, reject) {
if (!navigator.geolocation) {
reject(new Error('Geolocation not supported'));
return;
}
navigator.geolocation.getCurrentPosition(
function(position) {
resolve({
latitude: position.coords.latitude,
longitude: position.coords.longitude
});
},
function(error) {
debugLog('Geolocation error:', error);
reject(error);
},
{
timeout: 10000,
maximumAge: 600000, // 10 minutes
enableHighAccuracy: false
}
);
});
}
function getLocationInfo(lat, lon) {
// Using reverse geocoding to get city/country
var url = 'https://api.openweathermap.org/geo/1.0/reverse?lat=' +
lat + '&lon=' + lon + '&limit=1&appid=' + config.weatherApiKey;
return fetch(url)
.then(function(response) {
if (!response.ok) throw new Error('Geocoding failed');
return response.json();
})
.then(function(data) {
if (data && data.length > 0) {
var location = data[0];
return {
city: location.name,
country: location.country,
state: location.state,
coordinates: { lat: lat, lon: lon }
};
}
throw new Error('No location data found');
});
}
function getWeatherInfo(lat, lon) {
var url = 'https://api.openweathermap.org/data/2.5/weather?lat=' +
lat + '&lon=' + lon + '&appid=' + config.weatherApiKey + '&units=metric';
return fetch(url)
.then(function(response) {
if (!response.ok) throw new Error('Weather API failed');
return response.json();
})
.then(function(data) {
var temp = Math.round(data.main.temp);
var condition = data.weather[0].main;
// Determine temperature-based condition
var tempCondition = temp < 10 ? 'Cold' : temp > 25 ? 'Hot' : null;
return {
temperature: temp,
condition: condition,
tempCondition: tempCondition,
description: data.weather[0].description,
city: data.name,
country: data.sys.country
};
});
}
function getContentForLocation(location) {
if (!location) return null;
var countryContent = config.locationContent[location.country];
if (countryContent && countryContent[location.city]) {
return countryContent[location.city];
}
return null;
}
function getContentForWeather(weather) {
if (!weather) return null;
// Try temperature-based condition first
if (weather.tempCondition && config.weatherContent[weather.tempCondition]) {
return config.weatherContent[weather.tempCondition];
}
// Try weather condition
if (weather.condition && config.weatherContent[weather.condition]) {
return config.weatherContent[weather.condition];
}
return null;
}
function updateContent(locationContent, weatherContent, location) {
// Update location-based content
if (locationContent) {
updateElements(config.selectors.headline, locationContent.headline);
}
// Update weather-based content
if (weatherContent) {
updateElements(config.selectors.message, weatherContent.message);
updateElements(config.selectors.offer, weatherContent.offer);
}
// Update location display
if (location) {
var locationText = location.city + (location.country ? ', ' + location.country : '');
updateElements(config.selectors.location, locationText);
}
// Apply fallbacks if needed
if (!locationContent) {
updateElements(config.selectors.headline, config.fallback.headline);
}
if (!weatherContent) {
updateElements(config.selectors.message, config.fallback.message);
}
if (!location) {
updateElements(config.selectors.location, config.fallback.location);
}
}
function updateElements(selector, content) {
if (!selector || !content) return;
var elements = document.querySelectorAll(selector);
Array.prototype.forEach.call(elements, function(element) {
element.textContent = content;
element.setAttribute('data-geo-personalized', 'true');
});
}
function trackPersonalization(location, weather) {
window.dataLayer = window.dataLayer || [];
var eventData = {
event: 'geo_weather_personalized',
user_city: location ? location.city : 'unknown',
user_country: location ? location.country : 'unknown',
weather_condition: weather ? weather.condition : 'unknown',
weather_temperature: weather ? weather.temperature : null,
page_url: window.location.href
};
window.dataLayer.push(eventData);
debugLog('Geo-weather personalization tracked:', eventData);
}
async function initGeoWeatherPersonalizer() {
debugLog('Initializing Geo-Weather Personalizer');
// Check if API key is configured
if (config.weatherApiKey === 'YOUR_API_KEY_HERE') {
debugLog('Weather API key not configured');
updateContent(null, null, null); // Apply fallbacks
return;
}
var cached = getCachedData();
var location = cached.location;
var weather = cached.weather;
var hasConsent = cached.consent;
// Request consent if needed and not already given
if (!hasConsent && config.privacy.askConsent) {
try {
hasConsent = await requestLocationConsent();
if (config.privacy.storeConsent) {
saveToCache(location, weather, hasConsent);
}
} catch (e) {
debugLog('Consent request failed:', e);
hasConsent = false;
}
}
// Get fresh location if not cached and consent given
if (!location && hasConsent) {
try {
var coords = await getCurrentLocation();
location = await getLocationInfo(coords.latitude, coords.longitude);
debugLog('Location obtained:', location);
} catch (e) {
debugLog('Location detection failed:', e);
}
}
// Get fresh weather if not cached and we have location
if (!weather && location && location.coordinates) {
try {
weather = await getWeatherInfo(location.coordinates.lat, location.coordinates.lon);
debugLog('Weather obtained:', weather);
} catch (e) {
debugLog('Weather detection failed:', e);
}
}
// Save to cache
saveToCache(location, weather, hasConsent);
// Get personalized content
var locationContent = getContentForLocation(location);
var weatherContent = getContentForWeather(weather);
// Update page content
updateContent(locationContent, weatherContent, location);
// Track personalization
trackPersonalization(location, weather);
geoData = { location: location, weather: weather };
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initGeoWeatherPersonalizer);
} else {
initGeoWeatherPersonalizer();
}
// Expose utility functions
window.geoWeatherPersonalizer = {
getCurrentData: function() {
return geoData;
},
clearCache: function() {
localStorage.removeItem(config.cache.storageKey);
debugLog('Cache cleared');
},
refresh: function() {
// Clear cache and re-run
this.clearCache();
initGeoWeatherPersonalizer();
}
};
})();
</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.