Polling Frequency vs. Data Freshness: Why Hitting the API More Often Isn’t Getting You Fresher Data

A pattern I see constantly in support emails: a developer is polling the current conditions endpoint every 30 seconds, burning through quota, and somehow still serving data that’s 15 minutes old. They’ve convinced themselves the fix is to poll more often. It isn’t. They’ve misunderstood where the freshness ceiling actually sits.

The ceiling isn’t the API. It’s the underlying observation and model update cadence — and no polling rate gets you past it.

What’s Actually Updating and When

METAR observations are issued roughly every hour at most stations, with busier airports issuing special reports (SPECIs) when conditions change significantly between scheduled observations. That’s your real-time floor for surface conditions: a new reading exists at best once per hour, usually on the hour. The last_updated field in a current conditions response reflects when the underlying observation was issued, not when the API last served you a response. Those are different things, and conflating them is where most over-polling starts.

For forecast data, freshness is governed by model run timing. GFS runs four times daily at 00Z, 06Z, 12Z, and 18Z. HRRR runs hourly but takes roughly 45–50 minutes to complete a run and work through downstream processing. NAM also runs four times daily. The practical consequence: between HRRR runs, the freshest available short-range forecast for a US location is already up to an hour old before you make the request. Polling every minute during that window gets you the same answer 60 times.

Our GRIB2 ingestion pipeline — pulling from HRRR, NAM, GFS, and ECMWF — processes model output as it becomes available. But we can’t serve data that hasn’t been computed yet. When a model run hasn’t completed, we serve the previous run’s output. That’s the correct behavior. Serving partial output from an in-progress run would be worse.

The Actual Freshness Window by Data Type

These differ enough that they should drive different polling logic:

  • Current conditions (METAR-backed): Updates roughly hourly. Polling faster than once every 10–15 minutes is chasing nothing — and even that’s conservative, since a genuinely new reading arrives at most once per hour.
  • Short-range forecast (HRRR coverage areas, US): New data available roughly every 60–75 minutes once you account for run time and ingestion. More frequent polling returns the same forecast with a newer HTTP timestamp.
  • Medium-range forecast (GFS, NAM): Four runs per day, so roughly a 6-hour window between genuine updates. For 7–10 day forecasts, polling more than once per hour is almost never justified.
  • Air quality: Often updated less frequently than surface weather — sometimes every few hours depending on the underlying source. The air_quality block reflects the freshest available index values, but those can lag current conditions by several hours.

How to Actually Design Around This

The useful mental model: know the upstream update cadence for what you care about, then set your polling interval to slightly exceed it — not match it, exceed it. You want to catch new data shortly after it lands without hitting the endpoint repeatedly before it does.

For current conditions, every 10 minutes is reasonable. For short-range hourly forecast, once every 30–45 minutes is plenty. For daily forecast, once per hour is generous. You can tighten these if you need to react to SPECI conditions arriving at irregular intervals, but that’s an edge case worth designing for explicitly rather than applying to everything.

A cleaner pattern for most apps: cache the response locally with a TTL that matches the upstream update window, and re-request only when that TTL expires. Then compare last_updated across successive responses — if it hasn’t changed, you haven’t gotten new data regardless of how recently you asked. Some teams build a lightweight check that skips processing the response body entirely when last_updated matches the previous call.

This matters more than it sounds on a free or starter tier. Quota exhaustion usually isn’t a traffic problem — it’s a polling logic problem. Five hundred requests over six hours that all return the same underlying data is a design issue, not a capacity issue.

One Wrinkle: The “Freshness Theater” Problem

There’s a subtler trap for developers who do handle the basic cadence correctly. Some weather APIs update the last_updated timestamp on every response even when the underlying observation hasn’t changed. The data looks fresher than it is: you poll, get a new timestamp, infer you received new data, process it, show it to the user — but the actual temperature, wind speed, and condition code are identical to what you had 20 minutes ago.

We try not to do this. Our last_updated reflects observation time, not response generation time. But it’s worth verifying against whatever API you’re building on. If the timestamp increments on every request regardless of the underlying data, it’s decorative. Check whether the actual field values are changing, not whether the timestamp is.

When Faster Polling Is Legitimately Justified

There are real use cases where sub-10-minute polling makes sense: real-time lightning detection feeds, high-frequency SPECI monitoring for rapidly changing airport visibility, storm cell tracking during active convection. But those cases typically require sources beyond a standard conditions API — dedicated lightning APIs, ASOS feeds, radar-derived products. A general-purpose weather endpoint isn’t the right tool for sub-minute event detection, and polling it faster won’t make it one.

For anything genuinely time-sensitive, alerts and webhooks are usually the right architecture — the server tells you when something changes rather than you checking constantly for changes that mostly aren’t there. We’re still working out the right shape for push-based delivery on our end, but the principle holds regardless of implementation.

Before you touch your polling interval, check last_updated. If the observation time hasn’t moved, neither has your data — and that won’t change until the next METAR lands or the next model run completes. That’s the right place to start debugging, and it usually turns out to be the whole problem.

Scroll to Top