Open-Meteo Scraper: Global Weather & Historical Archive avatar

Open-Meteo Scraper: Global Weather & Historical Archive

Pricing

from $0.37 / 1,000 weather scrapeds

Go to Apify Store
Open-Meteo Scraper: Global Weather & Historical Archive

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

Arman Hossain

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Open-Meteo Scraper: Current conditions, hourly and daily forecasts out to 16 days, and hourly-resolution history back to 1940, for any coordinate or place name

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

FieldWhat it holds
locationThe location exactly as you passed it
resolvedName, admin1, country, countryCodeGeocoder match for place-name inputs (null when you passed coordinates)
latitude, longitude, elevationThe grid cell Open-Meteo actually served, plus its elevation in metres
timezone, timezoneAbbreviation, utcOffsetSecondsTimezone the series timestamps are expressed in
modeforecast or historical
currentTemperature, currentApparentTemperature, currentRelativeHumidityLive conditions (forecast mode only)
currentPrecipitation, currentWindSpeed, currentWindDirectionLive conditions, continued
currentWeatherCode, currentWeatherDescriptionWMO code plus its plain-English meaning
hourly, dailyColumn-oriented forecast series: a time array plus one array per variable
historicalSeriesThe same structure for archive runs, holding hourly and daily
unitsUnit string for every variable returned, split by current, hourly and daily
sourceUrlThe exact Open-Meteo URL used, so any record is reproducible by hand
scrapedAtRun 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

FieldTypeDefaultNotes
locationsarrayrequired"lat,lon" strings or place names. Place names are geocoded to the single best match.
variablesarraytemperature_2m, relative_humidity_2m, precipitation, wind_speed_10mHourly variable names. An empty array means no hourly series.
dailyVariablesarrayweather_code, temperature_2m_max, temperature_2m_min, precipitation_sumDaily aggregates. An empty array means no daily series.
forecastDaysinteger3Anything from 1 to 16. Ignored in historical mode.
historicalFromstring""YYYY-MM-DD. Setting it switches to the archive API.
historicalTostring""YYYY-MM-DD. Defaults to yesterday.
timezonestringautoIANA name, or auto for each location's local time.
unitsstringmetricmetric 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&current=.",
"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. historicalFrom routes the request to archive-api.open-meteo.com, and without it you get api.open-meteo.com/v1/forecast. The archive rejects a start date without an end date, so an omitted historicalTo becomes yesterday.
  • Coordinates snap to a grid. The returned latitude and longitude are the model cell centre, typically within a few kilometres of what you asked for. elevation is that cell's elevation, which matters when comparing mountain and valley readings.
  • Bad variable names fail loudly. Open-Meteo answers HTTP 400 with a reason string, that reason is copied into RUN_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.