# WAQI Air Quality Scraper (`parseforge/waqi-air-quality-scraper`) Actor

Export real-time air quality from the World Air Quality Index. Pull AQI, dominant pollutant, PM2.5, PM10, O3, NO2, SO2, CO, temperature, humidity, pressure and geo data for any city. Bring your own token or use the included demo key.

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

## Pricing

from $3.75 / 1,000 result items

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

![ParseForge Banner](https://github.com/ParseForge/apify-assets/blob/ad35ccc13ddd068b9d6cba33f323962e39aed5b2/banner.jpg?raw=true)

## 🌬️ WAQI Air Quality Scraper

> 🚀 **Export real-time air-quality data in seconds.** Pull **AQI, PM2.5, PM10, O3, NO2, SO2, CO, weather, and geo** for any city or bounding box from the World Air Quality Index. Free to start, full coverage with a free WAQI token.

> 🕒 **Last updated:** 2026-05-21 · **📊 20 fields** per record · **🌐 12,000+ stations** · **🏭 7 pollutants** · **🌍 Global coverage**

The **WAQI Air Quality Scraper** exports real-time air-quality readings from the **World Air Quality Index** (waqi.info, aqicn.org), the largest open AQI network on the planet. Each record returns **20 fields**, including the AQI value, the dominant pollutant, individual measurements for PM2.5, PM10, O3, NO2, SO2, and CO, weather observations (temperature, pressure, humidity, wind), the station latitude/longitude, the observation timestamp, the official station URL, and the data attributions for proper citation.

The network covers **12,000+ monitoring stations** across cities, suburbs, embassies, ports, and rural sites in nearly every country. Three run modes are supported: query a list of named cities, locate the nearest station to the caller, or sweep every station inside a custom lat/lng bounding box.

| 🎯 Target Audience | 💡 Primary Use Cases |
|---|---|
| Climate research, ESG analysts, public-health teams, real-estate due diligence, smart-city ops, news media, environmental NGOs | AQI dashboards, ESG reporting, pollution-exposure studies, location risk assessment, real-time air-quality alerts, environmental journalism |

---

### 📋 What the WAQI Air Quality Scraper does

Three run modes plus seven-pollutant breakdown:

- 🌆 **City mode.** Hand a list of city slugs (`beijing`, `shanghai`, `delhi`, `london`) and get the official station for each.
- 📍 **Here mode.** Auto-detects the nearest station to the caller IP (good for "what is the AQI right now where I am").
- 📦 **Bounds mode.** Sweep every station inside a `{lat1, lng1, lat2, lng2}` bounding box (requires your own token).
- 🏭 **Seven pollutants.** AQI plus individual PM2.5, PM10, O3, NO2, SO2, CO readings.
- 🌡️ **Weather context.** Temperature, pressure, humidity, and wind on the same row.
- 🗺️ **Geo + attribution.** Latitude, longitude, station URL, and the official data-source attributions.

Each record includes the city name, the station ID, the AQI, the dominant pollutant, the seven pollutant readings, the four weather readings, the station coordinates, the observation timestamp, the official station detail URL, the data attributions list, and the scrape time.

> 💡 **Why it matters:** WAQI is the most-cited open AQI source for ESG disclosures, real-estate due diligence, and public-health journalism. Building your own pipeline against the data service means writing a station resolver, rate-limit handler, and citation tracker. This Actor returns the row, the weather, the geo, and the attributions on every call.

> 🔑 **Token note:** the Actor ships with the public `demo` token so anyone can try it. The demo token only returns the Shanghai sample station regardless of the city you ask for. **For full 12,000+ station coverage and bounding-box queries, grab a free WAQI token at `https://aqicn.org/data-platform/token/` and pass it in the `token` input.** Free WAQI tokens have generous limits for individual and research use.

---

### 🎬 Full Demo

_🚧 Coming soon: a 3-minute walkthrough showing how to go from sign-up to a downloaded dataset._

---

### ⚙️ Input

<table>
<thead>
<tr><th>Input</th><th>Type</th><th>Default</th><th>Behavior</th></tr>
</thead>
<tbody>
<tr><td><code>maxItems</code></td><td>integer</td><td><code>10</code></td><td>Records to return. Free plan caps at 10, paid plan at 1,000,000.</td></tr>
<tr><td><code>mode</code></td><td>string</td><td><code>"city"</code></td><td><code>city</code>, <code>here</code>, or <code>bounds</code>.</td></tr>
<tr><td><code>cities</code></td><td>array</td><td><code>["beijing","shanghai","tokyo","delhi","london"]</code></td><td>City slugs when <code>mode = "city"</code>.</td></tr>
<tr><td><code>bounds</code></td><td>object</td><td><code>null</code></td><td>Used when <code>mode = "bounds"</code>. Object <code>{lat1, lng1, lat2, lng2}</code>. Your own token required.</td></tr>
<tr><td><code>token</code></td><td>string</td><td><code>"demo"</code></td><td>WAQI access token. <code>demo</code> returns the Shanghai sample station only. Replace with your own free WAQI token for full coverage.</td></tr>
</tbody>
</table>

**Example: AQI for five major cities (with your own token).**

```json
{
    "maxItems": 5,
    "mode": "city",
    "cities": ["beijing", "shanghai", "tokyo", "delhi", "london"],
    "token": "YOUR_WAQI_TOKEN"
}
````

**Example: every station inside a Tokyo bounding box.**

```json
{
    "maxItems": 200,
    "mode": "bounds",
    "bounds": { "lat1": 35.5, "lng1": 139.5, "lat2": 35.8, "lng2": 139.9 },
    "token": "YOUR_WAQI_TOKEN"
}
```

> ⚠️ **Good to Know:** the included `demo` token is a public preview key from WAQI. It returns the Shanghai station for almost any city slug and does not support bounding-box queries. Get a free token at `https://aqicn.org/data-platform/token/` for full 12,000+ station coverage.

***

### 📊 Output

Each air-quality record contains **20 fields**. Download the dataset as CSV, Excel, JSON, or XML.

#### 🧾 Schema

| Field | Type | Example |
|---|---|---|
| 🏙️ `cityName` | string | `"Shanghai (上海)"` |
| 🆔 `stationId` | number | `1437` |
| 🌬️ `aqi` | number | `82` |
| 🏭 `dominantPollutant` | string | `"pm25"` |
| ⚗️ `pm25` | number | null | `82` |
| ⚗️ `pm10` | number | null | `29` |
| ⚗️ `o3` | number | null | `22.8` |
| ⚗️ `no2` | number | null | `8.3` |
| ⚗️ `so2` | number | null | `4.6` |
| ⚗️ `co` | number | null | `10` |
| 🌡️ `temperature` | number | null | `22` |
| 🌪️ `pressure` | number | null | `1008` |
| 💧 `humidity` | number | null | `88` |
| 🍃 `wind` | number | null | `3.6` |
| 📍 `latitude` | number | `31.2047372` |
| 📍 `longitude` | number | `121.4489017` |
| 🕒 `observedAt` | ISO 8601 | `"2026-05-21T05:00:00+08:00"` |
| 🔗 `stationUrl` | string | `"https://aqicn.org/city/shanghai"` |
| 📑 `attributions` | array | See sample |
| 🕒 `scrapedAt` | ISO 8601 | `"2026-05-20T22:15:29.901Z"` |

#### 📦 Sample records

<details>
<summary><strong>🌆 Shanghai station, AQI 82, dominant PM2.5</strong></summary>

```json
{
    "cityName": "Shanghai (上海)",
    "stationId": 1437,
    "aqi": 82,
    "dominantPollutant": "pm25",
    "pm25": 82,
    "pm10": 29,
    "o3": 22.8,
    "no2": 8.3,
    "so2": 4.6,
    "co": 10,
    "temperature": 22,
    "pressure": 1008,
    "humidity": 88,
    "wind": 3.6,
    "latitude": 31.2047372,
    "longitude": 121.4489017,
    "observedAt": "2026-05-21T05:00:00+08:00",
    "stationUrl": "https://aqicn.org/city/shanghai",
    "attributions": [
        { "url": "https://sthj.sh.gov.cn/", "name": "Shanghai Environment Monitoring Center" },
        { "url": "http://106.37.208.233:20035/emcpublish/", "name": "China National Urban air quality real-time publishing platform" },
        { "url": "https://china.usembassy-china.org.cn/embassy-consulates/shanghai/air-quality-monitor-stateair/", "name": "U.S. Consulate Shanghai Air Quality Monitor" },
        { "url": "https://waqi.info/", "name": "World Air Quality Index Project" }
    ],
    "scrapedAt": "2026-05-20T22:15:29.901Z"
}
```

</details>

<details>
<summary><strong>🇨🇳 Beijing station (with own WAQI token)</strong></summary>

```json
{
    "cityName": "Beijing (北京)",
    "stationId": 1451,
    "aqi": 130,
    "dominantPollutant": "pm25",
    "pm25": 130,
    "pm10": 70,
    "o3": 35,
    "no2": 22,
    "so2": 4,
    "co": 9,
    "temperature": 26,
    "pressure": 1014,
    "humidity": 38,
    "wind": 2.5,
    "latitude": 39.954592,
    "longitude": 116.468117,
    "observedAt": "2026-05-21T05:00:00+08:00",
    "stationUrl": "https://aqicn.org/city/beijing",
    "attributions": [
        { "url": "http://www.bjmemc.com.cn/", "name": "Beijing Environmental Protection Monitoring Center" },
        { "url": "https://waqi.info/", "name": "World Air Quality Index Project" }
    ],
    "scrapedAt": "2026-05-20T22:15:30.000Z"
}
```

</details>

***

### ✨ Why choose this Actor

| | Capability |
|---|---|
| 🌬️ | **12,000+ stations.** Cities, suburbs, embassies, ports, rural and roadside sites worldwide. |
| 🏭 | **7 pollutants.** AQI plus PM2.5, PM10, O3, NO2, SO2, CO on every row. |
| 🌡️ | **Weather context.** Temperature, pressure, humidity, wind from co-located sensors. |
| 📦 | **3 query modes.** City list, nearest station, or bounding box. |
| 🔑 | **Bring your own token.** Public demo key included to test, swap in your free WAQI token for full coverage. |
| ⚡ | **Fast.** 5 stations in under 4 seconds. |
| 📑 | **Citation-ready.** Every record carries the official WAQI attributions list. |

> 📊 WAQI is the canonical open AQI feed cited in ESG disclosures, real-estate due diligence, and global-health reporting. Real-time, attributed data is the foundation of any air-quality workflow.

***

### 📈 How it compares to alternatives

| Approach | Cost | Coverage | Refresh | Filters | Setup |
|---|---|---|---|---|---|
| **⭐ WAQI Air Quality Scraper** *(this Actor)* | $5 free credit, then pay-per-use | **12,000+ stations** | **Live per run** | city, here, bounding box | ⚡ 2 min |
| Commercial AQI APIs | $99+/month | Vendor network | Streaming | Many | ⏳ Onboarding |
| Direct WAQI integration | Free | Worldwide | Per-call | Many | 🐢 Dev work |
| National regulator portals | Free | Country-specific | Hourly | Limited | 🕒 Variable |

Pick this Actor when you want WAQI data in a clean dataset, attributed, with weather context, on demand.

***

### 🚀 How to use

1. 📝 **Sign up.** [Create a free account with $5 credit](https://console.apify.com/sign-up?fpr=vmoqkp) (takes 2 minutes).
2. 🔑 **Optional: get a free WAQI token** at `https://aqicn.org/data-platform/token/` for full station coverage.
3. 🌐 **Open the Actor.** Go to the WAQI Air Quality Scraper page on the Apify Store.
4. 🎯 **Set input.** Pick a mode (`city`, `here`, `bounds`), supply the cities or bounds, paste your token, set `maxItems`.
5. 🚀 **Run it.** Click **Start** and let the Actor collect your data.
6. 📥 **Download.** Grab your results in the **Dataset** tab as CSV, Excel, JSON, or XML.

> ⏱️ Total time from signup to downloaded dataset: **3-5 minutes.** No coding required.

***

### 💼 Business use cases

<table>
<tr>
<td width="50%" valign="top">

#### 🌱 ESG & Sustainability Reporting

- Facility-level AQI for ESG disclosures
- Supply-chain pollution exposure analysis
- Sustainability-report data backbones
- Scope-3 environmental risk inputs

</td>
<td width="50%" valign="top">

#### 🏘️ Real Estate Due Diligence

- Air-quality scoring for residential listings
- Office portfolio location risk reviews
- Tenant disclosure and amenity insights
- Acquisition due-diligence environmental data

</td>
</tr>
<tr>
<td width="50%" valign="top">

#### 🏥 Public Health Operations

- Asthma and COPD exposure forecasting
- School and hospital outdoor-activity alerts
- Vulnerable-population early warnings
- City-level pollution dashboards

</td>
<td width="50%" valign="top">

#### 🌆 Smart City & Mobility

- Routing optimisation around pollution hotspots
- Traffic-policy impact monitoring
- EV-adoption ROI dashboards
- Public transit air-quality positioning

</td>
</tr>
</table>

***

### 🔌 Automating WAQI Air Quality Scraper

Control the scraper programmatically for scheduled runs and pipeline integrations:

- 🟢 **Node.js.** Install the `apify-client` NPM package.
- 🐍 **Python.** Use the `apify-client` PyPI package.
- 📚 See the [Apify API documentation](https://docs.apify.com/api/v2) for full details.

The [Apify Schedules feature](https://docs.apify.com/platform/schedules) lets you trigger this Actor every hour. Pair with webhooks to push readings into a BI dashboard, alert Slack on AQI thresholds, or write rows to BigQuery.

***

### 🌟 Beyond business use cases

Air-quality data powers more than commercial workflows. The same structured records support research, education, civic projects, and personal initiatives.

<table>
<tr>
<td width="50%">

#### 🎓 Research and academia

- Atmospheric-science coursework with live data
- Pollution-exposure epidemiology studies
- Climate-policy reproducible papers
- Urban-planning lab projects

</td>
<td width="50%">

#### 🎨 Personal and creative

- Personal AQI dashboards for runners and cyclists
- Travel-blogger air-quality maps
- Family-health alert apps
- Hobbyist environmental data art

</td>
</tr>
<tr>
<td width="50%">

#### 🤝 Non-profit and civic

- Community-led pollution monitoring
- Environmental-justice advocacy reports
- School-district air-quality auditing
- Investigative reporting on industrial sites

</td>
<td width="50%">

#### 🧪 Experimentation

- Train AQI-forecasting ML models
- Prototype geo-targeted alert systems
- Test cross-pollutant correlation tools
- Validate satellite-vs-ground pollution data

</td>
</tr>
</table>

***

### 🤖 Ask an AI assistant about this scraper

Open a ready-to-send prompt about this ParseForge actor in the AI of your choice:

- 💬 [**ChatGPT**](https://chat.openai.com/?q=How%20do%20I%20use%20the%20WAQI%20Air%20Quality%20Scraper%20by%20ParseForge%20on%20Apify%3F%20Show%20me%20input%20examples%2C%20output%20fields%2C%20common%20use%20cases%2C%20and%20how%20to%20integrate%20it%20into%20a%20workflow.)
- 🧠 [**Claude**](https://claude.ai/new?q=How%20do%20I%20use%20the%20WAQI%20Air%20Quality%20Scraper%20by%20ParseForge%20on%20Apify%3F%20Show%20me%20input%20examples%2C%20output%20fields%2C%20common%20use%20cases%2C%20and%20how%20to%20integrate%20it%20into%20a%20workflow.)
- 🔍 [**Perplexity**](https://perplexity.ai/search?q=How%20do%20I%20use%20the%20WAQI%20Air%20Quality%20Scraper%20by%20ParseForge%20on%20Apify%3F%20Show%20me%20input%20examples%2C%20output%20fields%2C%20common%20use%20cases%2C%20and%20how%20to%20integrate%20it%20into%20a%20workflow.)
- 🅒 [**Copilot**](https://copilot.microsoft.com/?q=How%20do%20I%20use%20the%20WAQI%20Air%20Quality%20Scraper%20by%20ParseForge%20on%20Apify%3F%20Show%20me%20input%20examples%2C%20output%20fields%2C%20common%20use%20cases%2C%20and%20how%20to%20integrate%20it%20into%20a%20workflow.)

***

### ❓ Frequently Asked Questions

#### 🧩 How does it work?

Pick a mode (`city`, `here`, or `bounds`), supply the cities or bounds, paste a WAQI token, and click Start. The Actor queries WAQI for each station, normalises the response, and emits clean rows with AQI, pollutants, weather, geo, and attributions.

#### 🔑 Why is the demo token limited?

The `demo` token is the public preview key shipped by WAQI. It returns the Shanghai sample station for most city slugs and does not support bounding-box queries. Grab a free token at `https://aqicn.org/data-platform/token/` to unlock the full 12,000+ station network and bounds mode.

#### 📏 How accurate is the data?

Every record is read live from WAQI. The pollutant numbers, weather observations, and attributions are passed through unchanged from the source feed.

#### 🔁 How often is the dataset refreshed?

WAQI updates station feeds in near real time as monitoring agencies post new readings (typically hourly). Every run of this Actor reads the live feed.

#### 🌍 Which countries are covered?

WAQI aggregates feeds from environmental agencies in nearly every country, plus embassy and consulate monitors in many regions. With your own token, you can query any city slug or any bounding box.

#### ⏰ Can I schedule regular runs?

Yes. Use Apify Schedules to refresh AQI hourly or on any cron expression. Pair with webhooks to power live dashboards or alerting.

#### ⚖️ Is this data legal to use?

WAQI publishes the feeds openly under attribution. The `attributions` field in every record lists the original data providers; include them when republishing or visualising.

#### 💼 Can I use this data commercially?

Yes, with proper attribution. WAQI supports commercial use; review WAQI's terms for redistribution at scale.

#### 💳 Do I need a paid Apify plan to use this Actor?

No. The free Apify plan is enough for testing (10 records per run). A paid plan lifts the limit and unlocks scheduling and larger datasets.

#### 🔁 What happens if a run fails or gets interrupted?

Apify automatically retries transient errors. Partial datasets are preserved.

#### 📦 What is bounds mode for?

Bounds mode sweeps every WAQI station inside a `{lat1, lng1, lat2, lng2}` rectangle, ideal for city-scale or regional pollution snapshots. Requires your own WAQI token.

#### 🆘 What if I need help?

Our support team is here to help. Contact us through the Apify platform or use the Tally form linked below.

***

### 🔌 Integrate with any app

WAQI Air Quality Scraper connects to any cloud service via [Apify integrations](https://apify.com/integrations):

- [**Make**](https://docs.apify.com/platform/integrations/make) - Automate multi-step workflows
- [**Zapier**](https://docs.apify.com/platform/integrations/zapier) - Connect with 5,000+ apps
- [**Slack**](https://docs.apify.com/platform/integrations/slack) - Get run notifications in your channels
- [**Airbyte**](https://docs.apify.com/platform/integrations/airbyte) - Pipe AQI rows into your warehouse
- [**GitHub**](https://docs.apify.com/platform/integrations/github) - Trigger runs from commits and releases
- [**Google Drive**](https://docs.apify.com/platform/integrations/drive) - Export datasets straight to Sheets

You can also use webhooks to trigger downstream actions when a run finishes. Push fresh AQI rows into your monitoring backend, or alert your team in Slack when readings cross a threshold.

***

### 🔗 Recommended Actors

- [**🌍 WHO GHO Health Indicators Scraper**](https://apify.com/parseforge/who-gho-health-indicators-scraper) - Global health observatory indicators
- [**☁️ NOAA Weather Scraper**](https://apify.com/parseforge/noaa-weather-scraper) - US National Weather Service forecasts
- [**🌡️ Open-Meteo Weather Scraper**](https://apify.com/parseforge/open-meteo-weather-scraper) - Global weather and climate data
- [**📡 Measurement Lab NDT Scraper**](https://apify.com/parseforge/measurement-lab-ndt-scraper) - M-Lab broadband-speed-test servers
- [**🛰️ OpenSky Flights Scraper**](https://apify.com/parseforge/opensky-flights-scraper) - Live global aircraft positions

> 💡 **Pro Tip:** browse the complete [ParseForge collection](https://apify.com/parseforge) for more environmental and infrastructure scrapers.

***

**🆘 Need Help?** [**Open our contact form**](https://tally.so/r/BzdKgA) to request a new scraper, propose a custom data project, or report an issue.

***

> **⚠️ Disclaimer:** this Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by the World Air Quality Index Project (WAQI / aqicn.org) or any of its contributors. All trademarks mentioned are the property of their respective owners. Only publicly available air-quality data is collected.

# Actor input Schema

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

Free users: Limited to 10 items (preview). Paid users: Optional, max 1,000,000

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

'city' = list of named cities. 'here' = nearest station (uses caller IP geo). 'bounds' = every station inside a lat/lng box (your own token required).

## `cities` (type: `array`):

List of city slugs or names when mode='city'. Examples: 'beijing', 'shanghai', 'london', 'new-york'.

## `bounds` (type: `object`):

Used when mode='bounds'. Object {lat1, lng1, lat2, lng2}. Requires your own token.

## `token` (type: `string`):

Optional. Free signup at aqicn.org/data-platform/token/ for global station access. The default 'demo' token returns Shanghai only.

## Actor input object example

```json
{
  "maxItems": 10,
  "mode": "city",
  "cities": [
    "beijing",
    "shanghai",
    "tokyo",
    "delhi",
    "london"
  ],
  "token": "demo"
}
```

# Actor output Schema

## `overview` (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 = {
    "maxItems": 10,
    "mode": "city",
    "token": "demo"
};

// Run the Actor and wait for it to finish
const run = await client.actor("parseforge/waqi-air-quality-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 = {
    "maxItems": 10,
    "mode": "city",
    "token": "demo",
}

# Run the Actor and wait for it to finish
run = client.actor("parseforge/waqi-air-quality-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "maxItems": 10,
  "mode": "city",
  "token": "demo"
}' |
apify call parseforge/waqi-air-quality-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=parseforge/waqi-air-quality-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "WAQI Air Quality Scraper",
        "description": "Export real-time air quality from the World Air Quality Index. Pull AQI, dominant pollutant, PM2.5, PM10, O3, NO2, SO2, CO, temperature, humidity, pressure and geo data for any city. Bring your own token or use the included demo key.",
        "version": "1.0",
        "x-build-id": "jHH1uhn3L4PQbdjJ5"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/parseforge~waqi-air-quality-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-parseforge-waqi-air-quality-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/parseforge~waqi-air-quality-scraper/runs": {
            "post": {
                "operationId": "runs-sync-parseforge-waqi-air-quality-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/parseforge~waqi-air-quality-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-parseforge-waqi-air-quality-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "maxItems": {
                        "title": "Max Items",
                        "minimum": 1,
                        "maximum": 1000000,
                        "type": "integer",
                        "description": "Free users: Limited to 10 items (preview). Paid users: Optional, max 1,000,000"
                    },
                    "mode": {
                        "title": "Mode",
                        "enum": [
                            "city",
                            "here",
                            "bounds"
                        ],
                        "type": "string",
                        "description": "'city' = list of named cities. 'here' = nearest station (uses caller IP geo). 'bounds' = every station inside a lat/lng box (your own token required)."
                    },
                    "cities": {
                        "title": "Cities",
                        "type": "array",
                        "description": "List of city slugs or names when mode='city'. Examples: 'beijing', 'shanghai', 'london', 'new-york'.",
                        "default": [
                            "beijing",
                            "shanghai",
                            "tokyo",
                            "delhi",
                            "london"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "bounds": {
                        "title": "Bounding Box",
                        "type": "object",
                        "description": "Used when mode='bounds'. Object {lat1, lng1, lat2, lng2}. Requires your own token."
                    },
                    "token": {
                        "title": "Token",
                        "type": "string",
                        "description": "Optional. Free signup at aqicn.org/data-platform/token/ for global station access. The default 'demo' token returns Shanghai only."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
