# Global Air Quality Forecast Scraper - Hourly PM2.5 & Pollen (`ninhothedev/air-quality-forecast-scraper`) Actor

$0.15/1K 🔥 Air quality forecast scraper! Hourly PM2.5, ozone, NO2 & pollen worldwide with EU + US AQI. No key. JSON, CSV, Excel or API in seconds. Build health & allergy apps ⚡

- **URL**: https://apify.com/ninhothedev/air-quality-forecast-scraper.md
- **Developed by:** [ninhothedev](https://apify.com/ninhothedev) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.15 / 1,000 results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Global Air Quality Forecast Scraper - Hourly PM2.5, Ozone & Pollen (No API Key)

Scrape **hourly air quality forecasts and pollen counts for any coordinate on Earth** - up to 7 days ahead, with no API key, no login and no proxy required. Feed the Actor a list of latitude/longitude pairs and it returns one clean, flat row per location per hour: PM2.5, PM10, ozone, nitrogen dioxide, sulphur dioxide, carbon monoxide, dust, UV index, European AQI, US AQI, an AQI category label, and alder, birch, grass and ragweed pollen counts.

Data comes from the [Open-Meteo](https://open-meteo.com/) air quality API, which blends the CAMS European and CAMS global atmospheric composition models. It is free for non-commercial use and requires no credentials.

### How is this different from the Air Quality Scraper?

This Actor is the **forecast + pollen counterpart** to [Air Quality Scraper](https://apify.com/ninhothedev/air-quality-scraper). They are complementary, not duplicates:

| | [Air Quality Scraper](https://apify.com/ninhothedev/air-quality-scraper) | **Air Quality Forecast Scraper** (this one) |
|---|---|---|
| Time dimension | **Current conditions** - one snapshot row per location, right now | **Hourly forecast** - one row per hour, 1-7 days ahead |
| Rows per location | 1 | 24 x forecast days (up to 168) |
| Pollen | Not included | **Alder, birch, grass, ragweed** |
| Extra fields | Live measurement values | European AQI + US AQI + AQI category, UV index, dust |
| Typical use | "What is the air like right now?" | "What will the air and pollen be like tomorrow at 3pm?" |

Use the current-conditions Actor for live dashboards and alerting on *now*. Use this one for planning, allergy calendars, scheduling and any model that needs a forward-looking hourly time series.

### Features

- **No API key, no account, no proxy** - runs out of the box.
- **Worldwide coverage** - any latitude/longitude, 11 km resolution.
- **Hourly granularity** - one dataset item per location-hour, ready for time-series charts.
- **Pollen forecasts** - alder, birch, grass and ragweed grains/m3 (Europe).
- **Both AQI standards** - European AQI and US AQI in the same row.
- **Human-readable AQI band** - `aqi_category` maps European AQI onto Good / Fair / Moderate / Poor / Very poor / Extremely poor.
- **Timezone-correct timestamps** - each `time` value is full ISO-8601 with the location's real UTC offset.
- **Clean, flat schema** - no nested objects, exports straight to CSV, Excel, JSON or Google Sheets.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | select | `forecast` | Scraping mode. Currently `forecast` - hourly air quality and pollen per location. |
| `locations` | array | `["52.52,13.405,Berlin", "51.5074,-0.1278,London"]` | One entry per location: `"lat,lon"` or `"lat,lon,Label"`. The label is copied into `location_name`. |
| `forecastDays` | integer | `3` | Days of hourly forecast per location (24 rows per day). Max 7. |
| `maxItems` | integer | `1000` | Hard cap on total rows pushed across all locations. Max 10000. |

#### Example input

```json
{
  "mode": "forecast",
  "locations": [
    "52.52,13.405,Berlin",
    "51.5074,-0.1278,London",
    "40.7128,-74.0060,New York",
    "35.6762,139.6503,Tokyo"
  ],
  "forecastDays": 3,
  "maxItems": 1000
}
```

### Output

One item per location-hour. Every field is nullable; hours where every pollutant is missing are dropped automatically.

```json
{
  "location_name": "Berlin",
  "latitude": 52.5,
  "longitude": 13.400002,
  "timezone": "Europe/Berlin",
  "elevation": 37.0,
  "time": "2026-07-28T00:00:00+02:00",
  "pm10": 8.9,
  "pm2_5": 4.8,
  "carbon_monoxide": 134.0,
  "nitrogen_dioxide": 6.9,
  "sulphur_dioxide": 0.6,
  "ozone": 60.0,
  "dust": 0.0,
  "uv_index": 0.0,
  "european_aqi": 24,
  "us_aqi": 34,
  "alder_pollen": 0.0,
  "birch_pollen": 0.0,
  "grass_pollen": 6.0,
  "ragweed_pollen": 0.0,
  "aqi_category": "Fair",
  "source": "open-meteo",
  "scraped_at": "2026-07-28T13:45:35.738263+00:00"
}
```

#### Field reference

| Field | Unit | Notes |
|---|---|---|
| `location_name` | - | Your label, or `"lat,lon"` if none supplied |
| `latitude`, `longitude` | degrees | Snapped to the model grid cell |
| `timezone` | IANA | Resolved automatically from coordinates |
| `elevation` | m | Grid-cell elevation |
| `time` | ISO-8601 | Local wall-clock time with real UTC offset |
| `pm10`, `pm2_5` | ug/m3 | Particulate matter |
| `carbon_monoxide`, `nitrogen_dioxide`, `sulphur_dioxide`, `ozone` | ug/m3 | Gaseous pollutants |
| `dust` | ug/m3 | Saharan/mineral dust |
| `uv_index` | index | Clear-sky UV index |
| `european_aqi` | EAQI | 0-100+, EEA scale |
| `us_aqi` | US AQI | 0-500, EPA scale |
| `alder_pollen`, `birch_pollen`, `grass_pollen`, `ragweed_pollen` | grains/m3 | Europe only |
| `aqi_category` | - | Good / Fair / Moderate / Poor / Very poor / Extremely poor |
| `source` | - | Always `open-meteo` |
| `scraped_at` | ISO-8601 | UTC run timestamp |

**AQI category bands** (European AQI): 0-20 Good, 20-40 Fair, 40-60 Moderate, 60-80 Poor, 80-100 Very poor, above 100 Extremely poor.

### Use cases

- **Health apps** - warn asthma, COPD and cardiovascular users hours before a PM2.5 or ozone spike instead of after it.
- **Allergy forecasts** - drive pollen calendars and medication reminders from real birch, grass, alder and ragweed counts.
- **Environmental research** - build reproducible multi-city hourly pollutant panels for exposure and epidemiology studies.
- **Smart home** - schedule air purifiers, HVAC recirculation and window-opening automations around forecast AQI.

Also useful for running/cycling apps, outdoor event planning, construction dust compliance, ESG reporting and insurance risk models.

### Pricing

Roughly **$0.5 per 1,000 rows**, plus standard Apify platform usage. A 4-city, 3-day run is 288 rows - a few cents. One API call per location returns the entire forecast window, so cost scales with locations, not with hours.

### Tips

- Fetching 7 days costs the same number of requests as 1 day; only row count changes.
- Set `maxItems` to `locations x forecastDays x 24` to keep runs predictable.
- Pollen fields are modelled for Europe; expect nulls or zeros elsewhere.
- Schedule the Actor daily and append to the same dataset to build a forecast-accuracy archive.

### Related Actors

- [Air Quality Scraper](https://apify.com/ninhothedev/air-quality-scraper) - current air-quality conditions (the "now" counterpart to this Actor)
- [MET Norway Weather Scraper](https://apify.com/ninhothedev/metno-weather-scraper) - free global weather forecasts
- [NOAA Weather Alerts Scraper](https://apify.com/ninhothedev/noaa-weather-alerts-scraper) - live US severe-weather alerts
- [USGS Water Scraper](https://apify.com/ninhothedev/usgs-water-scraper) - US river gauge and water-quality data

### Data source and legal

Data by [Open-Meteo.com](https://open-meteo.com/), based on CAMS (Copernicus Atmosphere Monitoring Service) models, licensed under CC BY 4.0. Only public, non-personal environmental data is collected - no personal data, so no GDPR obligations arise from the output. Attribute Open-Meteo when you redistribute the data.

### Development

```bash
python -m compileall -q src
python tests/test_smoke.py   # offline smoke tests, no network needed
```

# Actor input Schema

## `mode` (type: `string`):

Scraping mode. 'forecast' takes your list of coordinates and returns one row per location per forecast hour (pollutants, AQI and pollen).

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

One entry per location, formatted as "lat,lon" or "lat,lon,Label". The optional label is copied into the location\_name field of every row; without it the coordinates are used. Example: "52.52,13.405,Berlin".

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

How many days of hourly forecast to fetch per location (24 rows per day). Minimum 1, maximum 7.

## `maxItems` (type: `integer`):

Hard cap on the number of hourly rows pushed to the dataset across all locations. Use it to control run cost. Maximum 10000.

## Actor input object example

```json
{
  "mode": "forecast",
  "locations": [
    "52.52,13.405,Berlin",
    "51.5074,-0.1278,London"
  ],
  "forecastDays": 3,
  "maxItems": 1000
}
```

# Actor output Schema

## `records` (type: `string`):

No description

# 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": [
        "52.52,13.405,Berlin",
        "51.5074,-0.1278,London"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ninhothedev/air-quality-forecast-scraper").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": [
        "52.52,13.405,Berlin",
        "51.5074,-0.1278,London",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("ninhothedev/air-quality-forecast-scraper").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": [
    "52.52,13.405,Berlin",
    "51.5074,-0.1278,London"
  ]
}' |
apify call ninhothedev/air-quality-forecast-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ninhothedev/air-quality-forecast-scraper"
        }
    }
}

```

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/n2tW225MQpAKL5d2v/builds/P1uAnX0RnOR2QErNS/openapi.json
