# Weather API — Forecast, Historical & Air Quality (Open-Meteo) (`highbrow_fame/weather-api`) Actor

Current conditions, hourly and 16-day forecast, air quality and historical weather back to 1940 for any city or coordinates. No key, one record per location. Unofficial Open-Meteo API.

- **URL**: https://apify.com/highbrow_fame/weather-api.md
- **Developed by:** [yestrue](https://apify.com/highbrow_fame) (community)
- **Categories:** Developer tools, Automation, Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.30 / 1,000 locations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Weather API — Forecast, Historical & Air Quality (Open-Meteo)

Weather for any place on Earth as one clean JSON record per location: current conditions, an hour-by-hour forecast, a daily forecast up to 16 days out, current air quality (European and US AQI, PM10, PM2.5, NO₂, SO₂, ozone, CO, UV) and, when you ask for it, historical weather for any date range back to 1940. Give it city names or coordinates, pick metric or imperial, and every number comes back with its unit and every weather code with a plain-English description. Built on Open-Meteo's public, key-less geocoding, forecast, archive and air-quality endpoints.

**Try it in 1 minute:**

1. Press **Start** — the prefilled input gets the weather for Berlin and New York (by name) and for `52.52,13.41` (by coordinates).
2. Seconds later the **Output** tab shows three records with current conditions, 168 hourly rows, 7 daily rows and air quality each.
3. Download JSON, CSV or Excel, or add your own places, raise **Forecast days** to 16, switch **Units** to imperial, or set **Historical from / to** for a past date range.

Price: **$0.30 per 1,000 locations** (one location = one record with current, hourly, daily, air quality and history inside). Names the geocoder does not know, invalid inputs and requests Open-Meteo refuses are free.

**Use it to:**

- Feed an AI agent or chatbot that answers "what's the weather in …" with real numbers instead of guesses.
- Pull the 16-day forecast for a list of venues, depots, farms or construction sites every morning into a sheet or a dashboard.
- Build historical weather datasets for analysis: a year of daily and hourly temperature, rain, snow and wind for each store or city.
- Enrich events, orders or incidents with the weather at their place and time (coordinates in, conditions out).
- Watch air quality and UV for the cities your users live in, without signing up for a weather vendor.

### How it works

1. **Locations** are parsed in every form: a place name (`Berlin`, `Paris, Texas` — the part after the comma picks among same-named places), a `lat,lng` pair (`52.52,13.41`) or, via the API, `{ lat, lng }` / `{ name }` objects. Duplicates are dropped; an input that is neither a name nor coordinates gets a free `INVALID_INPUT` record.
2. **Names** are resolved with Open-Meteo's geocoder (`geocoding-api.open-meteo.com/v1/search`) into coordinates plus the `location` block (name, country, region, time zone, population). No match is a free `NOT_FOUND`.
3. **Forecast** comes from `api.open-meteo.com/v1/forecast` with 15 current variables, 10 hourly variables and 14 daily variables for 1-16 days in the location's own time zone. **Air quality** (`air-quality-api.open-meteo.com`) and, with a date range, the **historical archive** (`archive-api.open-meteo.com`, ERA5 reanalysis back to 1940) are fetched at the same time — 2 to 4 requests per location.
4. Open-Meteo's arrays-per-variable answers are transposed into rows of friendly fields (`temperature`, `feelsLike`, `windSpeed` …), each WMO weather code gets a `description`, and the units of every field go into one `units` object on the record.

Requests go directly to Open-Meteo (no proxy, unless a connection drops); its per-IP rate limit (HTTP 429) is waited out and retried on the same route. Open-Meteo publishes no weather warnings, so `alerts` is always an empty list.

### Input

| Field | What it does |
|---|---|
| `locations` | Places, one per line: a name (`Berlin`, `Paris, Texas`) or `lat,lng` (`52.52,13.41`). Objects `{ lat, lng }` / `{ name }` via the API. |
| `forecastDays` | Days of daily and hourly forecast, 1-16 (default 7). |
| `includeHourly` | Add the hour-by-hour forecast (default on). |
| `units` | `metric` (°C, km/h, mm; snow in cm) or `imperial` (°F, mph, inch). |
| `includeAirQuality` | Add current air quality (default on; one extra request). |
| `historicalFrom`, `historicalTo` | `YYYY-MM-DD` dates; adds `historical { daily[], hourly[] }` from the archive. At most 366 days per location, back to 1940-01-01; one date alone means that day. |
| `hourlyLimit` | Cuts the forecast's hourly list after this many hours (default 168 = 7 days, max 384). |
| `maxConcurrency` | Locations fetched in parallel (default 4). |
| `proxyConfiguration` | Used only to retry after a network error; the first try is direct. |

### Output

One record per location:

| Field | What it is |
|---|---|
| `location` | `{ name, country, countryCode, admin1, timezone, population }` from the geocoder; for a coordinate input only `timezone` is filled |
| `lat`, `lng`, `elevation`, `timezone`, `utcOffsetSeconds` | The point the weather is for, the model grid cell's elevation (m), and the local time zone every time in the record is in |
| `units` | `{ system, temperature, humidity, feelsLike, precipitation, snowfall, windSpeed, windDirection, pressureMsl, … }` — the unit of every numeric field |
| `current` | `{ time, temperature, humidity, feelsLike, isDay, precipitation, rain, showers, snowfall, weatherCode, description, cloudCover, pressureMsl, surfacePressure, windSpeed, windDirection, windGusts }` |
| `hourly[]` | `{ time, temperature, humidity, feelsLike, precipitationProbability, precipitation, weatherCode, description, cloudCover, windSpeed, windDirection, uvIndex }` from midnight today |
| `daily[]` | `{ date, weatherCode, description, temperatureMax, temperatureMin, feelsLikeMax, feelsLikeMin, sunrise, sunset, uvIndexMax, precipitationSum, rainSum, snowfallSum, precipitationProbabilityMax, windSpeedMax, windGustsMax }` |
| `airQuality` | `{ time, europeanAqi, usAqi, pm10, pm25, carbonMonoxide, nitrogenDioxide, sulphurDioxide, ozone, uvIndex, units }` for the current hour, or null when off |
| `historical` | `{ from, to, daily[], hourly[] }` for the dates you asked for (no precipitation probability or UV in the archive), or null |
| `alerts[]`, `warnings[]` | `alerts` is always `[]` (Open-Meteo has no warnings); `warnings` notes a failed air-quality request or a qualifier that matched no candidate |
| `input`, `status`, `error`, `scrapedAt` | What you gave, `OK` / `NOT_FOUND` / `INVALID_INPUT` / `FAILED`, the reason, and when |

#### Example

```json
{
  "input": "Berlin",
  "location": { "name": "Berlin", "country": "Germany", "countryCode": "DE", "admin1": "State of Berlin", "timezone": "Europe/Berlin", "population": 3426354 },
  "lat": 52.52437,
  "lng": 13.41053,
  "elevation": 38,
  "timezone": "Europe/Berlin",
  "utcOffsetSeconds": 7200,
  "units": { "system": "metric", "temperature": "°C", "humidity": "%", "feelsLike": "°C", "precipitation": "mm", "rain": "mm", "showers": "mm", "snowfall": "cm", "cloudCover": "%", "pressureMsl": "hPa", "surfacePressure": "hPa", "windSpeed": "km/h", "windDirection": "°", "windGusts": "km/h", "precipitationProbability": "%", "temperatureMax": "°C", "temperatureMin": "°C", "feelsLikeMax": "°C", "feelsLikeMin": "°C", "precipitationSum": "mm", "rainSum": "mm", "snowfallSum": "cm", "precipitationProbabilityMax": "%", "windSpeedMax": "km/h", "windGustsMax": "km/h" },
  "current": { "time": "2026-10-19T20:15", "temperature": 8.7, "humidity": 62, "feelsLike": 5.8, "isDay": false, "precipitation": 0, "rain": 0, "showers": 0, "snowfall": 0, "weatherCode": 0, "description": "Clear sky", "cloudCover": 0, "pressureMsl": 1029.7, "surfacePressure": 1025, "windSpeed": 7.8, "windDirection": 68, "windGusts": 18 },
  "hourly": [
    { "time": "2026-10-19T00:00", "temperature": 11.6, "humidity": 80, "feelsLike": 9.4, "precipitationProbability": 0, "precipitation": 0, "weatherCode": 3, "description": "Overcast", "cloudCover": 100, "windSpeed": 12.2, "windDirection": 66, "uvIndex": 0 }
  ],
  "daily": [
    { "date": "2026-10-19", "weatherCode": 3, "description": "Overcast", "temperatureMax": 11.8, "temperatureMin": 5.3, "feelsLikeMax": 9.4, "feelsLikeMin": 2.5, "sunrise": "2026-10-19T07:38", "sunset": "2026-10-19T18:02", "uvIndexMax": 2.65, "precipitationSum": 0, "rainSum": 0, "snowfallSum": 0, "precipitationProbabilityMax": 0, "windSpeedMax": 12.9, "windGustsMax": 31.3 },
    { "date": "2026-10-20", "weatherCode": 80, "description": "Slight rain showers", "temperatureMax": 10.8, "temperatureMin": 5.1, "feelsLikeMax": 8.3, "feelsLikeMin": 2.2, "sunrise": "2026-10-20T07:40", "sunset": "2026-10-20T18:00", "uvIndexMax": 2.15, "precipitationSum": 0.6, "rainSum": 0.6, "snowfallSum": 0, "precipitationProbabilityMax": 14, "windSpeedMax": 13.1, "windGustsMax": 31 }
  ],
  "airQuality": { "time": "2026-10-19T20:00", "europeanAqi": 27, "usAqi": 28, "pm10": 7.4, "pm25": 6, "carbonMonoxide": 198, "nitrogenDioxide": 15.5, "sulphurDioxide": 3.3, "ozone": 46, "uvIndex": 0, "units": { "europeanAqi": "EAQI", "usAqi": "USAQI", "pm10": "μg/m³", "pm25": "μg/m³", "carbonMonoxide": "μg/m³", "nitrogenDioxide": "μg/m³", "sulphurDioxide": "μg/m³", "ozone": "μg/m³" } },
  "historical": null,
  "alerts": [],
  "warnings": [],
  "status": "OK",
  "error": null,
  "scrapedAt": "2026-10-19T18:30:00.000Z"
}
```

### FAQ

**Is this an official API?** No, it's an unofficial API built on public pages/endpoints — Open-Meteo's free, key-less weather, geocoding, archive and air-quality APIs (open-meteo.com, CC BY 4.0 data). This Actor only shapes their answers into stable JSON records; the forecasts themselves come from the national weather services Open-Meteo combines (DWD, NOAA, Météo-France, ECMWF and others).

**Why does `alerts` stay empty?** Open-Meteo has no weather-warnings endpoint, so there is nothing to put there. The field is kept so your code can rely on the record's shape; if you need official warnings, take them from your national weather service.

**How far back and how far ahead?** Forecasts cover 1-16 days (hourly and daily). The historical archive goes back to 1940-01-01 and runs about five days behind today; a run reads at most 366 days per location, so a longer period is several runs.

**Why is a place NOT_FOUND, or the wrong one?** The geocoder knows cities, towns, villages and many postcodes by their English and local names, but not street addresses or landmarks. Qualify ambiguous names (`Paris, Texas`, `Paris, US`) or give coordinates — `lat,lng` always works. A qualifier that matches nothing takes the first candidate and says so in `warnings`.

**What times and units are these?** Every time is local to the location (`timezone`, `utcOffsetSeconds`) without an offset suffix, straight from Open-Meteo. Numbers are in the `units` you chose; the record lists the unit of every field, so a parser never has to guess.

**Like it?** A short review on the Store page helps other people find this Actor. Something missing or broken? Tell us on the Issues tab — we read every one.

### Related Actors

- [Google Trends API](https://apify.com/highbrow_fame/google-trends-reliable) — interest over time and by region
- [OpenStreetMap Places](https://apify.com/highbrow_fame/openstreetmap-places) — POIs, addresses and opening hours
- [Google News API](https://apify.com/highbrow_fame/google-news-api) — headlines by keyword and topic
- [Web Fetch API](https://apify.com/highbrow_fame/web-fetch-api) — any URL as HTML, text, Markdown or JSON
- [RSS & Atom Feed Reader](https://apify.com/highbrow_fame/rss-feed-reader) — any feed or website as one clean list

# Actor input Schema

## `locations` (type: `array`):

Places to get weather for, one per line: a city or town name ("Berlin", "Paris, Texas" — the part after the comma picks among same-named places) or coordinates as "lat,lng" ("52.52,13.41"). Via the API, objects { lat, lng } or { name } work too.

## `forecastDays` (type: `integer`):

How many days of daily (and hourly) forecast, starting today: 1 to 16.

## `includeHourly` (type: `boolean`):

Add the hour-by-hour forecast (temperature, feels-like, humidity, precipitation and its probability, weather code, cloud cover, wind, UV index). Off gives current conditions and the daily summary only.

## `units` (type: `string`):

metric: °C, km/h, mm (snow in cm). imperial: °F, mph, inch. Every record carries its units.

## `includeAirQuality` (type: `boolean`):

Add current air quality: European and US AQI, PM10, PM2.5, CO, NO₂, SO₂, ozone and UV index (one extra request per location).

## `historicalFrom` (type: `string`):

First day of historical weather to add from Open-Meteo's archive (back to 1940-01-01). Together with Historical to, at most 366 days per location; one date alone means that single day. The archive runs about 5 days behind today.

## `historicalTo` (type: `string`):

Last day of historical weather. The record then gets historical { daily\[], hourly\[] } next to the forecast.

## `hourlyLimit` (type: `integer`):

Cuts the forecast's hourly list after this many hours (16 days are 384 hours). Historical hours are not cut; they are bounded by the date range.

## `maxConcurrency` (type: `integer`):

Locations fetched at the same time (each is 2-4 requests). Open-Meteo's free tier allows about 600 requests a minute; 4 keeps a run well inside it, and a 429 answer is waited out and retried.

## `proxyConfiguration` (type: `object`):

Used only to try again after a network error: Open-Meteo's endpoints answer directly, so the first try of every request goes out without a proxy.

## Actor input object example

```json
{
  "locations": [
    "Berlin",
    "New York",
    "52.52,13.41"
  ],
  "forecastDays": 7,
  "includeHourly": true,
  "units": "metric",
  "includeAirQuality": true,
  "hourlyLimit": 168,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Every result as a JSON record, with a status for each input.

## `resultsCsv` (type: `string`):

The same records as CSV, for a spreadsheet.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "locations": [
        "Berlin",
        "New York",
        "52.52,13.41"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("highbrow_fame/weather-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "locations": [
        "Berlin",
        "New York",
        "52.52,13.41",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("highbrow_fame/weather-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "locations": [
    "Berlin",
    "New York",
    "52.52,13.41"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call highbrow_fame/weather-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,highbrow_fame/weather-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RHTIIZZSg4B91tvid/builds/zn5dwlR8at1K05N0e/openapi.json
