NWS Weather Scraper: US Forecasts, Alerts & Observations
Pricing
from $0.37 / 1,000 weather scrapeds
NWS Weather Scraper: US Forecasts, Alerts & Observations
Scrape US National Weather Service forecasts, hourly outlooks, active alerts and station observations by coordinate or zone. No API key, no proxy, no browser.
Pricing
from $0.37 / 1,000 weather scrapeds
Rating
0.0
(0)
Developer
Arman Hossain
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
9 days ago
Last modified
Categories
Share

Pulls National Weather Service data for any US location: twelve-hour and hourly forecasts, active watches and warnings, and the latest reading from the nearest observation station.
The NWS publishes everything through api.weather.gov, a public API built for programmatic use. There's no key, no quota and, so there's nothing for a browser or a proxy to solve. A four-location forecast run finishes in about two seconds. The one thing NWS asks for is a User-Agent that identifies you, which this Actor sends on every request.
Agent skill: SKILL.md
https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/nws-weather-scraper.md
What you get
| Field | What it holds |
|---|---|
location, locationType | The location as normalised, and whether it resolved as a point or a zone |
latitude, longitude | Coordinates as sent to NWS (null for zone codes) |
city, state | Nearest named place for points; zone name and state for zones |
gridId, gridX, gridY | The NWS forecast grid cell the point resolved to |
forecastOffice, timeZone, radarStation | Issuing WFO, IANA timezone, covering radar |
dataType, units | Which product was fetched, and in which unit system |
temperature, temperatureUnit, windSpeed, windDirection | Headline conditions from the first forecast period |
shortForecast, detailedForecast | The one-line and full narrative for that period |
forecastPeriods, periodCount | Every period returned, capped by maxPeriods |
observationStation | Nearest station plus its latest temperature, dewpoint, humidity, wind, pressure and visibility |
alerts, alertCount | Active alerts covering the location, with event, severity, urgency, headline, area, onset, expiry and full text |
forecastUrl, updatedAt | Source URL and the timestamp NWS stamped on the product |
scrapedAt | Run timestamp |
RUN_SUMMARY in the key-value store holds per-run counts, the settings you used, and any location that failed.
Use cases
- Demand forecasting. Join daily highs against store-level sales history.
- Field operations. Check tomorrow's conditions across every depot before dispatch.
- Event alerting. Poll
dataType: "alerts"on a schedule and page on any Severe or Extreme event. - Risk and insurance. Build a warning history for a portfolio of insured sites.
- Newsroom monitoring. Watch heat, flood and winter-storm advisories across a set of counties.
Quick start
Two cities, standard forecast:
{"locations": ["39.7456,-97.0892", "40.7128,-74.0060"]}
Hourly detail in metric, no alerts, one day of periods:
{"locations": ["47.6062,-122.3321", "37.7749,-122.4194"],"dataType": "hourly","units": "si","includeAlerts": false,"maxPeriods": 24}
Alert monitoring across a set of forecast zones:
{"locations": ["KSZ009", "TXZ248", "FLZ173"],"dataType": "alerts","contactEmail": "ops@example.com"}
Input
| Field | Type | Default | Notes |
|---|---|---|---|
locations | array | required | "lat,lon" strings or NWS zone codes such as KSZ009 or KSC201. Mixed input is fine. |
dataType | string | forecast | forecast, hourly, alerts or observations. |
units | string | us | us for F, mph and inHg; si for C, km/h and Pa. |
includeAlerts | boolean | true | Attach active alerts to every record. Always on when dataType is alerts. |
maxPeriods | integer | 24 | Cap stored forecast periods per location. 0 means keep them all. |
contactEmail | string | "" | Added to the User-Agent so NWS can contact you about heavy usage. |
units only affects gridpoint products. Zone-code forecasts are text only: NWS rejects a units parameter on them and returns no numeric temperature, so temperature is null and the narrative arrives in the forecaster's own units.
Output example
{"location": "40.7128,-74.006","locationType": "point","latitude": 40.7128,"longitude": -74.006,"city": "New York","state": "NY","gridId": "OKX","gridX": 33,"gridY": 42,"forecastOffice": "OKX","timeZone": "America/New_York","radarStation": "KDIX","dataType": "forecast","units": "us","temperature": 90,"temperatureUnit": "F","windSpeed": "6 to 10 mph","windDirection": "SW","shortForecast": "Mostly Sunny","detailedForecast": "Mostly sunny, with a high near 90. Heat index values as high as 102. Southwest wind 6 to 10 mph.","forecastPeriods": [{"number": 1,"name": "Today","startTime": "2026-08-06T07:00:00-04:00","endTime": "2026-08-06T18:00:00-04:00","isDaytime": true,"temperature": 90,"temperatureUnit": "F","probabilityOfPrecipitation": { "unitCode": "wmoUnit:percent", "value": 9 },"windSpeed": "6 to 10 mph","windDirection": "SW","shortForecast": "Mostly Sunny","detailedForecast": "Mostly sunny, with a high near 90."}],"periodCount": 4,"observationStation": null,"alerts": [{"id": "urn:oid:2.49.0.1.840.0.c1834a44913d904db6ce91b95b70d126406790b2.004.1","event": "Heat Advisory","severity": "Moderate","urgency": "Expected","certainty": "Likely","headline": "Heat Advisory issued August 6 at 2:26AM EDT until August 7 at 8:00PM EDT by NWS Upton NY","areaDesc": "New York (Manhattan); Bronx; Richmond (Staten Is.); Kings (Brooklyn); Northern Queens; Southern Queens","onset": "2026-08-06T11:00:00-04:00","expires": "2026-08-06T10:30:00-04:00","senderName": "NWS Upton NY","description": "* WHAT.Heat index values up to 104 expected."}],"alertCount": 1,"forecastUrl": "https://api.weather.gov/gridpoints/OKX/33,42/forecast?units=us","updatedAt": "2026-08-06T09:41:52+00:00","scrapedAt": "2026-08-06T11:35:21.410Z"}
With dataType: "observations" the observationStation object is populated instead of forecastPeriods:
{"stationId": "KMYZ","stationName": "Marysville Municipal Airport","timestamp": "2026-08-06T10:55:00+00:00","textDescription": "Fog/Mist","temperature": { "value": 68, "unit": "F" },"dewpoint": { "value": 64.4, "unit": "F" },"relativeHumidity": { "value": 88.27, "unit": "%" },"windSpeed": { "value": 4.7, "unit": "mph" },"windDirection": { "value": 80, "unit": "deg" },"windGust": null,"barometricPressure": { "value": 30.03, "unit": "inHg" },"visibility": { "value": 3, "unit": "mi" }}
Finding a location code
Coordinates are the simplest input, and anything you can read off a map works. Zone codes are useful when you want an official NWS area rather than a single point.
| Code shape | Meaning | Example |
|---|---|---|
SSZnnn | Public forecast zone | KSZ009 (Washington County, KS) |
SSCnnn | County zone | KSC201 |
SSZnnn (fire) | Fire weather zone | KSZ009 |
To find the zone for a point, run the Actor once with coordinates and read forecastUrl, or open https://api.weather.gov/points/{lat},{lon} and look at properties.forecastZone. Full zone URLs are accepted too, because the Actor takes the last path segment.
API example
curl -X POST "https://api.apify.com/v2/acts/arman-bd~nws-weather-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"locations": ["40.7128,-74.0060", "41.8781,-87.6298"],"dataType": "forecast","units": "us","maxPeriods": 8}'
JavaScript example
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('arman-bd/nws-weather-scraper').call({locations: ['40.7128,-74.0060', '47.6062,-122.3321'],dataType: 'forecast',includeAlerts: true,});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const r of items) {console.log(`${r.city}, ${r.state}: ${r.temperature}${r.temperatureUnit}, ${r.shortForecast} (${r.alertCount} alerts)`);}
Limits and behaviour
- Every point costs two hops.
/points/{lat},{lon}resolves a 2.5 km grid cell, and the forecast URL it returns is fetched second. The Actor follows whatever URL NWS hands back rather than building gridpoint URLs itself, so office re-gridding never breaks a run. - Coordinates are rounded to four decimals. Anything finer gets a 301 redirect to the nearest supported point, and rounding up front saves the round trip.
- Coverage is US only. A point outside NWS coverage returns 404 with
InvalidPoint, lands inRUN_SUMMARY.failures, and the run continues. - A missing User-Agent is a 403. NWS refuses anonymous clients outright, so the Actor always identifies itself, and
contactEmailputs your address in the header. - Transient errors get retried. 429s and 5xx responses get three attempts with linear backoff, while 400 and 404 are treated as fatal for that location only.
- Public data only. NWS output is US government work in the public domain.
FAQ
Do I need an API key? No. You supply no credentials.
Do I need a proxy? No. Proxy configuration is not required to run this Actor.
Does it work outside the United States? No. NWS covers US states, territories and coastal waters only, and other coordinates return 404. For worldwide coverage use the Open-Meteo Scraper below.
Why is temperature null for a zone code? Zone forecasts are the forecaster's narrative text with no structured values. Pass coordinates when you need numbers.
How current is the data? Gridpoint forecasts are re-issued several times a day, alerts are effectively real time, and station observations update roughly hourly. updatedAt carries the timestamp NWS stamped on the product it served.
Can I schedule it? Yes, and that is the intended use. There is no quota to exhaust, so hourly or even quarter-hourly alert sweeps are fine.