We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
Call
https://coords.zone/api/v1/climate
with lat
and lng
query
parameters. It returns the average last spring frost and first autumn frost for that point,
both as a day-of-year number and as a readable date — for latitude 42.36, longitude −71.06
(Boston, Massachusetts) the last spring frost is Apr 5
and the first autumn
frost is Nov 9, a growing season of about 217 days. No API key is required
to try it.
curl "https://coords.zone/api/v1/climate?lat=42.36&lng=-71.06"
{
"lat": 42.36,
"lng": -71.06,
"min_temp": -19.34,
"max_temp": 23.16,
"frost_last_doy": 95.4,
"frost_last_date": "Apr 5",
"frost_first_doy": 312.57,
"frost_first_date": "Nov 9"
}
| Field | Type | Description |
|---|---|---|
| frost_last_doy | number | Last spring frost as a day of year, 1–365. Fractional, because it is an average across years. |
| frost_last_date | string |
The same date rendered as "Mon D", e.g. "Apr 5".
|
| frost_first_doy | number | First autumn frost as a day of year. |
| frost_first_date | string |
The same date rendered as "Mon D".
|
| min_temp | number | Average annual extreme minimum temperature, °C. This is the value the USDA zone is derived from. |
| max_temp | number | Average annual extreme maximum temperature, °C. |
min_temp and max_temp are
truncated above for readability; the API returns full floating-point precision.
The frost-free window is the gap between the two day-of-year values, which is why they are exposed as numbers and not only as strings:
const res = await fetch(
"https://coords.zone/api/v1/climate?lat=42.36&lng=-71.06"
);
const { frost_last_doy, frost_first_doy } = await res.json();
const growingSeasonDays = Math.round(
frost_first_doy - frost_last_doy
);
console.log(growingSeasonDays); // 217
In Python:
import requests
c = requests.get(
"https://coords.zone/api/v1/climate",
params={"lat": 42.36, "lng": -71.06},
).json()
print(round(c["frost_first_doy"] - c["frost_last_doy"])) # 217
Every value here is a 30-year climatological average, not a prediction for the current year. "Last frost Apr 5" means that in a typical year the last freezing night falls around 5 April at that location — roughly half of years will have a later one. Gardeners traditionally add a safety margin of one to two weeks before planting frost-tender crops, and this API deliberately does not pick that margin for you.
The fractional day-of-year values are a direct consequence of averaging: a
frost_last_doy
of 95.4 is the mean of many individual years'
last-frost days, not a claim of sub-day precision. Round them before showing them to
people, or use the pre-rendered frost_last_date
and frost_first_date
strings.
In climates that never reliably freeze, there is no meaningful frost date, and the frost
fields come back as null
rather than as an invented date. Latitude 1.35, longitude 103.82 (Singapore) returns:
{
"lat": 1.35,
"lng": 103.82,
"min_temp": 23.29,
"max_temp": 27.33,
"frost_last_doy": null,
"frost_last_date": null,
"frost_first_doy": null,
"frost_first_date": null
}
Treat null
as "frost-free" rather than as an error, and guard the
growing-season subtraction above accordingly.
Frost dates are derived from ERA5-Land, the highest-resolution reanalysis in ECMWF's ERA5 family, over decades of record. Coverage is global and land-based, so the same call works for any land coordinate on Earth. Treat the result as a regional average rather than a reading for one garden: elevation, slope, and urban heat can shift real frost dates by days between neighbouring sites.