Geolocation: Weather application
Fetch weather data from an API using the user's geolocation data.
Last updated Apr 23, 2026 If you want to get started quickly, click on the button below.
This creates a repository in your GitHub account and deploys the application to Cloudflare Workers.
export default {
async fetch(request) {
let endpoint = "https://api.waqi.info/feed/geo:";
const token = ""; //Use a token from https://aqicn.org/api/
let html_style = `body{padding:6em; font-family: sans-serif;} h1{color:#f6821f}`;
let html_content = "<h1>Weather 🌦</h1>";
const latitude = request.cf.latitude;
const longitude = request.cf.longitude;
endpoint += `${latitude};${longitude}/?token=${token}`;
const init = {
headers: {
"content-type": "application/json;charset=UTF-8",
},
};
const response = await fetch(endpoint, init);
const content = await response.json();
html_content += `<p>This is a demo using Workers geolocation data. </p>`;
html_content += `You are located at: ${latitude},${longitude}.</p>`;
html_content += `<p>Based off sensor data from <a href="${content.data.city.url}">${content.data.city.name}</a>:</p>`;
html_content += `<p>The AQI level is: ${content.data.aqi}.</p>`;
html_content += `<p>The N02 level is: ${content.data.iaqi.no2?.v}.</p>`;
html_content += `<p>The O3 level is: ${content.data.iaqi.o3?.v}.</p>`;
html_content += `<p>The temperature is: ${content.data.iaqi.t?.v}°C.</p>`;
let html = `
<!DOCTYPE html>
<head>
<title>Geolocation: Weather</title>
</head>
<body>
<style>${html_style}</style>
<div id="container">
${html_content}
</div>
</body>`;
return new Response(html, {
headers: {
"content-type": "text/html;charset=UTF-8",
},
});
},
};
export default {
async fetch(request): Promise<Response> {
let endpoint = "https://api.waqi.info/feed/geo:";
const token = ""; //Use a token from https://aqicn.org/api/
let html_style = `body{padding:6em; font-family: sans-serif;} h1{color:#f6821f}`;
let html_content = "<h1>Weather 🌦</h1>";
const latitude = request.cf.latitude;
const longitude = request.cf.longitude;
endpoint += `${latitude};${longitude}/?token=${token}`;
const init = {
headers: {
"content-type": "application/json;charset=UTF-8",
},
};
const response = await fetch(endpoint, init);
const content = await response.json();
html_content += `<p>This is a demo using Workers geolocation data. </p>`;
html_content += `You are located at: ${latitude},${longitude}.</p>`;
html_content += `<p>Based off sensor data from <a href="${content.data.city.url}">${content.data.city.name}</a>:</p>`;
html_content += `<p>The AQI level is: ${content.data.aqi}.</p>`;
html_content += `<p>The N02 level is: ${content.data.iaqi.no2?.v}.</p>`;
html_content += `<p>The O3 level is: ${content.data.iaqi.o3?.v}.</p>`;
html_content += `<p>The temperature is: ${content.data.iaqi.t?.v}°C.</p>`;
let html = `
<!DOCTYPE html>
<head>
<title>Geolocation: Weather</title>
</head>
<body>
<style>${html_style}</style>
<div id="container">
${html_content}
</div>
</body>`;
return new Response(html, {
headers: {
"content-type": "text/html;charset=UTF-8",
},
});
},
} satisfies ExportedHandler;
import { Hono } from 'hono';
import { html } from 'hono/html';
type Bindings = {};
interface WeatherApiResponse {
data: {
aqi: number;
city: {
name: string;
url: string;
};
iaqi: {
no2?: { v: number };
o3?: { v: number };
t?: { v: number };
};
};
}
const app = new Hono<{ Bindings: Bindings }>();
app.get('*', async (c) => {
// Get API endpoint
let endpoint = "https://api.waqi.info/feed/geo:";
const token = ""; // Use a token from https://aqicn.org/api/
// Define styles
const html_style = `body{padding:6em; font-family: sans-serif;} h1{color:#f6821f}`;
// Get geolocation from Cloudflare request
const req = c.req.raw;
const latitude = req.cf?.latitude;
const longitude = req.cf?.longitude;
// Create complete API endpoint with coordinates
endpoint += `${latitude};${longitude}/?token=${token}`;
// Fetch weather data
const init = {
headers: {
"content-type": "application/json;charset=UTF-8",
},
};
const response = await fetch(endpoint, init);
const content = await response.json() as WeatherApiResponse;
// Build HTML content
const weatherContent = html`
<h1>Weather 🌦</h1>
<p>This is a demo using Workers geolocation data.</p>
<p>You are located at: ${latitude},${longitude}.</p>
<p>Based off sensor data from <a href="${content.data.city.url}">${content.data.city.name}</a>:</p>
<p>The AQI level is: ${content.data.aqi}.</p>
<p>The N02 level is: ${content.data.iaqi.no2?.v}.</p>
<p>The O3 level is: ${content.data.iaqi.o3?.v}.</p>
<p>The temperature is: ${content.data.iaqi.t?.v}°C.</p>
`;
// Complete HTML document
const htmlDocument = html`
<!DOCTYPE html>
<head>
<title>Geolocation: Weather</title>
</head>
<body>
<style>${html_style}</style>
<div id="container">
${weatherContent}
</div>
</body>
`;
// Return HTML response
return c.html(htmlDocument);
});
export default app;
from workers import WorkerEntrypoint, Response, fetch
class Default(WorkerEntrypoint):
async def fetch(self, request):
endpoint = "https://api.waqi.info/feed/geo:"
token = "" # Use a token from https://aqicn.org/api/
html_style = "body{padding:6em; font-family: sans-serif;} h1{color:#f6821f}"
html_content = "<h1>Weather 🌦</h1>"
latitude = request.cf.latitude
longitude = request.cf.longitude
endpoint += f"{latitude};{longitude}/?token={token}"
response = await fetch(endpoint)
content = await response.json()
html_content += "<p>This is a demo using Workers geolocation data. </p>"
html_content += f"You are located at: {latitude},{longitude}.</p>"
html_content += f"<p>Based off sensor data from <a href='{content['data']['city']['url']}'>{content['data']['city']['name']}</a>:</p>"
html_content += f"<p>The AQI level is: {content['data']['aqi']}.</p>"
html_content += f"<p>The N02 level is: {content['data']['iaqi']['no2']['v']}.</p>"
html_content += f"<p>The O3 level is: {content['data']['iaqi']['o3']['v']}.</p>"
html_content += f"<p>The temperature is: {content['data']['iaqi']['t']['v']}°C.</p>"
html = f"""
<!DOCTYPE html>
<head>
<title>Geolocation: Weather</title>
</head>
<body>
<style>{html_style}</style>
<div id="container">
{html_content}
</div>
</body>
"""
headers = {"content-type": "text/html;charset=UTF-8"}
return Response(html, headers=headers)
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/workers/examples/geolocation-app-weather/#page","headline":"Geolocation: Weather application","description":"Fetch weather data from an API using the user's geolocation data.","url":"https://developers.cloudflare.com/workers/examples/geolocation-app-weather/","inLanguage":"en","image":"https://developers.cloudflare.com/workers/examples/geolocation-app-weather/og.png?v=972760bfcd66e48d","dateModified":"2026-04-23","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["Geolocation","JavaScript","TypeScript","Python"]}
description: Personalize website styling based on localized user time. title: "Geolocation: Custom Styling" image: https://developers.cloudflare.com/workers/examples/geolocation-custom-styling/og.png?v=6862e2c3f7438877
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/workers/llms.txt
Use this file to discover all available pages before exploring further.

