# AAA Gas Prices Scraper & Monitor - US National & State Averages (`neverempty/aaa-gas-prices-monitor`) Actor

AAA gas prices from the public AAA Fuel Prices pages: US national average, all 50 states + DC and metro areas, for regular, mid-grade, premium, diesel and E85, with the page date. Monitoring mode returns only areas whose price changed, with the previous price. Unofficial.

- **URL**: https://apify.com/neverempty/aaa-gas-prices-monitor.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Business, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 area price row returneds

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

## AAA Gas Prices Scraper & Monitor - US National & State Averages

Get today's **AAA gas prices** as clean rows: the **US national average**, the average for each of the **50 states and DC**, and the average for every **metro area** AAA lists in a state. Each row has regular, mid-grade, premium and diesel (and E85 for the national average), the date AAA prints on the page ("Price as of"), and yesterday, week-ago, month-ago and year-ago prices where AAA gives them. Then turn on **monitoring mode**, schedule the Actor once or twice a day, and each run returns only the areas whose price **changed**, with the previous price and the difference.

**Source:** the public AAA Fuel Prices pages at [gasprices.aaa.com](https://gasprices.aaa.com/). **Unofficial.** This Actor is not affiliated with, endorsed by or sponsored by AAA (American Automobile Association) or OPIS. AAA is a trademark of its owner. The values are AAA's; the Actor only reads what the public page shows.

Built for people who need the AAA number every day without opening the page: prediction-market traders who follow gas price markets, fuel and fleet analysts, journalists and newsletter writers, pricing teams, and anyone who keeps a daily series in a sheet or a database.

- **National, state and metro averages in one run.** Empty input = the national average. `states: ["all"]` adds all 50 states and DC from one page. `includeMetros` adds each state's metro areas.
- **Monitoring mode for alerts.** The first run remembers the prices (free). Later runs return only the areas that changed, with `previousRegular`, `regularChange` and the same for every fuel. Set `minChangeUsd` (for example `0.02`) to be told only about moves of 2 cents or more.
- **The date AAA shows is on every row.** `priceDate` is the "Price as of" date on the page, so you can see when a run read yesterday's numbers because AAA had not updated yet.
- **Cross-checked on the page.** The same price appears in two places on each AAA page (the table and the headline figure, the table and the map, the metro heading and its table). If the two disagree, that price is `null` and the row says why. Nothing is guessed.
- **Polite by design.** No login, no API key, no browser, no proxy. The Actor reads robots.txt on every run and keeps the 10 seconds between requests that AAA's robots.txt asks for.

Sister Actors for prediction-market work: [Kalshi Markets Scraper](https://apify.com/neverempty/kalshi-markets-scraper), [Kalshi Weather Markets API](https://apify.com/neverempty/kalshi-weather-markets-api) and [US Weather Forecast API](https://apify.com/neverempty/us-weather-forecast-api).

### What you get

One row per area. Prices are US dollars per gallon, with the four decimals AAA shows.

| Field | Example | Meaning |
|---|---|---|
| `areaType` | `national` / `state` / `metro` | What the row is about |
| `areaName` | `National`, `Texas`, `Austin-San Marcos` | The area as AAA names it |
| `stateCode`, `stateName` | `TX`, `Texas` | The state (empty on the national row) |
| `priceDate`, `priceAsOf` | `2026-10-05`, `10/5/26` | The "Price as of" date on AAA's page, as a date and as AAA writes it |
| `regular`, `midGrade`, `premium`, `diesel` | `4.3653`, `4.8604`, `5.2603`, `6.3207` | Today's average ("Current Avg.") |
| `e85` | `3.3068` | National row only. AAA does not show E85 for states or metros, so it is `null` there |
| `regularYesterday`, `regularWeekAgo`, `regularMonthAgo`, `regularYearAgo` | `4.3697`, `4.4768`, `4.1459`, `3.1339` | AAA's own comparison prices. The same four exist for `midGrade`, `premium`, `diesel` and `e85`. Present on the national row and on state and metro rows read with `includeMetros`; `null` on state rows read from the state table (that table has today's prices only) |
| `changeType`, `changedFuels` | `price-changed`, `["regular","diesel"]` | Monitoring mode only: the watched fuels that moved by at least `minChangeUsd` |
| `previousRegular`, `regularChange` | `4.3653`, `0.0048` | Monitoring mode: the price in the last row this watch returned for the area (or the starting point) and today minus that. The same pair exists for every fuel |
| `previousPriceDate`, `previousCheckedAt` | `2026-10-05`, ISO time | Monitoring mode: when the previous price was read and the AAA date it carried |
| `source`, `sourceUrl` | `national-page`, `https://gasprices.aaa.com/` | Which AAA page the row was read from: `national-page`, `state-list-page` or `state-page` |
| `note` | | Empty on a normal row. Says why when a value is `null` or a row is a free reason row |
| `status` | `ok` | `ok` on a price row. Anything else is a free row that explains itself |
| `checkedAt` | ISO time | When this run read the page |

Example row (national average, monitoring mode, some fields left out):

```json
{
  "status": "ok",
  "changeType": "price-changed",
  "areaType": "national",
  "areaName": "National",
  "priceDate": "2026-10-06",
  "regular": 4.3701,
  "midGrade": 4.8604,
  "premium": 5.2603,
  "diesel": 6.3007,
  "e85": 3.3068,
  "regularYesterday": 4.3653,
  "changedFuels": ["regular", "diesel"],
  "previousRegular": 4.3653,
  "regularChange": 0.0048,
  "previousDiesel": 6.3207,
  "dieselChange": -0.02,
  "previousPriceDate": "2026-10-05",
  "source": "national-page",
  "sourceUrl": "https://gasprices.aaa.com/",
  "checkedAt": "2026-10-06T10:00:10.500Z"
}
```

One area is one row with the fuels as columns (not one row per fuel), so a daily export of all states is 52 rows and opens as one table in a sheet.

### Input

| Field | What it does |
|---|---|
| `states` | Two-letter codes or names, one per line, or `all`. Empty = only the national average |
| `skipNational` | On = leave out the national row |
| `includeMetros` | On = read each listed state's own page: the state row gets yesterday / week / month / year prices, and every metro area in the state gets a row |
| `monitoringMode` | On = return only areas whose price changed since the last row you received |
| `minChangeUsd` | Monitoring: smallest change to report, in dollars (`0.02` = 2 cents). Empty = any change |
| `fuels` | Monitoring: which fuels trigger a row. Empty = all |
| `watchName` | Monitoring: a name for what is remembered, one per schedule |
| `resetMonitoringState` | Monitoring: forget and start again |

#### Examples

National average and all states (52 rows, 3 requests, about 25 seconds):

```json
{ "states": ["all"] }
```

Follow the national regular price and be told only when it moves by 1 cent or more:

```json
{ "monitoringMode": true, "fuels": ["regular"], "minChangeUsd": "0.01", "watchName": "national-regular" }
```

Texas and California with their metro areas:

```json
{ "states": ["TX", "CA"], "includeMetros": true, "skipNational": true }
```

### Monitoring mode

1. **First run:** the Actor remembers today's price for every area you asked for and returns one free `baseline-saved` row. No price rows, no charge.
2. **Later runs:** each area is compared with the price in the last row you received for it (or with the starting point). An area is returned when one of the watched fuels differs by at least `minChangeUsd`. The row carries the previous price and the difference for every fuel.
3. **Nothing changed:** the run returns one free `no-change` row and costs one check.

Because the comparison is against the last row you received, small moves add up: with `minChangeUsd` at `0.02`, an area that rises 1 cent on each of two days is returned on the second day, with the price from the starting point as `previousRegular`.

If a run reaches the maximum charge you set, the changes it could not return are not marked as seen. The next run returns them.

Do not run two schedules with the same `watchName` at the same moment. Apify's key-value store has no atomic update, so two runs that finish in the same second can overwrite each other's memory.

### When AAA updates

AAA's page says the averages are updated daily, and it prints the date as "Price as of". The Actor copies that date into `priceDate` on every row. If you run before AAA has updated for the day, you get the previous day's numbers with the previous day's `priceDate`; the Actor does not relabel them. For a daily record, schedule one run in the US morning and, if you want to be sure, a second one a few hours later: in monitoring mode the second run costs one check when nothing changed.

### For prediction markets

Kalshi lists markets on the average price of regular gas. Kalshi's public contract terms for that market (the AAAGAS contract) say "The Source Agency is AAA". This Actor reads the same public AAA page a person would open. It is not Kalshi's settlement feed and not an official record: Kalshi decides how and when it reads the value, and AAA's page can change during the day. Use the rows to follow the number, not as proof of how a market will settle.

### Limits you should know

- **What AAA publishes is what you get.** State and metro tables have no E85. The state table has today's prices only; the comparison prices for a state need `includeMetros`.
- **No history beyond AAA's own columns.** The page shows today, yesterday, a week ago, a month ago and a year ago. To build a daily series, schedule the Actor and keep the rows.
- **No station prices and no county rows.** This Actor returns AAA's averages for the nation, states and metro areas.
- **10 seconds between requests.** AAA's robots.txt asks for it and the Actor keeps it. National plus all states is 3 requests (about 25 seconds). With `includeMetros`, each state adds about 10 seconds.
- **No retries around a block.** If AAA answers 403, 429 or a verification page, the Actor stops asking for that page and returns a free row that says so. It does not use proxies.
- **A state code AAA does not know gets no request.** AAA answers an unknown `?state=` with the national page. The Actor checks state names before asking and checks the heading of the page that comes back, so national numbers are never returned as a state's.

### Price

Pay per event, no start fee:

- **$0.002 for each area row returned** (`price-returned`), less on paid Apify plans. National plus all 51 states is 52 rows, about $0.10.
- **$0.001 for a monitoring run where nothing changed** (`check-done`), once per run.
- Free: the first monitoring run, and every row that only explains why something was not returned.

Set a maximum charge per run in Apify if you want a hard ceiling. The Actor never charges past it, and it tells you which areas were left out.

### FAQ

**Is this an official AAA API?** No. AAA does not publish one. The Actor reads AAA's public web pages.

**Why is `regular` empty on a row?** The two places where AAA's page shows that price disagreed when the run read it, or the price could not be read. The `note` field says which. The Actor does not pick one.

**Why did I get yesterday's date?** AAA had not updated yet when the run started. See "When AAA updates".

**Can I get all metro areas in the country?** Yes: `states: ["all"]` with `includeMetros`. It takes about 9 minutes because of the 10 seconds between requests.

### Thanks for using this Actor

We build these tools for people who run them every day, and we improve them from what users tell us.

- **Missing a field, or need another filter?** Tell us in the **Issues** tab. If the data is there, we add it.
- **Found a bug or a wrong value?** Post the run ID in the **Issues** tab. Wrong data is the thing we fix first.

If this Actor saved you time, a short review helps other people find it.

# Actor input Schema

## `states` (type: `array`):

US states to return, one per line: two-letter codes (TX, CA, NY, DC) or names (Texas). Write all for the 50 states and DC. All states come from one AAA page (one request), so all costs the same time as one. Something that is not a state comes back as a free row that says so. Empty = no state rows, only the national average.

## `skipNational` (type: `boolean`):

Off (or empty) = the run also returns one row for the US national average: regular, mid-grade, premium, diesel and E85, each for today, yesterday, a week ago, a month ago and a year ago. On = only the states you listed.

## `includeMetros` (type: `boolean`):

On = for each state in States, read that state's own AAA page and return one row for the state (with yesterday, week-ago, month-ago and year-ago prices) plus one row for every metro area AAA lists in it (Texas has 27, California 31). AAA's robots.txt asks for 10 seconds between requests, so each state adds about 10 seconds: all 51 take about 9 minutes and return several hundred rows. Off (or empty) = state rows come from the one state table, with today's prices only.

## `monitoringMode` (type: `boolean`):

On = for scheduled runs and alerts. The first run remembers today's prices as a starting point and returns no price rows (free). Later runs return a row only for an area whose price changed, with the previous price and the difference. A run where nothing changed costs one check and returns a free no-change row. AAA updates once a day, so one or two runs a day is enough. Off (or empty) = always return every area.

## `minChangeUsd` (type: `string`):

Monitoring mode only. For example 0.02 = return an area only when a watched fuel differs by 2 cents or more from the price in the last row you received for that area (or from the starting point). Small daily moves add up: three days of +1 cent are returned on the day the total reaches the amount. Empty = any change (AAA shows four decimals).

## `fuels` (type: `array`):

Monitoring mode only. An area is returned when one of these fuels changed. Every row still carries all fuels. Empty = all fuels. Pick only Regular to follow the number most people quote.

## `watchName` (type: `string`):

Optional, used with monitoring mode. Runs with the same watch name share what is remembered. Give a different name to each schedule. Do not run two schedules with the same watch name at the same time. Letters, digits, dot, dash and underscore.

## `resetMonitoringState` (type: `boolean`):

Forget what this watch remembered at the start of this run, so every area gets a new starting point. Turn it off again for scheduled runs.

## Actor input object example

```json
{
  "states": [
    "all"
  ]
}
```

# Actor output Schema

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

One row per area (US national average, a state or DC, or a metro area): regular, mid-grade, premium, diesel and E85 prices in US dollars per gallon, the date AAA shows on the page, and yesterday, week-ago, month-ago and year-ago prices where AAA gives them. In monitoring mode only areas whose price changed, with the previous price and the difference. A state that does not exist, a page AAA did not answer for, or a run that hit its maximum charge comes back as a free row that says why.

# 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 = {
    "states": [
        "all"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/aaa-gas-prices-monitor").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 = { "states": ["all"] }

# Run the Actor and wait for it to finish
run = client.actor("neverempty/aaa-gas-prices-monitor").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 '{
  "states": [
    "all"
  ]
}' |
apify call neverempty/aaa-gas-prices-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/aaa-gas-prices-monitor"
        }
    }
}
```

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/7jkjrX1q40xZmA5jT/builds/krTIELQiB6h3zhdCO/openapi.json
