Weather API

Free weather forecast API for personal use

No API key required Non-commercial use

Overview

The response holds up to four blocks: the conditions now, a 60 minute rain forecast, 240 hourly rows, and 10 daily rows.

Build a request

Start with
1. Location

The service moves your position to the cell 42.35, -71.05. The cell is about 5.5 km across.

2. Data
Item Now Hour by hour Day by day
Temperature
Temperature Included Included Included
Feels like Included Included Included
Dew point Included Included Included
Heat index Included Included Not available
Humidity Included Included Included
Rain and snow
Rain rate Included Included Not available
Rain total Not available Included Included
Chance of rain Not available Included Included
Rain or snow Included Included Included
Wind
Wind speed Included Included Included
Wind gust Included Included Included
Wind direction Included Included Included
Sky and air
Cloud cover Included Included Included
Visibility Included Included Included
Pressure Included Not available Not available
UV index Included Included Included
In words
Conditions Included Included Included
Summary text Included Included Included
Sun and moon
Sunrise and sunset Not available Not available Included
Twilight times Not available Not available Included
Moon Not available Not available Included

A dot means the block carries the item. A dash means it does not. Every row carries its own time stamp. The Next 60 minutes block covers the United States and Europe.

3. Units

Imperial units add fields. Imperial units do not replace the SI fields. The times use the local time zone of the coordinate.

Your API URL
4. Preview

5. Use it in code
Terminal
curl "https://graysky.net/free/v1/forecast/42.35,-71.05?dataSets=current,daily"

Endpoint

GET https://graysky.net/free/v1/forecast/{LATITUDE},{LONGITUDE}
Terminal
$ curl "https://graysky.net/free/v1/forecast/42.35,-71.05?dataSets=current,hourly,daily"

The coordinate cell

The service moves your position to a 0.05 degree cell. A cell is about 5.5 km across. The response header X-Gc-Grid shows the cell. Example: the point 42.3601,-71.0589 becomes the cell 42.35,-71.05.

Query parameters

NameDefaultDescription
dataSets current,daily A comma-set of blocks: current, minutely, hourly, and daily. See Data blocks. An unknown member gets HTTP 400.
units si si or imperial. Imperial units add fields. Imperial units do not replace the SI fields. See Units.
lang en The API answers in English only. A different value gets HTTP 400.

The service ignores an unknown query parameter. A link with ?utm_source= works. The service resolves the time zone from the coordinate and returns it in location.timezone. Do not send a timezone parameter.

Data blocks

The dataSets parameter selects the blocks. Each block is one part of the response. See Response format for the shared field rules.

BlockFields
current validAt, conditionCode, conditionLabel, temperatureC, feelsLikeC, heatIndexC, dewPointC, humidityPercent, cloudCoverPercent, visibilityKm, uvIndex, uvCategory, pressureMb, precipRateMmHr, precipType, windSpeedMs, windGustMs, windDirectionDeg, windDirectionCardinal, summary
minutely 61 rows of validAt, precipRateMmHr, and precipChancePercent, plus coverage and anchorAgeMinutes. Radar coverage is the United States and Europe. Outside that area, data[] is empty and coverage says so.
hourly The current set without pressureMb, plus precipMm and precipChancePercent, in 240 hourly rows.
daily temperatureMaxC/MinC, feelsLikeMaxC/MinC, dewPointMaxC/MinC, humidityPercent, cloudCoverPercent, visibilityKm, uvIndex, uvIndexPeakTime, precipMm, precipChancePercent, precipType, wind fields, sunriseAt, sunsetAt, solarNoonAt, dawn and dusk times, moonriseAt, moonsetAt, moonPhase, narrative, in 10 daily rows.

Two gaps to know. pressureMb is in the current block only. Precipitation is one precipMm amount plus a precipType value; there are no separate rain, shower, and snowfall fields.

Response format

The response is one JSON object with location, meta, and the blocks you requested. These rules hold everywhere:

  • SI on the wire. Values are metric with a unit suffix: temperatureC, windSpeedMs, precipMm. The imperial option adds companion fields. It removes nothing. See Units.
  • RFC 3339 timestamps. Each time field is an RFC 3339 string with an explicit offset, not a Unix epoch.
  • Percentages are 0-100. humidityPercent, cloudCoverPercent, precipChancePercent.
  • Wind comes paired. windDirectionDeg (0-360) and windDirectionCardinal (for example SW).
  • Conditions are an enum. conditionCode is a fixed string with a human conditionLabel beside it. See condition codes.
  • Nullable, not absent. A field with no data is null, not dropped. A decoder can rely on the shape.

location

FieldTypeNotes
latitudenumberThe latitude of the cell that answered.
longitudenumberThe longitude of the cell that answered.
timezonestringThe IANA time zone name, for example America/New_York.
utcOffsetSecondsintegerThe offset from UTC in seconds. It includes DST.

meta

FieldTypeNotes
unitsstringEchoes the request's units value. The wire is always SI. This is a display hint.
generatedAtstringThe RFC 3339 time of the response build.
expiresAtstringA client-cache hint. It matches the Cache-Control lifetime.
modelSourcesstring[]The internal model identifiers in this response.
attributionstringThe credit string.

Condition codes

conditionCode is one value from a fixed set. New values are additive. Treat an unknown value as cloudy. The current set:

clear-day, clear-night, mostly-clear-day, mostly-clear-night, partly-cloudy-day, partly-cloudy-night, mostly-cloudy-day, mostly-cloudy-night, cloudy, rain, sleet, snow, wind, fog, hail, thunderstorm, scattered-thunderstorms, isolated-thunderstorms, tornado, limited.

limited marks a degraded entry. The validAt is valid, but the numeric fields are null, because every model source ran out of coverage for that lead. Show "data unavailable", not a zero.

The machine-readable contract is /dev/openapi.yaml (OpenAPI 3.1).

Units

ValueBehavior
si (default) SI fields only: temperatureC, windSpeedMs, precipMm, and so on.
imperial The SI fields plus imperial companions on the same entry. meta.units echoes imperial.

A companion appears only when the SI source field is present. A null SI value makes a null imperial value. The API never invents a number.

SI to imperial companion map

SI fieldImperial companionConversion
temperatureCtemperatureF°C → °F
feelsLikeCfeelsLikeF°C → °F
dewPointCdewPointF°C → °F
heatIndexCheatIndexF°C → °F
temperatureMaxC / temperatureMinCtemperatureMaxF / temperatureMinF°C → °F (daily)
windSpeedMs / windGustMswindSpeedMph / windGustMphm/s × 2.23694
precipMmprecipInmm ÷ 25.4
precipRateMmHrprecipRateInHrmm/hr ÷ 25.4
visibilityKmvisibilityMikm × 0.621371
pressureMbpressureInHgmb × 0.02953

Response headers

HeaderMeaning
X-Gc-SurfaceAlways free-v1 on this endpoint.
X-Gc-GridThe 0.05 degree cell that answered.
X-Gc-BudgetHow much of this hour's shared budget is used, in steps of 10 percent.
X-AttributionThe credit line. Show it or link to graysky.net.
Cache-ControlHow long the answer stays fresh. Keep each answer for at least that long.
LinkPoints to the rules on this page (rel="terms-of-service").

The service sends Access-Control-Allow-Origin: *. A browser page can call the API directly.

Errors

Each error is an RFC 9457 Problem Details object with Content-Type: application/problem+json:

400 Bad Request - application/problem+json
{
  "type": "https://graysky.net/dev#bad-coordinate",
  "title": "Bad Request",
  "status": 400,
  "detail": "The path needs latitude,longitude in degrees. Example: /free/v1/forecast/42.35,-71.05",
  "traceId": "8f1c2a7d9e3b4c01-BOS"
}
FieldNotes
typeA URI for the problem type. It points at a row in the table below.
titleA short name for the status.
statusThe HTTP status code, repeated in the body.
detailWhat went wrong in this request.
traceIdThe correlation id. Quote it when you report a problem.

The type URI ends with one of these fragments:

Statustype fragmentCause
400#bad-coordinateThe path is not a valid latitude,longitude pair.
400#bad-parameterAn unknown dataSets member, a bad units value, or a timezone parameter.
400#unsupported-languageThe lang value is not en.
404#no-coverageGraySky has no data for this point now.
503#budget-exhaustedThe shared budget for this hour is empty. Wait for the Retry-After seconds.
503#service-disabledThe free service is off.
502#upstream-errorThe data source sent an error.
504#upstream-timeoutThe data source did not answer in time.

Good fits

  • Fixed displays. A Raspberry Pi panel, a smart mirror, a desk widget, or a lamp that turns blue before rain.
  • Home automation. A Home Assistant sensor. Skip the irrigation when today's precipMm is above 2. Close the blinds when uvIndex passes 7.
  • A rain warning for one place. The minutely block holds 61 per-minute rows. Use it to warn yourself 20 minutes before the rain starts.
  • Classroom projects. For students building web apps that work on the first try.
  • Chat bots. A bot that posts one daily forecast for one town.
  • Personal scripts. A shell prompt, a terminal weather command, or a morning cron job.
  • Garden and sensor logs. Log the forecast rain total (precipMm) for one yard. Or compare a home weather station's own readings with the forecast.

Poor fits

These uses empty the shared budget, or the rules do not permit them.

UseWhy
Commercial workThe rules do not permit it. Email [email protected].
A page that shows many citiesEach new cell is a new request to the origin.
An app with a location for each userEach user adds a cell. The budget empties quickly.
Bulk collection of the gridIt empties the shared budget for everybody.
Severe-weather alarmsThe free API does not serve the alerts block. Do not build a safety alarm on it.

Limits and rules

This API needs no key and no account. It has rules.

  • Use this API for non-commercial work only.
  • Give credit to GraySky. Add a link to graysky.net.
  • Poll each coordinate at most once every 10 minutes. A faster poll returns the same cached response.
  • Send fewer than 10 requests each minute.

Caching

The service caches each answer at the edge. A cache hit does not use the shared budget. A repeat of a warm cell costs the service almost nothing.

The Cache-Control header shows how long an answer stays fresh. Keep each answer for at least that time. An answer with the minutely block stays fresh for about 2 minutes. All other answers stay fresh for about 10 minutes.

Data sources

GraySky makes the forecast with a proprietary multi-model engine. The engine blends these inputs:

  • Short-term models. Kilometer-scale numerical models over North America. They power the first 48 hours of the hourly block and most of the current block.
  • Global models. Two independent global models make the 2 to 10 day outlook in the daily block and the second half of the hourly block.
  • Live radar. Radar mosaics over the United States and Europe feed our nowcaster. The nowcaster makes the minutely block.
  • Surface observations. Tens of thousands of stations feed our verification pipeline. The pipeline trains the calibration layer.

We add three layers on top:

  • Bias calibration. We correct temperatures with per-city tables. We fit the tables each night against station observations. We recalibrate rain probabilities each night against radar truth.
  • Model blending. Where two models disagree, we use the model with the better score for that location and that variable.
  • Plain-language summaries. A deterministic rule set writes the summary fields from the numbers. No generative model writes them.

Refresh cadence

LayerRefresh
Minutely precipitationEvery 2 minutes during active precipitation. Every 10 minutes when clear.
Current conditions and hourlyEvery 15 minutes.
Daily 10-day outlookEvery 6 hours.
Bias-calibration tablesRefit every night against the latest observations.

Coverage

BlockCoverage
currentWorldwide
minutelyUnited States and Europe
hourlyWorldwide
dailyWorldwide

FAQ

Do I need an API key?

No. Send the request. There is no key, no account, and no sign-up.

Can I call the API from a browser page?

Yes. The service sends CORS headers. A page on any origin can call the API. The rules also apply to a page.

Is there an SDK?

No. The API is plain HTTP and JSON. Every language can call it. To get a typed client, generate one from /dev/openapi.yaml with an OpenAPI 3.1 tool.

What is the coverage outside the United States?

The current, hourly, and daily blocks are global. The minutely block covers the United States and Europe.

Can I use the data in a commercial product?

No. The free API is for non-commercial work only. For commercial use, email [email protected].

Can I republish the data?

Show the data to your users, with credit to GraySky. Do not mirror the API. Do not sell the raw JSON.

How do I contact you?

Email [email protected]. Include the traceId from the error response when you report a problem.