Geolocation at the edge

by landro

What are we building?

Check it out! https://weatherflare.adhocracy.workers.dev
Screenshot of geolocation weather site at https://weatherflare.adhocracy.workers.dev

A rendered on demand static HTML page rendered via Javascript on Cloudflare workers based on the visitors geo-location without the use of client side javascript or location data.

What geolocation data is available via Cloudflare headers?

request.cf.colo - The three-letter IATA airport code of the data center that the request hit, for example, "DFW".
country

request.cf.country - Country of the incoming request. The two-letter country code in the request. This is the same value as that provided in the CF-IPCountry header, for example, "US".

request.cf.isEUCountry - If the country of the incoming request is in the EU, this will return "1". Otherwise, this property will be omitted.

request.cf.city - City of the incoming request, for example, "Austin".

request.cf.continent - Continent of the incoming request, for example, "NA".

request.cf.latitude - Latitude of the incoming request, for example, "30.27130".

request.cf.longitude - Longitude of the incoming request, for example, "-97.74260".

request.cf.postalCode - Postal code of the incoming request, for example, "78701".

request.cf.metroCode - Metro code (DMA) of the incoming request, for example, "635".

request.cf.region - If known, the ISO 3166-2 name for the first level region associated with the IP address of the incoming request, for example, "Texas".

request.cf.regionCode - If known, the ISO 3166-2 code for the first-level region associated with the IP address of the incoming request, for example, "TX".

request.cf.timezone - Timezone of the incoming request, for example, "America/Chicago".

Check it out! https://weatherflare.adhocracy.workers.dev

Complete cloudflare worker code (no client side javascript)

addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
// https://api.weather.gov/points/38.8894,-77.0352
const { latitude, longitude } = request.cf;
const headers = {
'content-type': 'application/json',
'User-Agent': ('landro.dev', 'jaylandro@hotmail.com')
}
const weatherLocationResponse = await fetch(
`https://api.weather.gov/points/${latitude},${longitude}`, { headers: headers }
);
console.log(weatherLocationResponse)
const weatherLocationData = await weatherLocationResponse.json();
const forecastResponse = await fetch(
weatherLocationData.properties.forecast, { headers: headers }
);
const forecastData = await forecastResponse.json();
const forecast = forecastData.properties.periods;
function iconHelper(shortForecastString) {
if (shortForecastString.includes("Snow"))
return '🌨';
if (shortForecastString.includes("thunderstorms"))
return '⛈';
if (shortForecastString.includes("Partly Cloudy"))
return '🌤';
if (shortForecastString.includes("Cloud"))
return '☁️';
if (shortForecastString.includes("Light Rain"))
return '🌦';
if (shortForecastString.includes("Rain"))
return '🌧';
return '☀️';
}
let html = `
<html>
<head>
<title>Geolocation: Weather</title>
</head>
<body>
<style>
body {
padding: 6em;
font-family: sans-serif;
}
h1 {
color: #f6821f;
}
.header {
grid-area: header;
margin-bottom: 0;
}
.icon {
grid-area: icon;
font-size: 3em;
font-style: normal;
}
.detailforecast {
grid-area: detailforecast;
line-height: 1.4;
max-width: 500px;
}
.day {
display: grid;
grid-gap: 10px;
grid-template-columns: 3.2em 3fr;
grid-template-areas:
"header header"
"icon detailforecast";
margin-bottom: 1.2em;
}
</style>
<div id="container">
<h1>Weather in ${weatherLocationData.properties.relativeLocation.properties.city}, ${weatherLocationData.properties.relativeLocation.properties.state}</h1>
<main>
<section>
${forecast.map(day => `
<div class="day">
<h3 class="header">${day.name}</h3>
<i class="icon">${iconHelper(day.shortForecast)}</i>
<span class="detailforecast">${day.detailedForecast}</span>
</div>
`).join(' ')}
</section>
</div>
</body>`;
return new Response(html, {
headers: {
'content-type': 'text/html; charset=UTF-8;',
},
});
}