You’re looking at a current conditions response. The condition.text field says “Light drizzle”. The weather_code is 1153. And precip_mm is 0.0.
Not a bug. Not a data gap. This is how precipitation reporting works — and if your application uses precip_mm > 0 as the condition for “it is raining”, you’re going to miss a real slice of precipitation events.
What “trace” means in meteorological terms
Trace precipitation has a formal definition. WMO guidance and standard METAR reporting both treat precipitation as measurable only when it accumulates to at least 0.1 mm (roughly 0.004 inches) within a given observation window. Anything below that threshold is classified as a trace — precipitation fell, but not enough to register against the measurement floor of most tipping-bucket gauges and automated surface observation systems (ASOS).
This isn’t an approximation or a laziness in reporting. A tipping-bucket gauge physically cannot tip for less than its minimum increment — typically 0.1 mm or 0.01 inches depending on the instrument. The infrastructure itself sets the floor. Readings below that threshold aren’t recorded as a quantity; they’re recorded as trace or zero depending on the system’s reporting convention.
When we ingest METAR observations alongside NWP model output — HRRR, NAM, GFS — that same threshold propagates forward. A forecast grid cell producing sub-0.1 mm of liquid equivalent in an hour will often emit 0.0 for the precipitation field, even if the condition code correctly reflects drizzle or light rain. The two data sources aren’t in conflict. They’re answering different questions.
The specific mismatch this creates
condition.text and weather_code are derived from a broader signal — cloud type, visibility, humidity, METAR present weather codes (the DZ, RA, BR group in a raw METAR string). These can and do indicate precipitation at rates that never accumulate to the measurement threshold in a one-hour window.
Light drizzle at 0.05 mm/hr falls continuously for an hour. Total accumulation: 0.05 mm. That gets stored and returned as 0.0. Meanwhile the METAR reported -DZ (light drizzle) the whole time, which is what drives the condition code. So your response correctly says “Light drizzle” and correctly says precip_mm: 0.0. Both are accurate. Application code written to check only precip_mm concludes it isn’t raining.
The same pattern shows up with freezing drizzle, light snow in marginal conditions, and intermittent light rain. Snow is especially prone to it — low-density snowfall can produce a valid -SN METAR observation with liquid water equivalent well under the reporting threshold.
What to actually check
The fix requires checking more than one field. For most applications, the right pattern looks like this:
bool isRaining = response.current.precip_mm > 0
|| IsPrecipitationCode(response.current.condition.code);
Where IsPrecipitationCode tests against the range of condition codes that represent active precipitation — drizzle (1150–1153), rain (1180–1201), snow (1210–1225), sleet and ice (1237–1252), and the mixed types. The full condition code list is documented; keep a local lookup rather than doing string matching on condition.text, since the text is locale-dependent and can change.
For apps that need to distinguish “wet ground from earlier rain” from “actively precipitating right now”, the condition code is more reliable than precip_mm at low intensities. For apps calculating load — roof drainage, agricultural irrigation accounting, flood modelling — precip_mm is the right field, and a 0.0 there genuinely means negligible accumulation even if some precipitation is occurring.
These are different questions. Use the right field for the question you’re actually asking.
Hourly vs. real-time: the window matters
The threshold issue is more pronounced in real-time responses than in hourly forecast data. A current conditions snapshot represents a point-in-time observation window — however long since the last METAR was issued, typically 20–60 minutes. A 0.05 mm/hr drizzle rate over a 30-minute window produces 0.025 mm total accumulation, which rounds to zero.
In hourly forecast data the accumulation window is a full 60 minutes, so the same 0.05 mm/hr rate gives 0.05 mm — still under the 0.1 mm threshold, still potentially returned as 0.0, but less dramatically so. At higher rates (0.2 mm/hr and up), hourly forecast precip_mm becomes reliable as a positive indicator. The real-time endpoint is where you’ll see the most trace-vs-zero ambiguity.
Why lowering the threshold doesn’t fix this
A reasonable question: why not store and return sub-threshold values as 0.05 instead of 0.0? Below the instrument measurement floor, you don’t have a measured value — you have an inferred one. If the gauge didn’t tip, you have a detection (precipitation occurred) but not a measurement (how much). Returning a synthetic value like 0.05 would imply a precision that doesn’t exist in the source data, which is a worse outcome than returning 0.0 and letting the condition code carry the qualitative signal.
NWP models do output sub-threshold grid values, so for forecast hours we have more to work with than for real-time METAR observations. But model output at these intensities carries enough uncertainty that fine-grained sub-threshold precision isn’t really meaningful. We’d rather return what the data actually supports.
Practical impact by use case
For outdoor scheduling apps (construction, events, sports), triggering on condition code is almost always better than triggering on precip_mm alone. A drizzle that doesn’t accumulate is still a drizzle — it affects ground conditions, visibility, and user experience.
For energy and agriculture applications tracking actual water input to a system, precip_mm is the right field, and trace precipitation often genuinely doesn’t matter. A 0.05 mm trace event doesn’t move soil moisture in any meaningful way.
For IoT and sensor correlation work — if you’re comparing our data against your own gauges and seeing the API report 0.0 while your sensor shows 0.08 mm — this is probably why. Your gauge may be logging trace; we’re rounding to the measurement floor. Both are correct; they’re reporting differently.
If your app cares whether precipitation is happening, check the condition code. If it cares how much has accumulated, use precip_mm. The field that looks broken is usually the one being asked the wrong question.
