# NWS Daily Climate Report Scraper: Official High, Low, Rain (`fecklesspleb/daily-climate-reports`) Actor

Daily high, low, precipitation, snow, records and normals parsed from the official NWS Daily Climate Report (CLI) text for MIA, NYC, ORD and 18 more locations. Latest, date-range with NCEI history, or live running max/min from METARs.

- **URL**: https://apify.com/fecklesspleb/daily-climate-reports.md
- **Developed by:** [Scott Williams](https://apify.com/fecklesspleb) (community)
- **Categories:** Developer tools, News, Other
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Daily Climate Reports: Official High, Low and Rain by Station

Get each day's **official high and low temperature**, precipitation, snow, records, normals and degree days for U.S. weather
stations as clean JSON. Values are **parsed from the official NWS Daily Climate Report (CLI)** text that each National Weather
Service office issues for its climate locations, with NOAA NCEI GHCN-Daily history and a METAR-based live running max/min.

Typical uses: settling or tracking temperature-based contracts and markets that reference the NWS daily climate report, daily
weather data for dashboards and models, energy and degree-day analysis, and a clean history of daily highs and lows for one station.

### Three modes

- **latest** (default): the newest full-day report for each location, plus today's partial-day report if one has been issued.
- **date_range**: every report for the dates you choose (up to 10 years). The NWS site keeps about the last 25 days of CLI reports.
  For older dates, or days with no full-day report, the Actor fills in NCEI GHCN-Daily summaries (high, low, precipitation, snow),
  which usually appear a few days after the date.
- **live_intraday**: a preliminary running max and min for today's climate day, computed from the station's METAR observations.
  Useful before the afternoon or next-morning report is out.

### Locations

21 built-in locations: MIA, NYC (Central Park), LAX, MDW, ORD, AUS, DEN, PHL, ATL, BOS, DCA, SEA, PHX, DFW, HOU, IAH, SFO, LAS,
MSP, ANC, HNL.

Any other three-letter CLI location code (for example `LGA`) works in `latest` and `date_range` too. For NCEI history or live mode
on it, add its details with `stationMap`:

```json
{"stationMap": {"ABQ": {"icao": "KABQ", "ghcnd": "USW00023050", "timeZone": "America/Albuquerque"}}}
```

### Input

| Field | Default | Notes |
|---|---|---|
| `contactEmail` | none (needed for live data) | Sent in the User-Agent so the data provider can reach you about your traffic. Never written to the output. Leave it empty to get free samples (below). |
| `mode` | `latest` | `latest`, `date_range` or `live_intraday` |
| `cliLocations` | `["MIA"]` | Three-letter CLI codes, up to 100 |
| `reportKinds` | full_day, partial_day | Which report kinds to keep |
| `startDate` / `endDate` | | `date_range` only, YYYY-MM-DD, inclusive |
| `includeNceiHistory` | true | Fills dates with no full-day CLI report |
| `maxReportVersions` | 50 | How many archived issuances to scan per location |
| `useSixHourExtremes` | true | live mode: also use the METAR 6-hour max/min groups |
| `onlyNewSinceLastRun` | auto | Skips reports already delivered. Corrected or re-issued reports are delivered again. |
| `stateKey` | default | Keeps separate "only new" memory for each schedule |
| `includeRawText` | false | Attaches the CLI text |
| `maxItems` | 1000 | |

**No e-mail = free sample mode.** If `contactEmail` is empty, the run makes no requests, logs a warning and returns 4 free sample
reports (MIA, NYC and BOS, late October 2026, parsed from real reports saved with the Actor) with `isSample: true`. Filters are not
applied to samples and nothing is charged. Add your e-mail to get live data. An e-mail that is invalid, or uses a placeholder domain
such as example.com, stops the run with an input error.

Example: a backfill for three cities.

```json
{"contactEmail": "YOUR_CONTACT_EMAIL", "mode": "date_range", "cliLocations": ["MIA", "NYC", "BOS"], "startDate": "2026-10-01"}
```

### Output example

One of the free sample records (from a run with no e-mail on 2026-10-31; some fields left out here):

```json
{
  "cliLocation": "MIA",
  "climateDate": "2026-10-27",
  "reportKind": "full_day",
  "maxTempF": 84,
  "minTempF": 75,
  "avgTempF": 80,
  "normalMaxF": 84,
  "normalMinF": 72,
  "recordMaxF": 90,
  "recordMaxYears": [1997, 2021],
  "precipIn": 0.41,
  "snowIn": 0.0,
  "cdd": 15,
  "highestGustMph": 36,
  "productKey": "KMFL-CDUS42KMFL280826-CLIMIA",
  "isSample": true
}
```

`reportKind` is one of `full_day` (the final report for the climate day), `partial_day` (the report valid as of the afternoon),
`ncei_daily_summary` (an NCEI history day) or `obs_running` (a preliminary live value).

Main fields: `maxTempF`, `minTempF` and their times in local standard time, `avgTempF`, normals, departures and records with record
years, `precipIn` and `snowIn` (a trace is 0.0 with `precipTrace` or `snowTrace` true), month- and year-to-date precipitation,
`hdd`/`cdd`, wind, `issuanceTimeUtc`, `isCorrection`, `productKey` (stable id), `sourceUrl` and `isSample` (`true` only on free
samples). Missing values (`MM`) are `null`, never 0. See `sample_output.json` for full records.

- The climate day runs midnight to midnight in **local standard time**, so during daylight saving time it runs 1 AM to 1 AM clock time.
- `sourceUrl` points to the archived version number seen at fetch time (`sourceVersionAtFetch`). The NWS site renumbers versions as
  new reports arrive, so use `productKey` as the identifier.
- `obs_running` values are preliminary. They come from METAR temperatures, which are rounded differently from the official daily
  extremes, and can differ by 1 to 2 °F.

### Price

Pay per event, no start fee set by the Actor:

- **$0.001 per climate report** (full-day or partial-day CLI)
- **$0.0005 per NCEI history day**
- **$0.001 per live snapshot**
- Sample records (no contact e-mail) are free, and records that could not be parsed are delivered free with the raw text.

Set a maximum cost per run in Apify and the Actor stops cleanly when it is reached.

If the input is invalid (for example it is not a JSON object, an e-mail or location is not valid, or a whole-number field is not a number), nothing is fetched and the run ends with one free status row: `Invalid input, nothing was fetched or charged: <reason>`. Nothing is charged for it.

### Sources, rate limits and legal

- **forecast.weather.gov**: the CLI text product, at most 1 request per second.
- **aviationweather.gov** Data API: METARs, at most 1 request every 2 seconds.
- **NCEI Access Data Service**: GHCN-Daily, at most 1 request per second.
- On errors against the weather.gov and aviationweather.gov hosts the Actor waits at least a minute between retries and tries at
  most 3 times, as NWS asks. Each host's robots.txt is checked before use.

This Actor uses U.S. government data from NOAA (the National Weather Service, the Aviation Weather Center and NCEI), which is in the
public domain. Values in this dataset are parsed or computed by the Actor and are not official government material (17 U.S.C. § 403).
The official values are the ones NOAA publishes, and NWS can revise reports after issue. This Actor is not affiliated with or
endorsed by NOAA or the National Weather Service.

#### NCEI attribution

`ncei_daily_summary` records come from NOAA's National Centers for Environmental Information (NCEI), a U.S. government work. Cite as:
Menne, M.J., I. Durre, B. Korzeniewski, S. McNeill, K. Thomas, X. Yin, S. Anthony, R. Ray, R.S. Vose, B.E. Gleason, and T.G. Houston
(2012): Global Historical Climatology Network - Daily (GHCN-Daily), Version 3. NOAA National Climatic Data Center. doi:10.7289/V5D21VHZ.
Retrieved through the NCEI Access Data Service (https://www.ncei.noaa.gov/access/services/data/v1).

# Changelog

This Actor's version history is a separate document: https://apify.com/fecklesspleb/daily-climate-reports/changelog.md

# Actor input Schema

## `contactEmail` (type: `string`):

Needed for live data. Sent in the User-Agent header ('DailyClimateReports/0.1 (Apify Actor; <this e-mail>)') so the data provider can reach you about your traffic if needed. Not written to the output. Placeholder domains such as example.com are refused. Leave it empty to try the Actor: the run then makes no requests and returns a few free sample reports marked isSample = true.

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

latest: the newest full-day report, plus today's in-progress report if one is out. date_range: every report for the dates you pick; dates older than the ~25-day CLI archive come from NCEI daily summaries. live_intraday: running max/min since local-standard-time midnight from METAR observations (preliminary, not official).

## `cliLocations` (type: `array`):

Three-character Daily Climate Report location codes (the CLIxxx suffix), e.g. MIA = Miami Intl, NYC = Central Park, MDW = Chicago Midway. Built-in station details for: ANC, ATL, AUS, BOS, DCA, DEN, DFW, HNL, HOU, IAH, LAS, LAX, MDW, MIA, MSP, NYC, ORD, PHL, PHX, SEA, SFO. Other codes work for CLI reports; add them to Station map for history and live modes.

## `reportKinds` (type: `array`):

Which CLI reports to keep. Offices typically issue a partial report in the late afternoon and the full-day report early the next morning.

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

date_range only. Climate date (YYYY-MM-DD), inclusive.

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

date_range only. Inclusive; defaults to today (U.S. Eastern).

## `includeNceiHistory` (type: `boolean`):

date_range only. Dates with no full-day CLI report in the archive are filled with NCEI GHCN-Daily summaries (high, low, precipitation, snow), usually available after 2 to 5 days.

## `maxReportVersions` (type: `integer`):

date_range only. The site keeps the last 50 issuances per location (about 25 days). Lower this to scan fewer.

## `useSixHourExtremes` (type: `boolean`):

live_intraday only. Also use the 6-hour max/min remark groups in synoptic METARs when their window lies inside the climate day; these catch peaks between hourly reports.

## `stationMap` (type: `object`):

Add or override station details per location code: {"ABQ": {"icao": "KABQ", "ghcnd": "USW00023050", "timeZone": "America/Denver"}}. icao is used in live mode, ghcnd for NCEI history, timeZone (IANA) for the local-standard-time day.

## `onlyNewSinceLastRun` (type: `string`):

Skip reports already delivered by an earlier run with the same state key. A corrected or re-issued report has a new issuance time and is delivered again.

## `stateKey` (type: `string`):

Separate 'only new' memory per schedule, e.g. one key per task.

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

Add the full CLI text to each record. Always included when a report could not be parsed.

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

Stop after this many records are saved.

## Actor input object example

```json
{
  "mode": "latest",
  "cliLocations": [
    "MIA",
    "NYC",
    "ORD",
    "LAX",
    "DEN"
  ],
  "reportKinds": [
    "full_day",
    "partial_day"
  ],
  "startDate": "2026-10-01",
  "endDate": "2026-10-27",
  "includeNceiHistory": true,
  "maxReportVersions": 50,
  "useSixHourExtremes": true,
  "onlyNewSinceLastRun": "auto",
  "stateKey": "default",
  "includeRawText": false,
  "maxItems": 100
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "mode": "latest",
    "cliLocations": [
        "MIA",
        "NYC",
        "ORD"
    ],
    "reportKinds": [
        "full_day",
        "partial_day"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("fecklesspleb/daily-climate-reports").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 = {
    "mode": "latest",
    "cliLocations": [
        "MIA",
        "NYC",
        "ORD",
    ],
    "reportKinds": [
        "full_day",
        "partial_day",
    ],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("fecklesspleb/daily-climate-reports").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 '{
  "mode": "latest",
  "cliLocations": [
    "MIA",
    "NYC",
    "ORD"
  ],
  "reportKinds": [
    "full_day",
    "partial_day"
  ],
  "maxItems": 100
}' |
apify call fecklesspleb/daily-climate-reports --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fecklesspleb/daily-climate-reports"
        }
    }
}
```

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/N28fAd2orhN3vJcHI/builds/JekAvahjHUvEWPRu3/openapi.json
