If you’re logging raw WeatherAPI responses and you’ve noticed that the station_id field occasionally switches between calls for the same lat/lon — you’re not imagining it, and it’s not a bug. It’s the expected output of a station selection system that re-evaluates which METAR station is most representative at query time, not at setup time.
Most pipelines aren’t built for this. They quietly store readings from two or three different stations into the same time-series column and then wonder why the data looks noisy.
What’s Actually Happening
Our station selection doesn’t pick the nearest METAR station once and lock it in. Each call goes through a composite scoring pass that weights distance, elevation difference, and recent station consistency. A station that scores well at 14:00 UTC might score lower at 20:00 UTC if it’s gone quiet or its readings have diverged from neighbors — and a slightly farther station can then take over.
The two most common triggers are station dropout and boundary conditions. Station dropout is straightforward: METAR stations report on a schedule (typically hourly for ASOS/AWOS, sometimes more for special reports), and when a station misses a couple of cycles its recency score degrades. A competing station at slightly greater distance but with fresh, consistent readings will edge it out.
Boundary conditions are subtler. If a query coordinate sits roughly equidistant between two stations with similar elevation profiles, a small change in either station’s recent variance can flip the winner. This is especially common in dense networks — parts of the UK, the US Northeast, central Europe. Ironically, the denser the network, the more often you’ll see station switching, because the margin between candidates is thin.
Why It Matters More Than You’d Think
A station switch doesn’t just change the station_id field. It changes the underlying observation point. If EGPF (Glasgow Airport) and a station 12 km northeast trade places in your time-series, temperature readings can differ by a degree or two consistently — not because conditions changed, but because one station sits at 8 m elevation and the other at 63 m. That’s before any lapse-rate correction gets applied.
For a dashboard that refreshes every 30 minutes, this is cosmetic. For anomaly detection, degree-day accumulation, or backtesting a model against recent actuals, it’s a quiet data integrity problem that’s genuinely hard to diagnose after the fact.
Condition code mapping is affected too. We translate raw METAR observations to our own numeric condition codes, and that translation is sensitive to which observation you started from. Two stations 10 km apart can report different present-weather groups for the same general conditions — particularly for fog, mist, and light precipitation near reporting thresholds. A station switch at the wrong moment can flip condition code 1183 to 1180, or toggle is_day indirectly through a different station’s local horizon geometry. Small effects, but they cascade if downstream logic branches on them.
How to Build Around It
The fix isn’t to suppress station switching — the switching is usually the right call. The fix is to make your pipeline aware of it.
1. Always persist station_id alongside the reading
A lot of pipelines store only the weather values. If you’re not storing station_id — and ideally the station’s lat/lon and elevation, which you can pull from a one-time lookup — you lose the ability to retroactively segment your time-series by station and understand which readings are actually comparable.
A minimal schema addition looks like this:
ALTER TABLE weather_observations
ADD COLUMN station_id VARCHAR(10),
ADD COLUMN station_lat DECIMAL(7,4),
ADD COLUMN station_lon DECIMAL(7,4),
ADD COLUMN station_elev_m SMALLINT;
You don’t need to re-query elevation on every call. Build a small local lookup table keyed on station_id and populate it lazily — first time you see a new station ID, fetch its metadata and cache it. ICAO codes are stable identifiers; elevation doesn’t change.
2. Flag station transitions in your ingestion layer
Keep a per-location variable for the last seen station_id. When it changes, write a transition event rather than silently continuing the series:
if (latestObservation.StationId != previousStationId)
{
await LogStationTransition(locationKey, previousStationId, latestObservation.StationId, timestamp);
previousStationId = latestObservation.StationId;
}
That transition log costs almost nothing to maintain and makes debugging a data anomaly three months from now vastly easier than trying to reconstruct it from raw values.
3. Don’t interpolate or diff across a station boundary
If your pipeline computes rolling deltas — temperature change over the last hour, precipitation accumulation since midnight — treat a station transition as a break in the series. A delta computed across two different stations is physically meaningless, even if the numbers happen to be close. Zero it out or mark it null for the observation immediately following a switch. This is the step most pipelines skip, and it’s where bad values actually surface.
4. Use pinned coordinates for anything that needs stability
If your use case genuinely requires a stable observation point — monitoring conditions at a specific warehouse or agricultural site — pass a precise lat/lon rather than a location string. The station-scoring system still runs, but if your coordinate is within a kilometer of a single dominant station with good data quality, it won’t switch.
What you want to avoid is a vague location string that resolves differently across calls because our geocoding returns slightly different coordinates each time. A coordinate pinned to five decimal places is much more stable input than location=Glasgow.
A Realistic Frequency Estimate
We don’t publish a specific switch rate because it varies heavily by region and time of day. Dense networks near airports tend to be more stable than sparse rural ones. Overnight hours see slightly more dropout-driven switches because some stations go into reduced-reporting mode. High-elevation and coastal locations — the same ones where station representativeness matters most — tend to have fewer nearby candidates, so when a switch does happen, the gap in readings is larger.
None of this is unique to our API. Any service pulling from METAR networks has the same underlying variability. The difference is whether it’s exposed or hidden behind a smoothing layer that introduces its own problems. We’d rather you see the actual station and deal with it than have us silently average across sources and obscure what you’re getting.
One Caveat Worth Naming
Station-transition awareness doesn’t eliminate the underlying physical reality that two nearby stations can read differently even when both are reporting accurately. Lapse-rate corrections help — roughly 0.65°C per 100 m of elevation difference, per the standard atmosphere model WMO uses — but they’re a general atmospheric average, not a measurement of the specific terrain between your query point and the station. If you’re using this data for something where a 1°C systematic offset would matter (agriculture, energy load forecasting, cold-chain logistics), it’s worth checking station elevation against your actual site elevation and deciding whether to apply your own correction on top of what the API returns.
The station_id field is in every realtime and current-conditions response for exactly this reason. If its value changes, that’s signal — treat it as one.
