# METAR Airport Weather API: Decoded Aviation Observations (`aeriontsai/metar-weather`) Actor

Decoded METAR and SPECI airport weather observations for any ICAO station (KJFK, EGLL...): temperature, dew point, wind, visibility, cloud layers, ceiling, flight category and raw METAR, up to 72 hours back. Data from NOAA / NWS Aviation Weather Center. Not for flight planning.

- **URL**: https://apify.com/aeriontsai/metar-weather.md
- **Developed by:** [Aerion](https://apify.com/aeriontsai) (community)
- **Categories:** Travel, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 observations

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 Aviation Weather Observations

Get decoded METAR airport weather for any list of ICAO station codes (e.g. KJFK, KLAX, EGLL) as clean rows: temperature, dew point, wind, visibility, cloud layers, ceiling and VFR/IFR flight category, with the unaltered raw METAR text on every row. Data comes from the NOAA / NWS Aviation Weather Center Data API, worldwide where reports exist, looking back up to 72 hours. Stations with no report are not charged. Not for flight planning or navigation.

### What does METAR Aviation Weather Observations do?

Give it a list of 4-character ICAO station IDs (for example KJFK, KLAX, EGLL) and it returns one row per
METAR / SPECI weather observation published by the NOAA / National Weather Service Aviation Weather Center
Data API: station, observation time, temperature, dew point, wind, visibility, cloud layers, ceiling,
flight category and the unaltered raw METAR text. Coverage is worldwide wherever the source has reports.
Typical uses: weather features for data pipelines, monitoring a fixed list of airports, or looking back up to 72 hours per run.

How fresh is the data? Most stations report once per hour, plus special reports (SPECI) when conditions
change. The Actor returns what the source has published at the time of the run. This Actor looks back at most 72 hours
(`hoursBack`); the source itself keeps about 30 days. Stations without a report in the chosen time window are skipped and not charged; when other stations
in the same request do return reports, the skipped ones are listed in the run log (the first 20).

### How much does it cost?

This Actor uses **pay-per-event** pricing: a small fee per run start and a fee per observation saved to the dataset.

| Event | When | Price (USD) |
|---|---|---|
| `observation` | one observation row saved to the dataset | 0.001 |
| Actor start | charged by the platform when a run starts | 0.00005 |

Runs that find no data or fail before saving anything charge no `observation` events.
Set **Maximum results** (`maxItems`) or a run spending limit to cap your cost; the Actor stops cleanly and keeps the results collected so far.

### Input

| Field | Type | Description |
|---|---|---|
| `stationIds` | array of strings | Required. 4-character ICAO station IDs (1-500). Requested in batches of up to 50 stations. |
| `hoursBack` | integer | Optional, 1-72. Hours of past reports to request. Empty = source default window (about 1.5 hours). |
| `latestOnly` | boolean | Default true: only the newest report per station. Set false to get every report in the window. |
| `maxItems` | integer | Stop after this many observations (default 100, max 10000). |

Example input:

```json
{ "stationIds": ["KJFK", "KLAX", "KORD"], "hoursBack": 3, "latestOnly": false, "maxItems": 100 }
```

### Output

Each observation is one record in the dataset. Example (from a local test run on saved source data):

```json
{
  "stationId": "KATL",
  "stationName": "Atlanta/Hartsfield-Jackson Intl, GA, US",
  "latitude": 33.6297,
  "longitude": -84.4422,
  "elevationM": 309,
  "reportType": "METAR",
  "observationTime": "2026-10-09T14:52:00.000Z",
  "reportTime": "2026-10-09T15:00:00.000Z",
  "temperatureC": 20.6,
  "dewpointC": 16.1,
  "windDirectionDeg": 80,
  "windVariable": false,
  "windSpeedKt": 14,
  "windGustKt": 22,
  "visibility": "10+",
  "visibilityMiles": 10,
  "visibilityAtLeast": true,
  "altimeterHpa": 1021.1,
  "seaLevelPressureHpa": 1020.2,
  "weather": null,
  "skyCover": "OVC",
  "clouds": [{ "cover": "SCT", "baseFtAgl": 18000, "type": null }, { "cover": "OVC", "baseFtAgl": 21000, "type": null }],
  "verticalVisibilityFt": null,
  "ceilingFtAgl": 21000,
  "flightCategory": "VFR",
  "rawMetar": "METAR KATL 091452Z 08014G22KT 10SM SCT180 OVC210 21/16 A3015 RMK AO2 SLP202 VIRGA OHD-ALQDS T02060161 51010",
  "source": "NOAA / National Weather Service Aviation Weather Center",
  "notice": "Decoded fields are reformatted from the source by this Actor (ceilingFtAgl is derived); rawMetar is the unaltered report. Not official government material; no endorsement by NOAA or the National Weather Service.",
  "scrapedAt": "2026-10-09T15:52:30.736Z"
}
```

Units are the source's: temperature in degrees Celsius, wind in knots, visibility in statute miles, pressure in
hectopascals, cloud bases and ceiling in feet above ground, elevation in meters. Times are UTC.
Missing values are `null` (for example when an automated station does not report visibility).

What we change and what we do not:

- `rawMetar` is the report text exactly as published.
- Decoded values are passed through as published by the source; we only reformat them (epoch time to ISO 8601,
  vertical visibility from hundreds of feet to feet, visibility text split into number + "at least" flag).
- `ceilingFtAgl` is **derived by this Actor** (lowest broken, overcast or obscured layer). `flightCategory` comes from the source.

Every run also writes a `RUN_SUMMARY` record (counts, success rate, why the run stopped) and an `errors` dataset with one row per problem (no personal data, no stack traces).

### Data source and license

Data source: Aviation Weather Center (AWC), National Weather Service (NWS), NOAA. This Actor reformats the data and is not an official NWS product. Not affiliated with or endorsed by NOAA or the NWS.

The NWS allows its information to be used as long as it is not claimed as your own, not used in a way that implies endorsement by or affiliation with NOAA/NWS, and not modified and then presented as official government material. For official aviation weather, use the official dissemination systems.
The Actor makes at most about 1 request per second (the source allows 100 per minute), batches up to 50 stations per request, and identifies itself with its own User-Agent.

### Limitations

- Not for flight planning or navigation; not an official weather briefing.
- Only 4-character ICAO station IDs; no search by state, country or map area in this version.
- The source returns at most 400 reports per request; long `hoursBack` windows use smaller batches, and a warning is logged if a response reaches the limit.
- History: at most 72 hours back per run (`hoursBack`); older reports are not available through this Actor.
- Values the source does not decode (for example some remarks) appear only in `rawMetar`.
- TAF forecasts are not included.
- Station IDs with a valid format that the source does not know return no rows and are not charged. If no requested station has a report, the run ends with 0 results and the log does not list the stations.

### Support

Found a problem or need a field? Open an issue in the **Issues** tab of this Actor. We aim to respond within 48 hours.

***

This Actor was developed with AI assistance and is covered by automated tests.

# Actor input Schema

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

4-character ICAO station identifiers, for example KJFK, KLAX, EGLL. Up to 500 stations per run. Stations are requested in batches of up to 50.

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

How many hours of past reports to request (1-72). Leave empty to use the source default window of about 1.5 hours. Larger windows use smaller station batches.

## `latestOnly` (type: `boolean`):

If enabled, only the most recent report of each station in the time window is saved. Disable to get every report (routine and special) in the window.

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

Stop after this many observations. You are charged per observation, so this also caps your cost.

## Actor input object example

```json
{
  "stationIds": [
    "KJFK",
    "KLAX",
    "KORD"
  ],
  "latestOnly": true,
  "maxItems": 100
}
```

# Actor output Schema

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

Normalized records (one per charged result event).

## `runSummary` (type: `string`):

JSON summary: counts, success rate, stop reason, billing summary, error counts.

## `errors` (type: `string`):

One record per error (taxonomy code, message, stage, URL). No stack traces.

# 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": [
        "KJFK",
        "KLAX",
        "KORD"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("aeriontsai/metar-weather").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": [
        "KJFK",
        "KLAX",
        "KORD",
    ],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("aeriontsai/metar-weather").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": [
    "KJFK",
    "KLAX",
    "KORD"
  ],
  "maxItems": 100
}' |
apify call aeriontsai/metar-weather --silent --output-dataset

```

## MCP server setup

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

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/6Owp1ALpwgwLpP3WN/builds/cDcDgYhm54e0m5YAX/openapi.json
