Open-Meteo Scraper: Global Weather & Historical Archive
Pricing
from $0.37 / 1,000 weather scrapeds
Open-Meteo Scraper: Global Weather & Historical Archive
Scrape Open-Meteo for global weather: current conditions, hourly and daily forecasts, and historical reanalysis back to 1940. Any coordinate or place name, no key.
Pricing
from $0.37 / 1,000 weather scrapeds
Rating
0.0
(0)
Developer
Arman Hossain
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share

Returns weather for any coordinate on earth: current conditions, hourly and daily forecasts out to 16 days, and reanalysis history stretching back to 1940. One Actor covers both, with a single switch between the two modes.
Open-Meteo is an open weather API with no key, no signup and no quota for non-commercial use. There's no browser, no proxy and no login. Place names are resolved through Open-Meteo's own geocoder, so "Tokyo" is as valid an input as "35.68,139.69".
Agent skill: SKILL.md
https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/open-meteo-weather-scraper.md
What you get
| Field | What it holds |
|---|---|
location | The location exactly as you passed it |
resolvedName, admin1, country, countryCode | Geocoder match for place-name inputs (null when you passed coordinates) |
latitude, longitude, elevation | The grid cell Open-Meteo actually served, plus its elevation in metres |
timezone, timezoneAbbreviation, utcOffsetSeconds | Timezone the series timestamps are expressed in |
mode | forecast or historical |
currentTemperature, currentApparentTemperature, currentRelativeHumidity | Live conditions (forecast mode only) |
currentPrecipitation, currentWindSpeed, currentWindDirection | Live conditions, continued |
currentWeatherCode, currentWeatherDescription | WMO code plus its plain-English meaning |
hourly, daily | Column-oriented forecast series: a time array plus one array per variable |
historicalSeries | The same structure for archive runs, holding hourly and daily |
units | Unit string for every variable returned, split by current, hourly and daily |
sourceUrl | The exact Open-Meteo URL used, so any record is reproducible by hand |
scrapedAt | Run timestamp |
RUN_SUMMARY in the key-value store holds per-run counts, the settings you used, and any location that failed.
Use cases
- Backtesting against sales. Pull ten years of daily highs for every store postcode.
- Agricultural monitoring. Soil moisture and precipitation series for a portfolio of farms.
- Climate research. Reanalysis back to 1940 without a vendor contract or per-call billing.
- Energy and demand modelling. Hourly temperature and cloud cover as model features.
- Travel and events. A 16-day outlook for a list of destinations, refreshed daily.
Quick start
Three locations, three-day forecast with the defaults:
{"locations": ["52.52,13.41", "Tokyo", "-33.8688,151.2093"]}
Hourly modelling features, aligned to UTC, two weeks out:
{"locations": ["40.7128,-74.0060", "51.5072,-0.1276"],"variables": ["temperature_2m", "precipitation", "cloud_cover", "wind_speed_10m"],"dailyVariables": ["temperature_2m_max", "temperature_2m_min", "precipitation_sum"],"forecastDays": 14,"timezone": "UTC","units": "metric"}
A decade of daily history for a backtest:
{"locations": ["Berlin", "Paris", "Madrid"],"variables": [],"dailyVariables": ["temperature_2m_max", "temperature_2m_min", "precipitation_sum", "sunshine_duration"],"historicalFrom": "2015-01-01","historicalTo": "2024-12-31","timezone": "UTC"}
Input
| Field | Type | Default | Notes |
|---|---|---|---|
locations | array | required | "lat,lon" strings or place names. Place names are geocoded to the single best match. |
variables | array | temperature_2m, relative_humidity_2m, precipitation, wind_speed_10m | Hourly variable names. An empty array means no hourly series. |
dailyVariables | array | weather_code, temperature_2m_max, temperature_2m_min, precipitation_sum | Daily aggregates. An empty array means no daily series. |
forecastDays | integer | 3 | Anything from 1 to 16. Ignored in historical mode. |
historicalFrom | string | "" | YYYY-MM-DD. Setting it switches to the archive API. |
historicalTo | string | "" | YYYY-MM-DD. Defaults to yesterday. |
timezone | string | auto | IANA name, or auto for each location's local time. |
units | string | metric | metric or imperial. |
Hourly and daily variables use different names: temperature_2m is hourly, temperature_2m_max is daily. Passing a daily name in variables makes Open-Meteo reject the whole request, and the Actor reports its reason verbatim in RUN_SUMMARY.failures. The full variable list lives in the Open-Meteo docs.
Output example
{"location": "Tokyo","resolvedName": "Tokyo","admin1": "Tokyo","country": "Japan","countryCode": "JP","latitude": 35.7,"longitude": 139.6875,"elevation": 40,"timezone": "Asia/Tokyo","timezoneAbbreviation": "GMT+9","utcOffsetSeconds": 32400,"mode": "forecast","currentTime": "2026-08-06T20:30","currentTemperature": 27.1,"currentApparentTemperature": 33.6,"currentRelativeHumidity": 91,"currentPrecipitation": 0,"currentWindSpeed": 3.3,"currentWindDirection": 139,"currentWeatherCode": 1,"currentWeatherDescription": "Mainly clear","hourly": {"time": ["2026-08-06T00:00", "2026-08-06T01:00", "2026-08-06T02:00"],"temperature_2m": [23.8, 23.3, 23.0],"precipitation": [0.2, 0.3, 0.3]},"daily": {"time": ["2026-08-06", "2026-08-07"],"weather_code": [51, 53],"temperature_2m_max": [31.1, 30.7],"temperature_2m_min": [22.6, 24.7],"precipitation_sum": [2.0, 3.1]},"historicalSeries": null,"units": {"current": { "temperature_2m": "°C", "wind_speed_10m": "km/h" },"hourly": { "time": "iso8601", "temperature_2m": "°C", "precipitation": "mm" },"daily": { "time": "iso8601", "temperature_2m_max": "°C", "precipitation_sum": "mm" }},"sourceUrl": "https://api.open-meteo.com/v1/forecast?latitude=35.6895&longitude=139.69171&timezone=auto&forecast_days=2¤t=.","scrapedAt": "2026-08-06T11:39:49.134Z"}
In historical mode hourly, daily and every current* field are null, and the series arrive under historicalSeries.hourly and historicalSeries.daily instead.
Choosing variables
Series come back column-oriented, not row-oriented: one time array and one array per variable, all the same length. Index i of every array describes the same instant. To flatten to rows in JavaScript:
const rows = record.daily.time.map((t, i) => ({date: t,max: record.daily.temperature_2m_max[i],min: record.daily.temperature_2m_min[i],rain: record.daily.precipitation_sum[i],}));
Useful hourly names: temperature_2m, apparent_temperature, precipitation, rain, snowfall, cloud_cover, wind_speed_10m, wind_gusts_10m, surface_pressure, soil_temperature_0cm, soil_moisture_0_to_7cm.
Useful daily names: weather_code, temperature_2m_max, temperature_2m_min, precipitation_sum, rain_sum, snowfall_sum, precipitation_hours, sunrise, sunset, sunshine_duration, wind_speed_10m_max, shortwave_radiation_sum.
API example
curl -X POST "https://api.apify.com/v2/acts/arman-bd~open-meteo-weather-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"locations": ["52.52,13.41", "Tokyo"],"dailyVariables": ["temperature_2m_max", "precipitation_sum"],"forecastDays": 7,"timezone": "UTC"}'
JavaScript example
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('arman-bd/open-meteo-weather-scraper').call({locations: ['Berlin', 'Paris'],historicalFrom: '2024-01-01',historicalTo: '2024-01-31',dailyVariables: ['temperature_2m_max', 'precipitation_sum'],variables: [],});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const r of items) {const d = r.historicalSeries.daily;console.log(`${r.location}: ${d.time.length} days, hottest ${Math.max(.d.temperature_2m_max)}`);}
Limits and behaviour
- Two APIs sit behind one Actor.
historicalFromroutes the request toarchive-api.open-meteo.com, and without it you getapi.open-meteo.com/v1/forecast. The archive rejects a start date without an end date, so an omittedhistoricalTobecomes yesterday. - Coordinates snap to a grid. The returned
latitudeandlongitudeare the model cell centre, typically within a few kilometres of what you asked for.elevationis that cell's elevation, which matters when comparing mountain and valley readings. - Bad variable names fail loudly. Open-Meteo answers HTTP 400 with a
reasonstring, that reason is copied intoRUN_SUMMARY.failures, and the run continues with the other locations. - Transient errors get retried. 429s and 5xx responses get three attempts with linear backoff.
- Each location is one request. Locations are fetched sequentially, so a hundred-location run is a hundred requests.
FAQ
Do I need an API key? No. You supply no credentials.
Do I need a proxy? No. Proxy configuration is not required to run this Actor.
How far back does the history go? To 1 January 1940, from ERA5 reanalysis. Recent days lag by a few days, which is why historicalTo defaults to yesterday rather than today.
How is this different from the NWS Scraper? NWS is the authoritative US government source and stops at the US border. Open-Meteo is global and adds 80+ years of history, but it is a model reanalysis rather than an official forecast product. Many users run both.
Why is currentTemperature null? You are in historical mode. The archive API has no concept of "now", so read historicalSeries instead.
Can I schedule it? Yes. There is no quota for reasonable non-commercial volumes, so daily or hourly refreshes are fine. Open-Meteo asks heavy commercial users to move to their paid plan.