NWS Climate Data API - Daily Temperature by Weather Station
Pricing
$10.00 / 1,000 climate day returneds
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
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
a day ago
Last modified
Categories
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.
| Trap | What a naive parser does | What this Actor does |
|---|---|---|
MM means the instrument reported nothing | Writes 0 | null, plus maxTemperatureIsMissing: true |
T means trace - it did rain, just less than 0.005 in | Writes 0 ("it did not rain") | null, plus precipitationIsTrace: true |
A report headed TODAY is preliminary - the day is not over, the high can still rise | Treats it as the settled daily high | reportBasis: "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 R | Drops it, or drops the whole row | precipitationIsTrace: true and precipitationIsRecord: true |
| Different weather offices publish different columns | Assumes one fixed layout, then silently drops or misreads rows | Reads 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 LASTHKS WEATHER ITEM OBSERVED TIME NORMAL DEPARTURE LASTLWC 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:
| Field | Example | Notes |
|---|---|---|
locationCode / stationName | NYC / CENTRAL PARK NY | The station as the NWS names it |
climateDate | 2026-08-29 | The climate day the report covers, not the day it was issued |
reportBasis | FINAL | FINAL = the completed previous day. PRELIMINARY = still in progress |
validAsOfLocal | 0425 PM LOCAL TIME | Only on preliminary reports |
maxTemperatureF | 76 | The official daily high |
maxTemperatureTimeLst | 355 PM | When it occurred, local standard time |
maxTemperatureRecordF / maxTemperatureRecordYears | 99 / [1953] | Record for this date, and every year it was set |
maxTemperatureNormalF / maxTemperatureDepartureF | 82 / -6 | 1991-2020 normal and departure |
maxTemperatureLastYearF | 78 | Same date last year |
maxTemperatureIsRecord | false | true when the NWS flags a record set or tied |
minTemperature* | Same nine fields for the daily low | |
averageTemperatureF + normal + departure | 70 / 74 / -4 | |
precipitationInches (+ IsTrace, IsMissing) | 0 | Plus normal, month-to-date, since Jan 1 |
snowfallInches (+ IsTrace), snowDepthInches | 0 | Plus month-to-date |
heatingDegreeDays / coolingDegreeDays | 0 / 5 | |
highestWindSpeedMph, highestGustSpeedMph, averageWindSpeedMph, highestWindDirection | 13, 19, 3.6, NE (40) | |
highestRelativeHumidityPercent / lowestRelativeHumidityPercent | 73 / 38 | |
averageSkyCover | 0 | 0 to 1 |
coreFieldsObserved / coreFieldsTotal | 9 / 9 | How much of the report was actually observed |
issuanceTime, productId, issuingOffice | 2026-08-30T06:42:00+00:00, KOKX | So you can cite the exact bulletin |
source | NWS 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 athttps://api.weather.gov/products/types/CLI/locations. Defaults to twelve major US cities.reportsPerLocation- how many recent reports per station.1is 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
FINALwith 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_ISSUESkey-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.