# METAR Weather Observations (`1mp/metar-observations`) Actor

Airport weather reports (METAR) by ICAO code or US lat/lon, up to 30 days back, one row per report; or daily highs and lows per station. NOAA and Iowa State data. $1 per 1,000 rows, no start fee.

- **URL**: https://apify.com/1mp/metar-observations.md
- **Developed by:** [Jesse Hawkins](https://apify.com/1mp) (community)
- **Categories:** Developer tools, Travel, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 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?

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

## METAR Weather Observations

Airport weather reports for any ICAO station, as clean JSON. Give
station codes (KORD, KJFK, EGLL, RJTT) or US coordinates, and get one
row per METAR or SPECI report over the last 1 to 720 hours:
temperature and dew point (F and C), wind direction, speed and gusts,
visibility, ceiling, altimeter, flight category (VFR, MVFR, IFR,
LIFR), the 6-hour and 24-hour max and min groups, hourly
precipitation, present weather and the raw METAR exactly as
published.

Or set `output` to `daily-summary` for one row per station per local
day with the high, the low and when each happened.

**$1.00 per 1,000 rows. No start fee.** No API key, no browser, no
proxy.

### Where the data comes from

- **Hours 1 to 672 (28 days):** NOAA's Aviation Weather Center,
  `aviationweather.gov`, routine and special reports.
- **Hours 673 to 720:** the Iowa State University ASOS/AWOS archive
  (Iowa Environmental Mesonet).
- **FAA identifiers with a digit (`57C`):** the Iowa State archive, for
  the whole range.

A station that `aviationweather.gov` does not answer for is looked up
in the Iowa State archive instead. US coordinates resolve to the
nearest NWS observation station through `api.weather.gov`.

Every request goes to these public services directly, paced under
their published limits: 100 requests a minute for
`aviationweather.gov` and one request a second for the Iowa State
archive (both read 2026-10-04).

### Input

```json
{
  "stationIds": ["KORD", "KJFK", "EGLL"],
  "hoursBack": 24
}
```

- `stationIds`: ICAO codes. 3-letter US codes get the K prefix (`ORD`
  becomes `KORD`). Commas or spaces inside one item split it. Up to
  200 per run. Empty, with no coordinates: `KORD`.
- `latLon`: optional US points, as `{"lat": 41.97, "lon": -87.9}`
  objects or `[41.97, -87.9]` pairs. Each becomes its nearest NWS
  station.
- `hoursBack`: 1 to 720. Default 24.
- `output`: `observations` (default) or `daily-summary`.
- `dateFrom`, `dateTo`: daily summary only. Station-local days,
  `YYYY-MM-DD`, `today` or `yesterday`. At most 366 days.
- `fields`: optional. Keep only these fields; `station_id` and
  `utc_time` are always kept.

`stationIds`, `latLon`, `output`, `dateFrom`, `dateTo`, `hoursBack`
and `fields` are the names other METAR Actors on the Store use, and
`ids` and `hours` are read too, so an existing input usually runs here
unchanged.

### Output: observations

A real row from a run on 2026-10-04 (`{"stationIds": ["KORD"]}`):

```json
{
  "station_id": "KORD",
  "station_name": "Chicago/O'Hare Intl, IL, US",
  "lat": 41.9602,
  "lon": -87.9316,
  "utc_time": "2026-10-04T20:51:00Z",
  "temp_f": 72.0,
  "dewpoint_f": 43.0,
  "wind_dir": 310.0,
  "wind_speed_kt": 8.0,
  "ceiling_ft": null,
  "visibility_sm": 10.0,
  "flight_category": "VFR",
  "metar_raw": "METAR KORD 042051Z 31008KT 10SM FEW300 22/06 A3014 RMK AO2 SLP203 T02220061 56005 $",
  "source": "aviationweather.gov",
  "obs_time": 1791147060,
  "report_type": "METAR",
  "temp_c": 22.2,
  "dewpoint_c": 6.1,
  "wind_gust_kt": null,
  "altimeter_hpa": 1020.7,
  "max_temp_6h_f": null,
  "min_temp_6h_f": null,
  "max_temp_24h_f": null,
  "min_temp_24h_f": null,
  "precip_in": null,
  "wx": null
}
```

- Temperatures come from the report's T-group (tenths of a degree C)
  when it has one, else from its whole-degree group. Both sources are
  read the same way, so the same report gives the same numbers.
- `wind_dir` is `null` for variable wind (`VRB`).
- `ceiling_ft` is the lowest broken or overcast layer, or the vertical
  visibility; `null` means no ceiling.
- `visibility_sm`: "10SM" and "10+" read as 10.0; 9999 metres reads
  as 6.0 from `aviationweather.gov` and 6.21 from the archive.
- `precip_in` is the hourly `Prrrr` group; a trace (`P0000`) is 0.0.
- `report_type` is `METAR` (routine) or `SPECI` (special). For archive
  rows it is the archive's own classification.
- `source` is `aviationweather.gov` or `mesonet-asos-archive`.
  Archive rows have `station_name` only when the same run also read
  the station from `aviationweather.gov`.

### Output: daily summary

```json
{"stationIds": ["KNYC", "EGLL"], "output": "daily-summary",
 "dateFrom": "2026-10-01", "dateTo": "2026-10-03"}
```

One row per station per station-local calendar day. Two sources,
named in `source`:

- `nws_cli`: the NWS Daily Climate Report, read through the Iowa State
  Mesonet, for US stations that issue one. Whole degrees F, with
  precipitation, snowfall, the 1991-2020 normals and the records. The
  NWS prints times in local standard time; `high_time` and
  `low_time` are converted to UTC. A report issued before the day
  ended is marked `complete: false`.
- `metar_derived`: everywhere else, and any day with no climate
  report: the highest and lowest temperature among that local day's
  reports from the Iowa State archive, with `obs_count`.
  `complete` is `false` while the day is still running or when the
  reports have a hole longer than 3 hours; `note` says which.

A real row from a run on 2026-10-04:

```json
{
  "record_type": "daily_summary",
  "station_id": "KNYC",
  "station_name": "NEW YORK CITY",
  "date": "2026-10-01",
  "timezone": "America/New_York",
  "source": "nws_cli",
  "high_f": 76.0,
  "high_c": 24.4,
  "high_time": "2026-10-01T18:03:00Z",
  "low_f": 65.0,
  "low_c": 18.3,
  "low_time": "2026-10-01T05:15:00Z",
  "precipitation_in": 0.0,
  "precipitation_trace": false,
  "snowfall_in": 0.0,
  "snowfall_trace": false,
  "high_normal_f": 70.0,
  "high_record_f": 88.0,
  "low_normal_f": 57.0,
  "low_record_f": 36.0,
  "precipitation_normal_in": 0.14,
  "obs_count": null,
  "complete": true,
  "note": null,
  "product_id": "202610020705-KOKX-CDUS41-CLINYC",
  "source_url": "https://mesonet.agron.iastate.edu/api/1/nwstext/202610020705-KOKX-CDUS41-CLINYC"
}
```

The highest hourly report is not always the day's true high: the peak
can fall between reports. The climate report's high is the official
one where it exists.

### Price

Pay per event: **$1.00 per 1,000 rows** in the dataset, nothing per
run. A US airport reports about 24 to 34 times a day, many airports
abroad every 30 minutes, and some automated US stations every 20
minutes, so:

| Run | Rows | Cost |
|---|---|---|
| KORD, 24 hours (2026-10-04) | 24 | about $0.02 |
| KORD, 700 hours | about 890 | about $0.89 |
| EGLL, 700 hours | about 1,400 | about $1.40 |
| 3 stations, 7 days, daily summary | 21 | about $0.02 |

Set **Maximum cost per run** to cap a run; it stops there and keeps
what it returned. `fields` makes rows smaller, not cheaper.

### Limits

- 720 hours (30 days) of reports; 366 days of daily summaries.
- 200 stations and 50 points per run.
- Coordinates work in the US only. Elsewhere, give the ICAO code.
- A station that is unknown, or silent for the whole range, returns no
  rows and is named in the run's status message. Nothing is charged
  for it.
- `aviationweather.gov` holds about 30 days. The Iowa State archive
  holds older years too, but this Actor reads at most 30 days of
  reports per run.

### What it will not do

- No forecasts (TAF), no radar, no model data. Observations only.
- No estimates: a missing value is `null`, never filled in.
- No scraping of weather websites. Public government and university
  data services only.

Not affiliated with NOAA, the NWS or Iowa State University. The data
is theirs; please credit "NOAA Aviation Weather Center" and "Iowa
Environmental Mesonet, Iowa State University" where you publish it.

### Changelog

- 0.1 (2026-10-04): first release.

# Actor input Schema

## `stationIds` (type: `array`):

4-letter ICAO codes, e.g. KORD, KJFK, EGLL, RJTT. 3-letter US codes get the K prefix (ORD -> KORD). FAA identifiers with a digit (57C) come from the Iowa State archive. Commas or spaces inside one item also split it. Up to 200 per run. Empty with no coordinates: KORD.

## `latLon` (type: `array`):

US points to resolve to the nearest NWS observation station through api.weather.gov: a list of objects with lat and lon keys (latitude and longitude also work), or \[lat, lon] pairs, e.g. one point at lat 41.97, lon -87.9. US only; elsewhere give the ICAO code.

## `output` (type: `string`):

observations (default): one row per METAR or SPECI report. daily-summary: one row per station per station-local day with the high, low and their times; the NWS Daily Climate Report where the station has one (precipitation and snowfall included), else computed from the day's reports.

## `hoursBack` (type: `integer`):

Hours of reports per station, 1 to 720 (30 days). The last 28 days come from aviationweather.gov, special reports included; older hours from the Iowa State ASOS archive. In daily-summary mode with no dates: the local days these hours touch.

## `dateFrom` (type: `string`):

daily-summary only. First station-local day, YYYY-MM-DD, or today or yesterday. With no To date the range runs to today. At most 366 days.

## `dateTo` (type: `string`):

daily-summary only. Last station-local day, YYYY-MM-DD, or today or yesterday. Alone, it is a single day.

## `fields` (type: `array`):

Keep only these output fields, e.g. temp_f, wind_gust_kt, metar_raw. station_id and utc_time are always kept (daily summary: record_type, station_id, date, source). Empty: every field. Same price per row.

## Actor input object example

```json
{
  "stationIds": [
    "KORD"
  ],
  "latLon": [],
  "output": "observations",
  "hoursBack": 24,
  "fields": []
}
```

# Actor output Schema

## `observations` (type: `string`):

Every row, as JSON from the run's default dataset.

## `overview` (type: `string`):

Observation rows in the overview view: station, time, type, temperature, wind, visibility, ceiling, category and raw METAR.

## `daily` (type: `string`):

Daily-summary rows in the daily view: station, date, high, low, their times and completeness.

# 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 = {
    "stationIds": [
        "KORD"
    ],
    "hoursBack": 24
};

// Run the Actor and wait for it to finish
const run = await client.actor("1mp/metar-observations").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 = {
    "stationIds": ["KORD"],
    "hoursBack": 24,
}

# Run the Actor and wait for it to finish
run = client.actor("1mp/metar-observations").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 '{
  "stationIds": [
    "KORD"
  ],
  "hoursBack": 24
}' |
apify call 1mp/metar-observations --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,1mp/metar-observations"
        }
    }
}
```

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/eITYtqn40asPyxWEr/builds/Ci0ac8nEvZbBxKqJ8/openapi.json
