# NWS Official Weather: Climate Reports and Observations (`osel_house/nws-official-weather`) Actor

Official NOAA/NWS daily climate reports (max/min temperature, precipitation, snow, wind, records, normals) parsed into clean JSON, plus hourly station observations. Public-domain data straight from api.weather.gov.

- **URL**: https://apify.com/osel\_house/nws-official-weather.md
- **Developed by:** [Tenzin Phuntsok](https://apify.com/osel_house) (community)
- **Categories:** Other, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 daily climate reports

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

## NWS Official Weather: Daily Climate Reports and Station Observations

Official NOAA / National Weather Service data as clean JSON rows, straight from the government API.

- **Daily climate report** for any of about 600 US climate stations: the official maximum and minimum temperature with the time each occurred, average temperature, precipitation, snowfall and snow depth, heating and cooling degree days, peak wind and gust, sky cover, humidity, the record and normal values for the date, and the normals for tomorrow. This is the NWS "CLI" Climatological Report (Daily), parsed field by field.
- **Station observations**: the hourly and special observations for any NWS/ICAO station (temperature, dewpoint, humidity, wind, gust, pressure, visibility, cloud layers, raw METAR), converted to US units.

All data is a US Government work in the public domain. No key, no scraping, no browser.

### Who this is for

- Prediction-market and weather-derivative traders who want the official NWS daily high and low, not a third-party estimate, with the preliminary and final report versions kept apart.
- Analysts, dashboards and AI agents that need one clean row per station-day instead of parsing fixed-width government text.
- Anyone who needs recent station observations with the original METAR attached.

**Important:** exchanges such as Kalshi and Polymarket settle each market on the source named in that market's rules (for many temperature markets that is The Weather Company, not NWS directly). This Actor returns the official NWS data; it does not claim to be the settlement source for any contract. Check the market rules yourself.

### Input

| Field | Default | Meaning |
|---|---|---|
| `stations` | `["KNYC"]` | Station ids. Examples: KNYC Central Park, KMDW Chicago Midway, KMIA Miami, KLAX Los Angeles, KDEN Denver, KPHL Philadelphia, KAUS Austin, KSFO San Francisco, KBOS, KATL, KDFW, KSEA. |
| `mode` | `daily_climate` | `daily_climate`, `observations` or `both`. |
| `startDate` | `yesterday` | `YYYY-MM-DD`, `today`, `yesterday` or `-N` (N days ago). |
| `endDate` | same as start | Up to 31 days per run. |
| `timezone` | `America/New_York` | IANA zone used to resolve `today` / `yesterday`. Observation day boundaries follow each station's own time zone (from NWS station metadata); this is only the fallback. |
| `reports` | `latest` | `latest` = newest report per day (final once issued, else the latest preliminary). `final` = final reports only. `all` = every issuance. |
| `observationInterval` | `hourly` | `hourly` = one observation per clock hour. `metar` = every observation with a raw METAR, including specials. `all` = every record (5-minute data at ASOS airports, about 300 rows a day). |
| `includeRawText` | `false` | Attach the original report text to each climate row. |
| `cliLocations` | none | Override the 3-letter climate location code for a station, e.g. `{"PAGS": "GUS"}`. K-stations use the last three letters (KNYC = NYC); the main Alaska, Hawaii, Puerto Rico and Pacific airports (PAFA, PANC, PAJN, PABR, PHNL, PHOG, PHTO, PHLI, TJSJ, PGUM, NSTU and others) are built in. Any other non-K station needs an entry here. |
| `maxConcurrency` | 4 | Parallel requests to api.weather.gov (1-8), shared across all stations. |

Example: the final report for Chicago Midway and Miami for the last three days.

```json
{
  "stations": ["KMDW", "KMIA"],
  "mode": "daily_climate",
  "startDate": "-3",
  "endDate": "yesterday",
  "reports": "final"
}
```

### Output

One row per station-day (climate) or per observation. Climate row, main fields:

```json
{
  "type": "climate_report",
  "station": "KNYC",
  "cliLocation": "NYC",
  "locationName": "CENTRAL PARK NY",
  "office": "KOKX",
  "date": "2026-09-24",
  "reportType": "final",
  "validAsOfLocal": null,
  "issuedLocal": "233 AM EDT FRI SEP 25 2026",
  "issuedAt": "2026-09-25T06:33:00+00:00",
  "maxTempF": 66,
  "maxTempTime": "15:05",
  "maxTempIsRecord": false,
  "maxTempRecordF": 91,
  "maxTempRecordYears": [2017],
  "maxTempNormalF": 73,
  "maxTempDepartureF": -7,
  "maxTempLastYearF": 80,
  "minTempF": 53,
  "minTempTime": "06:44",
  "minTempRecordF": 40,
  "minTempRecordYears": [1963],
  "minTempNormalF": 60,
  "avgTempF": 60,
  "precipIn": 0,
  "precipTrace": false,
  "precipMonthToDateIn": 2.21,
  "precipYearToDateIn": 33.56,
  "snowIn": 0,
  "snowDepthIn": 0,
  "heatingDegreeDays": 5,
  "coolingDegreeDays": 0,
  "highestWindMph": 17,
  "highestWindDirection": "NE",
  "highestGustMph": 32,
  "avgWindMph": 10,
  "avgSkyCover": 0.4,
  "weatherObserved": [],
  "humidityHighestPct": 74,
  "humidityLowestPct": 42,
  "normals": { "for": "today", "maxNormalF": 73, "maxRecordF": 90, "maxRecordYears": [1970], "minNormalF": 59, "minRecordF": 40, "minRecordYears": [1887] },
  "productId": "d328a89d-29f7-474e-9de8-c96a5ca3cb5e",
  "sourceUrl": "https://api.weather.gov/products/d328a89d-29f7-474e-9de8-c96a5ca3cb5e",
  "source": "NOAA/NWS Climatological Report (Daily, product CLI) via api.weather.gov",
  "licence": "US Government work, public domain",
  "fetchedAt": "2026-09-25T13:02:11.000Z",
  "tables": { "temperature": [], "precipitation": [], "snowfall": [], "heating": [], "cooling": [] }
}
```

Notes on climate rows:

- `reportType` is `preliminary` for the afternoon or early-morning versions ("VALID AS OF ... LOCAL TIME") and `final` for the full-day report issued after local midnight. `validAsOfLocal` carries the cut-off time of a preliminary report.
- Times such as `maxTempTime` are local standard time as printed by NWS, in 24-hour `HH:MM`.
- `precipTrace` / `snowTrace` are true when NWS printed `T` (a trace); the numeric value is then `0`.
- `*IsRecord` is true when NWS flagged the value with `R` (record set or tied).
- `tables` holds every row of the report's fixed-width table (observed, time, record, record years, normal, departure, last year) for precipitation, snowfall and degree days, so nothing is lost.
- Missing values (`MM` in the report) are `null`. A day whose max and min are both `MM` is still returned (NWS says the data is missing), with a note in the log.
- Not every office publishes every column. `reportColumns` lists the columns that office prints (for example Emporia KS prints no record values, Seattle prints no normals). A field whose column is absent is `null`. About 84% of stations use the full layout.

Observation row, main fields: `station`, `stationName`, `stationTimeZone`, `timestamp` (UTC), `tempF`, `tempC`, `dewpointF`, `humidityPct`, `windDirectionDeg`, `windSpeedMph`, `windGustMph`, `pressureInHg`, `seaLevelPressureMb`, `visibilityMi`, `precipLastHourIn`, `maxTempLast24HoursF`, `minTempLast24HoursF`, `heatIndexF`, `windChillF`, `cloudLayers`, `textDescription`, `rawMetar`, `sourceUrl`.

### Limits

- api.weather.gov keeps roughly the **last 7 days** of climate reports and observations. Older dates return no rows. Schedule the Actor daily if you want to build a history.
- The final climate report for a day is normally issued between about 1 AM and 8 AM local time the next day. Run after that, or use `reports: latest` to get the preliminary version meanwhile.
- Not every observation station has a climate report. About 600 do; the list is at `https://api.weather.gov/products/types/CLI/locations`. If a station's report is filed under a code the Actor cannot derive, use `cliLocations`. You can also pass the 3-letter code itself as the station (`"FAI"`) in `daily_climate` mode.
- Three Pacific offices (Palau TKR, Chuuk TKK, Tinian T11) publish a free-form report that is not parsed; they return a warning instead of a row.
- A run that produces no rows **fails**, with the reason in the status message. Only the Actor start event is charged for such a run.
- A station that fails (unknown id, NWS error) is reported in the log and status message; the other stations still return rows.
- Rows are written in batches per station; the order of stations in the dataset is not guaranteed.
- If a run is stopped (timeout, abort, platform restart), use **Resurrect** on the run: it continues with the stations that were not finished. After a hard stop, stations finished in the last two seconds before the stop may appear twice.
- NWS asks for modest request rates. Keep `maxConcurrency` low for large station lists.
- Airport ASOS stations report every 5 minutes; the default `observationInterval: hourly` keeps one record per hour so a day is about 24 rows, not 300.

### Pricing

Pay per event. You are charged for each climate report row and each observation row actually written to the dataset, plus the standard Actor start event. A run that returns no rows fails and charges only the start event. See the Pricing tab for current rates.

### Data source and licence

Data is produced by the US National Weather Service and retrieved from `https://api.weather.gov`. NWS states that its information "is in the public domain and may be used without charge for any lawful purpose". This Actor is not affiliated with or endorsed by NOAA or the NWS; it only names them as the source of the unaltered data. Each row carries `source`, `sourceUrl` and `licence` so you can cite it.

### Support

Open an issue in the Issues tab with the run id and the station and date you asked for. Parsing problems on an unusual report are usually fixed within a day.

# Actor input Schema

## `stations` (type: `array`):

NWS/ICAO station ids, for example KNYC (Central Park), KMDW (Chicago Midway), KMIA, KLAX, KDEN, KPHL, KAUS, KSFO. One climate report per station per day.

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

daily\_climate = the official daily climate report (max/min temperature, precipitation, snow, wind, humidity, records and normals). observations = the hourly station observations (temperature, dewpoint, wind, pressure, raw METAR). both = both.

## `startDate` (type: `string`):

YYYY-MM-DD, or "today", "yesterday", or "-N" for N days ago. Resolved in the time zone below. api.weather.gov keeps roughly the last 7 days.

## `endDate` (type: `string`):

Same formats as start date. Leave empty for a single day. Maximum 31 days per run.

## `timezone` (type: `string`):

IANA time zone used to resolve "today" / "yesterday". Observation day boundaries follow each station's own time zone from NWS metadata; this zone is only the fallback for stations without one.

## `reports` (type: `string`):

latest = the most recent report for each day (the final one once issued, else the latest preliminary). final = only final reports (a day with no final yet returns nothing). all = every issuance, preliminary and final.

## `observationInterval` (type: `string`):

hourly = one observation per clock hour (the routine METAR when there is one). metar = every observation that carries a raw METAR, including specials. all = every record, which at ASOS airports means one every 5 minutes (about 300 rows per day).

## `includeRawText` (type: `boolean`):

Add the full original NWS report text to each climate row.

## `cliLocations` (type: `object`):

Only needed when a station's climate report is filed under a 3-letter location code the Actor cannot derive. K-stations use the last three letters (KNYC -> NYC); the main Alaska, Hawaii, Puerto Rico and Pacific airports are built in (PAFA -> FAI). Map station id to code, e.g. {"PAGS": "GUS"}.

## `maxConcurrency` (type: `integer`):

Parallel requests to api.weather.gov (1-8), shared across all stations. Keep low; NWS rate limits are unpublished.

## Actor input object example

```json
{
  "stations": [
    "KNYC"
  ],
  "mode": "daily_climate",
  "startDate": "yesterday",
  "timezone": "America/New_York",
  "reports": "latest",
  "observationInterval": "hourly",
  "includeRawText": false,
  "maxConcurrency": 4
}
```

# Actor output Schema

## `results` (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 = {
    "stations": [
        "KNYC"
    ],
    "startDate": "yesterday",
    "timezone": "America/New_York"
};

// Run the Actor and wait for it to finish
const run = await client.actor("osel_house/nws-official-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 = {
    "stations": ["KNYC"],
    "startDate": "yesterday",
    "timezone": "America/New_York",
}

# Run the Actor and wait for it to finish
run = client.actor("osel_house/nws-official-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 '{
  "stations": [
    "KNYC"
  ],
  "startDate": "yesterday",
  "timezone": "America/New_York"
}' |
apify call osel_house/nws-official-weather --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,osel_house/nws-official-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/hkM6afqyjdfvATPmj/builds/s1ckbOQ3eO2TnjsXB/openapi.json
