UV Index Is Modeled, Not Measured
Most developers pull uv_index from a weather API response, display it to users, maybe color-code it green through red, and move on. The number looks authoritative. It isn’t — at least not in the way a temperature reading from a physical sensor is.
UV index in API responses, including ours, is almost always a modeled output: a function of solar zenith angle, total column ozone (typically pulled from satellite retrievals like OMI or TROPOMI), surface albedo, altitude, and cloud optical depth. No UV pyranometer is sitting at the coordinates you queried. The model estimates what would reach the surface if conditions matched the inputs. That distinction matters more than most people expect.
What the WMO Definition Actually Says
The UV index standard comes from a 1994 joint recommendation by the World Health Organization, WMO, UNEP, and ICNIRP. It defines UV index as a dimensionless linear scale where 1 unit corresponds to 25 mW/m² of erythemally-weighted UV radiation — the portion of the spectrum that causes sunburn, weighted by how effectively each wavelength does so. That weighting function peaks around 297–298 nm and drops sharply on both sides.
The index is erythemal, not broadband. A UV-A tanning lamp and direct July noon sun can have wildly different UV indices even if their total radiant power looks similar, because UV-A (315–400 nm) contributes almost nothing to the erythemal calculation. If you’re building anything around skin safety, “UV radiation” is not one thing — and the index only captures part of it.
The Four Variables That Move the Number Around
Solar Zenith Angle
This is the dominant driver and the one the model gets most reliably right. As the sun approaches the horizon, UV index drops fast — the path length through the atmosphere roughly doubles for every ~10 degrees of zenith angle past 60°. Near sunrise and sunset it’s essentially zero regardless of other conditions. The geometry here is straightforward and the model handles it well.
Total Column Ozone
Stratospheric ozone is the primary UV-B filter. A 1% decrease in ozone produces roughly a 1.5–2% increase in erythemally-effective UV at the surface — a relationship sometimes called the radiation amplification factor. Satellite ozone retrievals are generally good, but they’re not instantaneous. There’s latency in the data pipeline, and ozone varies by latitude and season in ways that matter especially at high latitudes in spring.
Cloud Cover and Optical Depth
This is where modeled UV index gets genuinely unreliable. Thick overcast can reduce UV index by 70–80%. Scattered cloud is more complicated: broken cloud fields can actually increase surface UV transiently through multiple scattering — the “broken cloud enhancement” effect is well-documented and can push instantaneous readings above clear-sky values. Most UV models either ignore this entirely or handle it through a single cloud modification factor derived from cloud cover percentage. If you’ve read our post on why cloud cover percentages are imprecise, you’ll recognize that same limitation compounding into the UV estimate.
Surface Albedo and Altitude
Fresh snow reflects 80–90% of incoming UV, and that reflected radiation adds to direct irradiance for someone standing on a slope. The model uses climatological or land-use-derived albedo values that won’t capture a fresh snowfall. Altitude matters independently — UV intensity increases roughly 6–10% per 1,000 meters of elevation gain, partly from reduced air mass and partly because there’s less ozone column above a high-altitude location. We apply an altitude correction in our pipeline, but it’s a general atmospheric correction, not a measurement of the specific location’s column.
Where API UV Index Specifically Breaks Down
The failure modes worth knowing about:
- High-reflectance surfaces. Ski resorts and snowfields. The model’s albedo assumption will underestimate effective UV exposure for someone on the ground.
- Partly cloudy days near solar noon. The broken cloud enhancement effect means the API might report a moderate UV index right as a momentary ground reading would spike above it.
- Urban canyons and shaded contexts. UV index is calculated for a horizontal surface with unobstructed sky view. Someone in a street canyon with buildings on three sides is getting a fraction of the modeled value. The model has no way to know that.
- Forecast UV vs. real-time UV. Pulling tomorrow’s UV index compounds cloud forecast uncertainty on top of UV modeling uncertainty. For general planning that’s usually fine. For anything claiming to be a precise real-time reading, the number is lagged and spatially averaged.
How to Consume It Responsibly in Code
Don’t Treat Decimal Precision as Real
Our API returns UV index as a float — something like 6.2. That decimal is not meaningful precision. Round to the nearest integer for display. The WHO categorizes UV into five bands (Low 0–2, Moderate 3–5, High 6–7, Very High 8–10, Extreme 11+) and those band boundaries are where communication should happen, not sub-integer values.
// Python example
uv_raw = response["current"]["uv"]
uv_index = round(uv_raw)
if uv_index <= 2:
category, advice = "Low", "No protection needed"
elif uv_index <= 5:
category, advice = "Moderate", "Cover up during midday"
elif uv_index <= 7:
category, advice = "High", "Sun protection essential"
elif uv_index <= 10:
category, advice = "Very High", "Extra protection needed"
else:
category, advice = "Extreme", "Avoid sun during midday hours"
Layer in Altitude Awareness
If your app serves users in mountainous regions — ski apps, hiking apps, anything in the Alps, Rockies, or Andes — apply a simple multiplicative correction on top of the returned value. A rough heuristic: add 8–10% per 1,000 meters above the station elevation. You can get elevation from our API’s location object. It won’t be precise, but it’s better than presenting a sea-level UV index to someone at 2,500m without any adjustment.
Flag Uncertainty on Partly Cloudy Days
If cloud is between roughly 25% and 75%, the UV index you’re showing has wider error bars than on clear or fully overcast days. Not a reason to hide the number — but worth surfacing in the UI. Something as simple as “UV may be higher under broken cloud” is honest and useful. You can pull cloud from the same API response.
Use Local Solar Noon, Not Wall Clock
Peak UV tracks solar noon, not 12:00 on a clock. It varies by longitude within a timezone, sometimes significantly. Our response includes astronomy.sunrise and astronomy.sunset; solar noon is roughly the midpoint. If your app guides users on when UV peaks, calculate from that midpoint. In a wide timezone like US Central, solar noon can differ from clock noon by over 30 minutes at the edges.
One Position Worth Stating Clearly
Apps that display UV index with high-precision numerics and confident language about “safe” versus “unsafe” exposure windows down to the minute are misrepresenting what the model can support. The modeling is good enough for general guidance — wear sunscreen above UV 5, seek shade during the two hours around solar noon on high UV days. It is not good enough to tell someone UV is safe at 11:52 but dangerous at 12:08. The uncertainty in the cloud optical depth estimate alone swamps that kind of precision.
The WHO bands exist for a reason. Use them.
One More Caveat the Docs Won’t Mention
UV index is always the surface value for a standardized horizontal unshaded plane. It says nothing about UV dose actually reaching human skin, which depends on posture, clothing, surrounding surface reflectance, and whether you’re in shade. Occupational health and clinical applications that need actual skin dose estimates use personal dosimeters, not modeled surface UV. For a consumer or developer app, the modeled index is the right input — just don’t let it carry more weight than the model can support.
The most useful thing you can add to an outdoor safety feature isn’t more decimal places. It’s a clear signal about which conditions make the estimate less reliable. Honest uncertainty serves users better than false confidence dressed up as precision.
