Why I Stopped Paying for Weather APIs
I was paying $40/month for a weather API. Then I found Open-Meteo — completely free, no API key, no rate limits, and the data is actually better.
- Global coverage — any latitude/longitude on Earth
- 16-day forecast + historical data back to 1940
- 80+ weather variables (temperature, rain, wind, UV, air quality)
- No API key — just make HTTP requests
- No rate limits for non-commercial use
Get Current Weather (3 Lines)
import requests
resp = requests.get("https://api.open-meteo.com/v1/forecast", params={
"latitude": 40.71, "longitude": -74.01, # New York
"current_weather": True
})
weather = resp.json()["current_weather"]
print(f"Temperature: {weather['temperature']}°C")
print(f"Wind: {weather['windspeed']} km/h")
print(f"Condition: {'Sunny' if weather['weathercode'] == 0 else 'See code ' + str(weather['weathercode'])}")
5-Day Forecast with Hourly Data
resp = requests.get("https://api.open-meteo.com/v1/forecast", params={
"latitude": 51.51, "longitude": -0.13, # London
"hourly": "temperature_2m,precipitation_probability,windspeed_10m",
"forecast_days": 5
})
data = resp.json()["hourly"]
for i in range(0, len(data["time"]), 6): # Every 6 hours
time = data["time"][i]
temp = data["temperature_2m"][i]
rain = data["precipitation_probability"][i]
wind = data["windspeed_10m"][i]
print(f"{time}: {temp}°C, {rain}% rain, {wind} km/h wind")
Historical Weather (Back to 1940!)
resp = requests.get("https://archive-api.open-meteo.com/v1/archive", params={
"latitude": 48.85, "longitude": 2.35, # Paris
"start_date": "2025-01-01",
"end_date": "2025-01-31",
"daily": "temperature_2m_max,temperature_2m_min,precipitation_sum"
})
daily = resp.json()["daily"]
for i in range(len(daily["time"])):
date = daily["time"][i]
high = daily["temperature_2m_max"][i]
low = daily["temperature_2m_min"][i]
rain = daily["precipitation_sum"][i]
print(f"{date}: {low}–{high}°C, {rain}mm rain")
Air Quality Index
resp = requests.get("https://air-quality-api.open-meteo.com/v1/air-quality", params={
"latitude": 39.90, "longitude": 116.40, # Beijing
"hourly": "pm2_5,pm10,us_aqi",
"forecast_days": 1
})
data = resp.json()["hourly"]
for i in range(0, 24, 3):
print(f"{data['time'][i]}: AQI={data['us_aqi'][i]}, PM2.5={data['pm2_5'][i]}")
Geocoding (City Name → Coordinates)
def get_coordinates(city):
resp = requests.get("https://geocoding-api.open-meteo.com/v1/search", params={
"name": city, "count": 1
})
result = resp.json()["results"][0]
return result["latitude"], result["longitude"], result["name"], result["country"]
lat, lon, name, country = get_coordinates("Tokyo")
print(f"{name}, {country}: {lat}, {lon}")
# Now get weather
resp = requests.get("https://api.open-meteo.com/v1/forecast", params={
"latitude": lat, "longitude": lon, "current_weather": True
})
print(f"Temperature: {resp.json()['current_weather']['temperature']}°C")
Build a Weather CLI Tool
#!/usr/bin/env python3
import requests, sys
def weather(city):
# Geocode
geo = requests.get("https://geocoding-api.open-meteo.com/v1/search",
params={"name": city, "count": 1}).json()
if not geo.get("results"):
print(f"City not found: {city}")
return
loc = geo["results"][0]
# Weather
w = requests.get("https://api.open-meteo.com/v1/forecast", params={
"latitude": loc["latitude"], "longitude": loc["longitude"],
"current_weather": True,
"daily": "temperature_2m_max,temperature_2m_min,precipitation_sum",
"timezone": "auto", "forecast_days": 3
}).json()
cw = w["current_weather"]
print(f"\n{loc['name']}, {loc.get('country', '')} — Now:")
print(f" {cw['temperature']}°C, wind {cw['windspeed']} km/h")
print(f"\n3-day forecast:")
for i in range(3):
d = w["daily"]
print(f" {d['time'][i]}: {d['temperature_2m_min'][i]}–{d['temperature_2m_max'][i]}°C, rain: {d['precipitation_sum'][i]}mm")
city = sys.argv[1] if len(sys.argv) > 1 else input("City: ")
weather(city)
Usage: python3 weather.py "San Francisco"
All Available Variables
| Category | Variables |
|---|---|
| Temperature |
temperature_2m, apparent_temperature, dewpoint_2m
|
| Precipitation |
rain, snowfall, precipitation_probability
|
| Wind |
windspeed_10m, windgusts_10m, winddirection_10m
|
| Solar |
uv_index, sunshine_duration, shortwave_radiation
|
| Pressure |
surface_pressure, pressure_msl
|
| Cloud |
cloudcover, cloudcover_low/mid/high
|
| Soil |
soil_temperature_0cm, soil_moisture_0_to_1cm
|
Comparison with Paid APIs
| Feature | Open-Meteo | OpenWeather | WeatherAPI |
|---|---|---|---|
| Price | Free | Free tier + paid | Free tier + paid |
| API Key | Not needed | Required | Required |
| Rate Limit | None* | 60/min (free) | 1M/month |
| Forecast Days | 16 | 5 (free) | 3 (free) |
| Historical Data | 1940–now | Paid only | Paid only |
| Air Quality | Free | Paid only | Paid only |
| Variables | 80+ | 20+ | 30+ |
*Fair use policy applies for non-commercial use.
What do you build with weather data? I'm always looking for creative API use cases.
I write about free APIs and developer tools every week. Follow for more practical tutorials.
More from me: 10 Dev Tools I Use Daily | 77 Scrapers on a Schedule | 150+ Free APIs
Building something with free APIs? I write about developer tools and free APIs every week. Follow for more.
Need automated data collection or a custom scraper? Email me at spinov001@gmail.com
Top comments (0)