NWS Climate Data API - Daily Temperature by Weather Station avatar

NWS Climate Data API - Daily Temperature by Weather Station

Pricing

$10.00 / 1,000 climate day returneds

Go to Apify Store
NWS Climate Data API - Daily Temperature by Weather Station

NWS Climate Data API - Daily Temperature by Weather Station

Official NOAA / National Weather Service daily climate report (CLI) for 629 US weather stations: the certified daily high and low temperature with the time each occurred, records, normals, departure, precipitation and snowfall. Missing (MM) and trace (T) are never turned into zero.

Pricing

$10.00 / 1,000 climate day returneds

Rating

0.0

(0)

Developer

NeverEmpty

NeverEmpty

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

a day ago

Last modified

Share

The certified daily climate report for 629 US stations, parsed into clean rows.

Every morning the US National Weather Service publishes a Climatological Report (CLI) for each of its climate sites: the official daily maximum and minimum temperature, the exact time each occurred, the record for that date, the 30-year normal, the departure from normal, precipitation, snowfall, degree days, wind and humidity.

It is published as a fixed-width plain-text bulletin. This Actor turns it into rows you can actually use.

This reads api.weather.gov, the official public API of the US National Weather Service (NOAA). It is a work of the US government: public domain, no API key, no rate-limit contract to sign, no terms that forbid redistribution. Nothing here parses a website, so nothing here breaks when a website is redesigned. No proxies required.

Why not just parse it yourself

Because the bulletin has four traps, and getting any of them wrong gives you a number that looks fine and is wrong.

TrapWhat a naive parser doesWhat this Actor does
MM means the instrument reported nothingWrites 0null, plus maxTemperatureIsMissing: true
T means trace - it did rain, just less than 0.005 inWrites 0 ("it did not rain")null, plus precipitationIsTrace: true
A report headed TODAY is preliminary - the day is not over, the high can still riseTreats it as the settled daily highreportBasis: "PRELIMINARY" and the time it was valid as of
R marks a record set or tied - and it shares the cell with the value, as in T RDrops it, or drops the whole rowprecipitationIsTrace: true and precipitationIsRecord: true
Different weather offices publish different columnsAssumes one fixed layout, then silently drops or misreads rowsReads each bulletin's own column header

Every row also carries coreFieldsObserved / coreFieldsTotal, so you can tell at a glance whether a station actually reported or quietly went dark.

The layout trap, concretely

The bulletin is not one national fixed-width format. Three real examples from the same morning:

NYC WEATHER ITEM OBSERVED TIME RECORD YEAR NORMAL DEPARTURE LAST
HKS WEATHER ITEM OBSERVED TIME NORMAL DEPARTURE LAST
LWC WEATHER ITEM OBSERVED NORMAL DEPARTURE LAST

On top of that, three-digit temperatures push the columns left - Phoenix at 113 F and Dallas at 103 F do not line up with New York at 76 F. A parser with hard-coded column positions loses exactly the days that matter most.

This Actor reads the column header of each bulletin and assigns values from that. 13 different header layouts are in live use. Verified against all 629 stations and 10,376 table rows, cross-checked against an independently written oracle: zero values taken from the wrong column, zero rows dropped, zero unexplained blanks.

What you get

One row per station, per climate day:

FieldExampleNotes
locationCode / stationNameNYC / CENTRAL PARK NYThe station as the NWS names it
climateDate2026-08-29The climate day the report covers, not the day it was issued
reportBasisFINALFINAL = the completed previous day. PRELIMINARY = still in progress
validAsOfLocal0425 PM LOCAL TIMEOnly on preliminary reports
maxTemperatureF76The official daily high
maxTemperatureTimeLst355 PMWhen it occurred, local standard time
maxTemperatureRecordF / maxTemperatureRecordYears99 / [1953]Record for this date, and every year it was set
maxTemperatureNormalF / maxTemperatureDepartureF82 / -61991-2020 normal and departure
maxTemperatureLastYearF78Same date last year
maxTemperatureIsRecordfalsetrue when the NWS flags a record set or tied
minTemperature*Same nine fields for the daily low
averageTemperatureF + normal + departure70 / 74 / -4
precipitationInches (+ IsTrace, IsMissing)0Plus normal, month-to-date, since Jan 1
snowfallInches (+ IsTrace), snowDepthInches0Plus month-to-date
heatingDegreeDays / coolingDegreeDays0 / 5
highestWindSpeedMph, highestGustSpeedMph, averageWindSpeedMph, highestWindDirection13, 19, 3.6, NE (40)
highestRelativeHumidityPercent / lowestRelativeHumidityPercent73 / 38
averageSkyCover00 to 1
coreFieldsObserved / coreFieldsTotal9 / 9How much of the report was actually observed
issuanceTime, productId, issuingOffice2026-08-30T06:42:00+00:00, KOKXSo you can cite the exact bulletin
sourceNWS api.weather.gov CLI product (official, public domain)

One real row, exactly as the Actor writes it

{
"locationCode": "NYC",
"stationName": "CENTRAL PARK NY",
"climateDate": "2026-08-29",
"reportBasis": "FINAL",
"reportBasisNote": "Issued for the completed previous climate day.",
"validAsOfLocal": null,
"issuanceTime": "2026-08-30T06:42:00+00:00",
"issuingOffice": "KOKX",
"maxTemperatureF": 76,
"maxTemperatureTimeLst": "355 PM",
"maxTemperatureIsMissing": false,
"maxTemperatureIsRecord": false,
"maxTemperatureRecordF": 99,
"maxTemperatureRecordYears": [1953],
"maxTemperatureNormalF": 82,
"maxTemperatureDepartureF": -6,
"maxTemperatureLastYearF": 78,
"minTemperatureF": 64,
"minTemperatureTimeLst": "719 AM",
"minTemperatureRecordF": 50,
"minTemperatureRecordYears": [1965, 1982, 1986],
"minTemperatureNormalF": 67,
"minTemperatureDepartureF": -3,
"averageTemperatureF": 70,
"averageTemperatureDepartureF": -4,
"precipitationInches": 0,
"precipitationIsTrace": false,
"precipitationMonthToDateInches": 8.49,
"precipitationSinceJan1Inches": 31.2,
"snowfallInches": 0,
"snowDepthInches": 0,
"heatingDegreeDays": 0,
"coolingDegreeDays": 5,
"highestWindSpeedMph": 13,
"highestGustSpeedMph": 19,
"averageWindSpeedMph": 3.6,
"highestRelativeHumidityPercent": 73,
"coreFieldsObserved": 9,
"coreFieldsTotal": 9,
"source": "NWS api.weather.gov CLI product (official, public domain)"
}

And a preliminary one, from a station that was not reporting - note that nothing is faked as zero:

{
"locationCode": "ANC",
"stationName": "ANCHORAGE AK",
"climateDate": "2026-08-29",
"reportBasis": "PRELIMINARY",
"validAsOfLocal": "0400 PM LOCAL TIME",
"maxTemperatureF": null,
"maxTemperatureTimeLst": null,
"maxTemperatureIsMissing": true,
"maxTemperatureRecordF": 72,
"maxTemperatureNormalF": 61,
"coreFieldsObserved": 3,
"coreFieldsTotal": 9
}

And a station whose weather office publishes no record or time columns at all - the fields that do not exist come back as null, not as zero:

{
"locationCode": "LWC",
"stationName": "LAWRENCE KS",
"climateDate": "2026-08-29",
"reportBasis": "FINAL",
"maxTemperatureF": 98,
"maxTemperatureTimeLst": null,
"maxTemperatureRecordF": null,
"maxTemperatureNormalF": 88,
"coreFieldsObserved": 8,
"coreFieldsTotal": 9
}

Input

{
"locations": ["NYC", "LAX", "ORD", "MIA", "DFW", "DEN", "PHL", "ATL", "SEA", "BOS", "IAH", "PHX"],
"reportsPerLocation": 1,
"maxRetries": 3
}
  • locations - three-letter NWS climate site codes. 629 sites publish a daily report; the full list is at https://api.weather.gov/products/types/CLI/locations. Defaults to twelve major US cities.
  • reportsPerLocation - how many recent reports per station. 1 is the latest. Raise it to backfill; the NWS keeps roughly the last two weeks per site.
  • maxRetries - retries per station when the NWS returns an error or something that is not JSON.

Typical uses

  • Settling and grading daily temperature contracts against the official certified high or low, with the time it occurred.
  • Energy and utility load models - heating and cooling degree days per station per day, straight from the source.
  • Insurance and agriculture - precipitation, snowfall and snow depth with trace distinguished from zero.
  • Climate and records reporting - departure from normal, the record for the date, and every year the record was set.

What it does when something is wrong

It tells you, instead of returning a clean-looking empty result.

  • A station code that is not three or four characters is rejected before any request is made.
  • A station with no reports throws with the reason, and the run continues with the other stations.
  • A bulletin that is empty, or in one of the non-standard Pacific-office formats, is never delivered as a row of nulls. It is reported as unreadable and not charged - a row that says FINAL with every field blank is worse than no row.
  • If the NWS returns HTML or an error status, that is treated as blocked and retried, then recorded in the RUN_ISSUES key-value record.
  • If a bulletin's columns do not line up with its own header, that row is skipped rather than guessed at - values are never read out of the neighbouring column, and a value that lands outside every declared column is never quietly discarded.
  • If you set a maximum total charge and the run hits it, the run stops and says the result is incomplete rather than quietly delivering a short dataset.

Pricing

Pay per result: one charge per climate-day row delivered. Failed stations are not charged.

Source and licence

All data comes from the US National Weather Service (api.weather.gov), a work of the US federal government and therefore in the public domain. This Actor adds parsing, validation and the missing/trace/preliminary handling described above.