# Air Quality Monitor Records — US EPA AQS (`nexgensignal/air-quality-monitor-records`) Actor

Keyless, pay-per-record EPA AQS annual pollutant concentrations — one row per monitor with site geography and full concentration statistics (mean, max, percentiles). Public-domain measurements, not attainment verdicts; no person data.

- **URL**: https://apify.com/nexgensignal/air-quality-monitor-records.md
- **Developed by:** [NexGen Signal](https://apify.com/nexgensignal) (community)
- **Categories:** Business, News, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $33.50 / 1,000 monitor records

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 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

## Air Quality Monitor Records — US EPA AQS

**Keyless. Pay per record. Annual pollutant concentrations for every US air-quality monitor.**

This actor turns the **US EPA Air Quality System (AQS)** annual concentration files into clean, per-monitor records — the raw ambient-air measurement layer for the nation's official air-monitoring network. Each run reads EPA's public AirData bulk files and delivers one row per monitor summary: the monitor identity, the site's geography and coordinates, the pollutant, the year, and the full set of concentration statistics — arithmetic mean, standard deviation, annual maximum, and the 99th through 10th percentiles. Monitor grain, structured for engineering use, in the public domain, with an honest measurements-not-verdicts caveat on every record.

### What this is, in one paragraph

The EPA's Air Quality System is the national repository for ambient-air-quality measurements reported by state, local, and tribal monitoring agencies. Its AirData service publishes annual summary files — one row per monitor, per pollutant, per pollutant standard, per sample duration — with the year's concentration statistics already computed. This actor reads the annual concentration-by-monitor file for the year you choose, filters to the pollutant and state you want, and flattens each summary row into a single analysis-ready record: monitor identity, site geography, pollutant, and the concentration distribution. Values are exactly as published by the EPA. You are billed only for records actually delivered.

### Who buys this and for what job

- **Environmental and public-health researchers** building panels of annual pollutant exposure by monitor, county, or metro area for epidemiology and policy studies.
- **Data engineers and app builders** who want the AQS measurement layer as clean rows keyed by monitor and pollutant, without parsing EPA's fixed-format bulk files.
- **ESG, climate, and real-estate analysts** scoring locations on measured air quality — ozone, particulate matter, NO₂, CO, SO₂, lead — across years.
- **Dashboards and data journalism** mapping annual concentrations and trends across the country's monitoring sites.

### Measurements, not verdicts — and public-domain data

Two honesty riders travel on every record. First, these are **official ambient-air measurements** — the concentration statistics reporting agencies submitted to the EPA — and **not** regulatory attainment, compliance, or design-value determinations. Whether an area meets a National Ambient Air Quality Standard is a formal regulatory judgment the EPA makes through a separate process; this actor never makes it and never implies it. Second, AQS data is a **work of the US federal government**: it carries no copyright and is in the **public domain** under 17 U.S.C. §105, free to reuse with attribution to the EPA. One caveat on freshness: current-year data are **preliminary until May 1 of the following year**, and reporting agencies have up to six months to submit, so the most recent years can be incomplete.

### Monitor grain — no person data

This actor works at monitor grain: sites, coordinates, pollutants, and concentration statistics. There are no natural-person fields in AQS monitor summaries — the "address" field is the monitoring **site's** location (often a school, park, or agency facility), not a person — and this actor emits none, with a person-key guard on every record as a backstop.

### Pricing

| Event | Free plan | Bronze | Silver | Gold / Platinum / Diamond |
|-------|-----------|--------|--------|---------------------------|
| `monitor_record` | $0.05 | $0.045 | $0.04 | $0.0335 |

Delivered before charged. Blocked runs and empty results cost nothing.

### Input

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `year` | integer | 2024 | Calendar year of the annual concentration file to read. Current-year data are preliminary. |
| `pollutant` | string | — | Optional. Keep only monitors whose parameter name contains this text (e.g. Ozone, PM2.5, Carbon monoxide). |
| `stateCode` | string | — | Optional. Keep only monitors in this 2-digit FIPS state code (e.g. 06 California, 48 Texas). |
| `maxRecords` | integer | 500 | Ceiling on records delivered and billed. |

### Output

One JSON object per monitor summary row. Real example (values exactly as published by the EPA, Fairhope, Alabama ozone monitor, 2024):

```json
{
  "record_id": "01-003-0010-44201-1|2024|1 HOUR|Ozone 1-hour 1979|Daily maxima of observed hourly values (between 9:00 AM and 8:00 PM)|No Events",
  "monitor_id": "01-003-0010-44201-1",
  "state_code": "01",
  "county_code": "003",
  "site_number": "0010",
  "parameter_code": "44201",
  "poc": "1",
  "parameter_name": "Ozone",
  "year": 2024,
  "sample_duration": "1 HOUR",
  "pollutant_standard": "Ozone 1-hour 1979",
  "metric_used": "Daily maxima of observed hourly values (between 9:00 AM and 8:00 PM)",
  "method_name": "INSTRUMENTAL - ULTRA VIOLET ABSORPTION",
  "units_of_measure": "Parts per million",
  "latitude": 30.497478,
  "longitude": -87.880258,
  "observation_count": 5284,
  "observation_percent": 93.0,
  "arithmetic_mean": 0.045013,
  "arithmetic_standard_dev": 0.011555,
  "first_max_value": 0.073,
  "first_max_datetime": "2024-06-08 14:00",
  "ninety_ninth_percentile": 0.069,
  "fiftieth_percentile": 0.047,
  "certification_indicator": "Certified",
  "local_site_name": "FAIRHOPE, Alabama",
  "site_address": "FAIRHOPE HIGH SCHOOL, 1 PIRATE DRIVE, FAIRHOPE,  ALABAMA",
  "state_name": "Alabama",
  "county_name": "Baldwin",
  "city_name": "Fairhope",
  "cbsa_name": "Daphne-Fairhope-Foley, AL",
  "source": "US EPA Air Quality System (AQS) / AirData",
  "licence": "US EPA Air Quality System (AQS) monitoring data — ... public domain (17 U.S.C. §105) ...",
  "disclaimer": "Reported concentration statistics are official ambient-air MEASUREMENTS ... NOT regulatory attainment ...",
  "observed_at": "2026-08-21T00:00:00Z"
}
```

An unbilled `RUN_RECEIPT` records the robots check, the year and filters, source rows seen and delivered, whether charged equals delivered, and the measurements-not-verdicts notice.

### Field reference

Each record is one monitor-summary row. Identity: `record_id` (unique per monitor-year-standard-duration-metric-event), `monitor_id` (state-county-site-parameter-POC), and the component keys `state_code`, `county_code`, `site_number`, `parameter_code`, `poc`. Pollutant: `parameter_name`, `sample_duration`, `pollutant_standard`, `metric_used`, `method_name`, `event_type`, and `units_of_measure`. Geography: `latitude`, `longitude`, `datum`, `local_site_name`, `site_address`, `state_name`, `county_name`, `city_name`, and `cbsa_name`. Coverage: `observation_count`, `observation_percent`, `valid_day_count`, and `required_day_count`. Concentration statistics: `arithmetic_mean`, `arithmetic_standard_dev`, `first_max_value`, `first_max_datetime`, and the `ninety_ninth_`, `ninety_eighth_`, `ninety_fifth_`, `ninetieth_`, `seventy_fifth_`, `fiftieth_`, and `tenth_percentile` values. Provenance and caveats: `year`, `certification_indicator`, `date_of_last_change`, `source`, `source_url`, `licence`, `attribution`, `disclaimer`, and `observed_at`.

### How a run works

A run first re-reads the source host's robots posture from your runtime — EPA's AQS host serves no robots file, a no-policy posture — and stops at the door if that ever changes. It then downloads the annual concentration-by-monitor bulk file for your chosen `year` and streams its single CSV member row by row. Each row is checked against your optional `pollutant` and `stateCode` filters before anything is delivered, so you are billed only for monitors that pass them. Each matching row is flattened to one record, numbers parsed, and delivered **before** it is charged, so a blocked or empty run costs you nothing. The actor stops at your `maxRecords` ceiling and records `charge_equals_delivered` in the receipt.

### Pollutants you can pull

AQS covers the full set of criteria and many non-criteria pollutants, and this actor surfaces the `parameter_name` on every row so a mixed pull stays self-describing. Common pulls include **Ozone**, **PM2.5** and **PM10** particulate matter, **Carbon monoxide**, **Nitrogen dioxide**, **Sulfur dioxide**, and **Lead** — the criteria pollutants behind the National Ambient Air Quality Standards — plus a long tail of speciated particulates and air toxics. Because each row also carries the `pollutant_standard`, `sample_duration`, and `metric_used`, you can tell a 1-hour ozone summary from an 8-hour one, or a 24-hour PM2.5 mean from an annual mean, without leaving the record. Pass a single `pollutant` to build a focused feed — say, only ozone monitors nationwide — or pull the whole year and group by `parameter_name` downstream. Paired with `stateCode`, you can scope to one state's monitors for a bounded, low-cost run.

### Cost guidance

One `monitor_record` per delivered row: cost = rows delivered × your plan's per-record price. A single annual file holds tens of thousands of monitor summaries across all pollutants and states, so scope with `pollutant` and `stateCode` to keep runs bounded — one state's ozone monitors is typically a few dozen to a few hundred rows. 1,000 records is **$50** (Free) / **$33.50** (Gold).

### Honest limitations

- **Measurements, not verdicts.** These are reported ambient-air concentrations, not attainment, compliance, or design-value determinations — those are separate EPA regulatory judgments this actor never makes.
- **Preliminary for recent years.** Current-year data are preliminary until May 1 of the following year; agencies have up to six months to report, so recent years may be incomplete.
- **Annual summaries.** This is the annual-concentration-by-monitor layer — not hourly or daily raw observations.
- **As published.** Values are exactly as the EPA distributes them; this actor reformats, it does not recompute or correct.
- **No person data** is emitted.

### Differentiation

The NexGenData fleet already ships **epa-facility-compliance-records**, built on EPA's Envirofacts and centred on the *regulated-facility compliance* angle — permits, inspections, and enforcement status for industrial sites. This actor is a different job on a different EPA system: **ambient air-quality measurements** from the AQS monitoring network — what the air actually measured at a monitor, not how a facility performed against its permit. Compliance program records ≠ air-monitoring concentrations; the two catch different buyer searches, and the sibling is named here so buyers pick the right one.

### The NexGen Signal family

Part of the NexGen Signal family of pay-per-record data products:

- [EPA Facility Compliance Records — Envirofacts](https://apify.com/nexgensignal/epa-facility-compliance-records)
- [National Macro Indicator Records — World Bank](https://apify.com/nexgensignal/national-macro-indicator-records)
- [ECB Bank Interest Rate Records — Euro Area MFI](https://apify.com/nexgensignal/ecb-bank-interest-rate-records)
- [US Treasury Fiscal Records — Rates & Debt](https://apify.com/nexgensignal/treasury-fiscal-records)
- [Federal Rulemaking Records — US Federal Register](https://apify.com/nexgensignal/federal-rulemaking-records)

*Source: US EPA Air Quality System (AQS) / AirData annual concentration-by-monitor files. AQS data is a work of the US federal government, no copyright, public domain (17 U.S.C. §105); free to reuse with attribution to the US EPA. Reported values are official ambient-air measurements, not regulatory attainment determinations; current-year data are preliminary. Reformatted to monitor records; no person data emitted.*

# Actor input Schema

## `year` (type: `integer`):

Calendar year of the annual concentration-by-monitor file to read (e.g. 2024). Current-year data are preliminary.

## `pollutant` (type: `string`):

Optional. Keep only monitors whose parameter name contains this text (case-insensitive), e.g. Ozone, PM2.5, Carbon monoxide, Nitrogen dioxide.

## `stateCode` (type: `string`):

Optional. Keep only monitors in this 2-digit FIPS state code (e.g. 06 for California, 48 for Texas).

## `maxRecords` (type: `integer`):

Maximum records delivered and billed. You are billed only for records delivered.

## Actor input object example

```json
{
  "year": 2024,
  "maxRecords": 500
}
```

# Actor output Schema

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

The delivered EPA AQS monitor records.

# 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 = {
    "year": 2024,
    "maxRecords": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgensignal/air-quality-monitor-records").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 = {
    "year": 2024,
    "maxRecords": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("nexgensignal/air-quality-monitor-records").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 '{
  "year": 2024,
  "maxRecords": 500
}' |
apify call nexgensignal/air-quality-monitor-records --silent --output-dataset

```

## MCP server setup

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

```

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/PpPAA1RG4ZnhkUk6k/builds/AY4Q12CmiR61QH5tt/openapi.json
