Methodology · v1.0

How uvindex.io produces every UV number

The UV Index has a precise scientific definition. This page documents what the numbers on the UV index home page, the city pages and the public API actually are: where they come from, how they are produced, what moment in time they describe, and where they should not be trusted.

Method version
v1.0
Last updated
Product type
Modelled estimates — no own sensors

On this page

The short version

  • We operate no UV instruments. Nothing on this site is a local ground measurement. Every value is a modelled estimate obtained from our data provider, OpenUV.
  • A UV Index is an intensity, not a dose. It describes erythemally weighted irradiance at an instant on a horizontal surface — not accumulated exposure, and not a personal risk score.
  • Retrieval time is not validity time. Each reading carries the provider's own timestamp; we cache values (and can fall back to a last-known-good copy for up to 7 days), so the time we fetched a number is never presented as the time it describes.
  • Some numbers are ours, not the provider's. Risk bands, burn-time estimates, reflective-surface figures, vitamin-D windows and the fallback hourly curve are computed by us from published formulas or heuristics. Each is documented in §5 with its limitations.
  • A displayed 0 can mean "no data". When every provider request fails and no cached value exists, our code returns a zero-filled placeholder. See §6.

1. What the UV Index is

The UV Index (UVI) measures solar ultraviolet radiation weighted by its ability to cause erythema — the reddening of human skin that precedes sunburn. It is not a measure of heat, brightness or total sunlight. The standard definition integrates spectral irradiance across the UV range after applying the reference erythema action spectrum:

UVI = k_er × ∫ E(λ) · s_er(λ) dλ
      integrated over λ = 250 … 400 nm

  E(λ)     spectral irradiance   [W·m⁻²·nm⁻¹]
  s_er(λ)  erythema weighting    [dimensionless]
  k_er     40 m²/W               [fixed constant]
  UVI      dimensionless

In words: measure or model the UV radiation at each wavelength, weight it by how strongly that wavelength reddens skin, add the weighted contributions, and multiply by 40.

The weighting function

Equal energy at different UV wavelengths does not produce equal sunburn. The reference action spectrum (ISO/CIE 17166:2019) weights shorter wavelengths far more heavily:

s_er(λ) = 1                       for 250 ≤ λ ≤ 298 nm
        = 10^(0.094 · (298 − λ))   for 298 < λ ≤ 328 nm
        = 10^(0.015 · (139 − λ))   for 328 < λ ≤ 400 nm

For sampled spectra the integral becomes a sum in which each sample must be multiplied by its own wavelength interval, Δλ — adding raw spectral values without it gives the wrong units and the wrong answer:

UVI ≈ 40 × Σᵢ E(λᵢ) · s_er(λᵢ) · Δλᵢ

Scale and units

Because k_er = 40 m²/W, one UV Index unit corresponds to 0.025 W/m² (25 mW/m²) of erythemally weighted irradiance. An erythemal irradiance of 0.20 W/m² is therefore 40 × 0.20 = UVI 8. A calculation expressed in mW/m² divides by 25 rather than multiplying by 40.

The scale is linear in that weighted irradiance: UVI 8 is twice the erythemal irradiance of UVI 4. It does not follow that any individual's risk doubles — personal sensitivity varies widely, which is why CIE separates standardised radiation quantities from an individual's minimum erythema dose.

Intensity versus accumulated exposure

Exposure is the integral of intensity over time. For an idealised horizontal surface receiving a stated UV level:

H_er = ∫ E_er(t) dt
     = (1/40) × ∫ UVI(t) dt     [J/m², t in seconds]

Example — a hypothetical constant UVI 8
for 20 minutes:
  H_er = (8 / 40) × 1200 s
       = 240 J/m²   (≈ 2.4 SED)

That is arithmetic, not a safe-exposure recommendation. We show it to make the definition checkable, not to imply a harmless period of unprotected exposure.

2. Where our numbers come from

There are two ways to obtain a UV Index: measure it with a spectroradiometer or a calibrated broadband erythemal sensor, or model it from solar geometry, total-column ozone, cloud, elevation, aerosol and surface-reflectance information. uvindex.io does the second — by buying the output of someone else's model.

The chain from the provider to the number on your screen:

OpenUV API v1 — api.openuv.io/api/v1
  ├─ GET /uv        current UV, today's max, timestamps
  └─ GET /forecast  hourly UV points for the day
     auth: x-access-token header · timeout: 8 s
        │
        ▼
Location = the city's stored latitude/longitude
     one point; no elevation parameter is sent
        │
        ▼
uvindex.io cache, per coordinate rounded to 3 dp
     current: 1 hour · forecast: 1 hour
     last-known-good fallback: up to 7 days
        │
        ▼
Values we derive ourselves (§5): bands, burn time,
reflection, vitamin-D windows, fallback curve
        │
        ▼
Display: rounding, UTC timestamps,
HTTP cache 30 min for guests

What the provider value is — and what we do not yet know

We display the provider's UV value as returned. We apply no cloud correction, no elevation correction and no bias adjustment of our own. The sky treatment of the underlying model (clear-sky versus cloud-aware, and how cloud information is applied) is therefore determined entirely by OpenUV, and we do not currently label the sky treatment on each reading. Until the audit in §8 is published, treat every displayed value as a model estimate of unlabelled sky treatment. This is a documented gap, not a claim of cloud-aware accuracy.

Two further distinctions we hold ourselves to:

  • Satellite input ≠ local measurement. Satellite ozone retrievals feed UV models, but a modelled value for your city is not a reading from an instrument in your city. We do not describe any value as "station-measured".
  • Provider ≠ standard. OpenUV supplies the data; WHO, CIE/ISO and NOAA define and standardise the quantity. A WHO reference legitimises the scale we report on — it does not validate our individual forecasts.

Resilience behaviour that affects what you see

  • OPENUV_API_TOKEN may hold several keys; requests are spread across them in random order, and a key answering 401, 403 or 429 (quota) falls through to the next.
  • If every key fails, we serve the last-known-good copy for that location — up to 7 days old.
  • If there is no cached copy either, the request returns a placeholder with uv = 0 and uv_time = null. A null timestamp is the signal that a value is a placeholder rather than a reading.

3. Operational data sources

These are the only sources whose numbers reach the page. The scientific bodies in §9 are references we follow and cite — not data providers for this site.

Source What it supplies
OpenUV — api.openuv.io/api/v1 Every current UV value, hourly forecast and monthly history point on this site. Modelled estimates, not our own measurements.
uvindex.io city database City name, country, latitude/longitude and population. Coordinates are what we send to the provider; a city is a single point, not an area average.

4. Time, caching and freshness

Three different times exist for any reading, and they must not be conflated:

  • Valid time — the moment the value describes. This is the provider's uv_time / uv_max_time, and it is what we display.
  • Issue time — when the provider produced the forecast. OpenUV's response does not expose this to us, so we do not display it; we will not invent it from another timestamp.
  • Retrieval time — when we fetched the value. Fetching a forecast at 12:05 does not mean it was produced at 12:05.

All times on the site are shown in UTC. Local-time display per city is a known limitation (§7).

What Refresh / lifetime Notes
Current UV per location1 hourKeyed to the clock hour, so the value tracks the day's UV curve. The first visitor in an hour triggers the live call.
Explicit-date lookups (e.g. tomorrow)Until end of day (UTC)Requested with the provider's dt parameter.
Hourly forecast1 hourPer location, per clock hour.
Last-known-good fallback7 daysUsed only when every provider key fails. Can make a displayed value days old.
Pre-fetched city readings (map, country pages)Hourly, 06:00–20:00 UTCuv:prefetch; one row per city per day, updated in place. Rows are only written when the provider returned a real timestamp.
Monthly history per cityDaily top-uphistoricaldata:update, for cities with population > 50,000 that have no history yet. See §5.5.
City page HTML (guests)30 minutesCache-Control: public, max-age=1800. Signed-in users are never served a shared copy.
sitemap.xml6 hoursRebuilt from the canonical origin.
UV alert emailsDaily 06:00 UTCSent when tomorrow's forecast maximum reaches the configured threshold (default UVI 8).

5. Numbers we compute ourselves

Everything in this section is produced by uvindex.io, not by the data provider. Each formula is given exactly as implemented, with what it is good for and what it cannot tell you.

5.1 Risk bands

Thresholds follow the WHO reporting categories and are applied to the displayed index:

BandUV IndexApplied as
Low 0 – 2 low
Moderate 3 – 5 moderate
High 6 – 7 high
Very High 8 – 10 very_high
Extreme 11+ extreme

WHO recommends sun protection from UVI 3 upwards. Bands below that are shown as lower risk, which is not the same as risk-free.

5.2 Time-to-burn estimate

minutes = (200 × burn_factor) / (3 × UVI)

burn_factor by Fitzpatrick skin type:
  I 2.5 · II 3 · III 4 · IV 5 · V 8 · VI 15
UVI = 0 → no value is shown

This is a heuristic, not a standard. It has no wavelength model, no personal minimum-erythema-dose input, and no account of clothing, sunscreen, shade, altitude or reflection. WHO's practical guide specifically discourages publishing burn times, because readers can read them as a guaranteed safe period of unprotected exposure. We are replacing this table with a sun-protection window — the hours when the forecast reaches UVI 3 or above — and it is listed as an open item in §7. Treat the current numbers as an order-of-magnitude illustration only.

5.3 Reflective surfaces

UVI_effective = UVI × (1 + R/100)        R = surface reflectance in %

Our reflectance table uses single published figures per surface (for example snow at 69%), while the underlying literature gives ranges — snow is commonly quoted at 50–88% depending on age and condition. The formula above is also an upper-bound illustration rather than a standardised index: the UV Index is defined for a horizontal surface, and reflectance alone does not describe a person's exposure geometry. Read this as education about reflection, not as a second UV forecast for a location. Restoring the published ranges is an open item in §7.

5.4 Vitamin-D exposure windows

The per-skin-type sunlight durations shown on city pages are a fixed editorial table indexed by risk band — not a calculation from your location, date, skin or clothing. The NIH notes that individual responsiveness and environmental factors make prescribing a sunlight duration for adequate vitamin D unreliable, and the American Academy of Dermatology does not recommend obtaining vitamin D through deliberate sun exposure. These windows are therefore illustrative context, are not medical advice, and are queued for replacement with an explanation of the uncertainty (§7).

5.5 Monthly history and season analysis

The 12-point "monthly UV trend" on a city page is built from twelve individual provider requests, one per month:

for each of the last 12 months:
    GET /uv?lat&lng&dt=<first day of month>T12:00:00.000Z
    store result.uv_max          → one value per month
missing value → recorded as "Data not available"

So each point is the modelled daily maximum for the 1st of that month — not an average over the month, not a noon value, and not a long-term climatology. A chart covering the last twelve months describes those twelve days in those twelve months, and nothing more. The season summary averages those monthly values over meteorological seasons (winter = Dec–Feb, spring = Mar–May, summer = Jun–Aug, autumn = Sep–Nov) and reports the highest. Clearer labelling of this statistic is an open item in §7.

5.6 Modelled fallback curves

When the provider's hourly forecast is unavailable (typically an exhausted quota), the hourly chart is not left blank — it is filled with a synthetic diurnal curve anchored to the best peak value we have:

UVI(h) = UVI_max × max(0, cos((h / 7) × π/2))^1.5
         for h = −7 … +7 hours from the peak

Peak value, in order of preference:
  1. the observed daily maximum
  2. the city's stored value for this month (§5.5)
  3. a clear-sky noon estimate from latitude and month:
       δ         = 23.45° × sin(360° × (284 + day_of_year) / 365)
       elevation = 90° − |latitude − δ|
       UVI       = 12 × sin(elevation)^2.5      (0 in polar night)

A curve produced this way is a shape, not a forecast: it carries no ozone, cloud or aerosol information. Labelling such charts as modelled in the interface itself — rather than only here — is an open item in §7.

6. Rounding, placeholders and what a zero means

  • Precision. Provider values are displayed as supplied; our own derived figures are rounded to two decimal places. WHO recommends whole numbers for public UV reporting, and extra decimals should not be read as demonstrated accuracy — the display precision on this site currently exceeds its accuracy. Reducing public-facing precision while keeping full precision in the API is an open item in §7.
  • Coordinate precision. Cache keys round latitude and longitude to three decimals (≈110 m at the equator). Two nearby points can therefore share one reading — which is appropriate for a city-scale product and wrong for a site-specific one.
  • A zero is ambiguous. uv = 0 is a genuine night-time value and the placeholder used when no data could be obtained. The distinguishing signal is the timestamp: a real reading has uv_time; a placeholder has null. Surfacing that difference visibly is an open item in §7.
  • Stale data is not flagged yet. A value served from the 7-day fallback looks like a fresh one on the page. Until a staleness indicator ships, use the API's timestamps to judge freshness.

7. Limitations and open items

Published honestly, in preference to an unsupported accuracy badge. We do not claim a percentage accuracy anywhere on this site, because we have not yet measured one (§8).

Structural limitations

  • Single provider, no independent cross-check, no ground truth.
  • Modelled values only; no instrument of our own, anywhere.
  • One coordinate per city; no elevation parameter is sent, and elevation raises real UV.
  • Per-reading sky treatment (clear-sky vs cloud-aware) is not documented or labelled.
  • No forecast issue time available from the provider.
  • All timestamps in UTC rather than city-local time.
  • Monthly history is one modelled day per month, over the last 12 months only.

Open items, in priority order

  1. Establish and label the sky treatment of every displayed value.
  2. Replace burn-time countdowns with a sun-protection window (UVI ≥ 3).
  3. Replace fixed vitamin-D durations with an explanation of the uncertainty, medically reviewed.
  4. Restore published reflectance ranges and reframe the reflection table as education.
  5. Label the history statistic precisely, with coverage and completeness.
  6. Whole-number display for public pages; full precision in the API and downloads.
  7. Visible staleness and placeholder indicators; a modelled-curve badge on fallback charts.
  8. Local-time display per city.
  9. Validation against ground-station observations (§8).

Found something wrong on this page or on a city page? Email [email protected] — corrections are recorded in the change log below.

8. Accuracy and validation — status

Status: not yet performed. No validation figures are published on this site, and no accuracy claim should be inferred from its absence.

When we do publish them, the protocol is fixed in advance so the result is auditable:

  • Reference data — measured UV from ground stations (ARPANSA's developer feeds and WOUDC archives), not another consumer weather app.
  • Disclosure — tested locations, dates, number of matched samples, forecast lead times and the matching rules.
  • Metrics — mean absolute error, root mean square error and mean bias, reported separately for daylight hours so that a mass of night-time zeros cannot flatter the headline number.
  • Like for like — same averaging interval, comparable location and elevation, compatible cloud treatment. A clear-sky estimate will not be scored as a cloudy-day forecast.

9. Standards and authority references

What each reference actually supports. These organisations are not data providers for this site (see §3), and listing them here implies no endorsement of uvindex.io.

ReferenceWhat it supports here
WHO / WMO / UNEP / ICNIRP — Global Solar UV Index: A Practical Guide The standard definition, the 0–11+ reporting scale, the risk categories, cloud labelling and public-communication principles. This is the document the scale on this site follows.
ISO/CIE 17166:2019 — Erythema reference action spectrum and standard erythema dose The normative erythema action spectrum s(λ) and the standard erythema dose (SED) terminology used in §1.
NOAA Global Monitoring Laboratory — CIE erythemal action-spectrum data Numerical weighting values and the piecewise parameterisation, useful for checking an implementation wavelength by wavelength.
Hong Kong Observatory — Measurement of Ultraviolet (UV) Index A clear worked explanation of the integral, the factor of 40, and how broadband instruments actually measure the erythemal irradiance.
US EPA — Learn About the UV Index How operational UV forecasts are produced: solar angle, total-column ozone, clouds, elevation and surface reflectivity.
WHO — Radiation: The ultraviolet (UV) index (Q&A) and UV radiation fact sheet The UV 3+ sun-protection threshold and general public-health guidance used in our advice copy.
NIH Office of Dietary Supplements — Vitamin D fact sheet (health professional) Why sunlight duration cannot be reliably prescribed for vitamin D synthesis — the basis for the caveats in §5.4.
American Academy of Dermatology — Vitamin D and UV exposure position Dermatology guidance against seeking vitamin D through deliberate UV exposure.
ARPANSA — Ultraviolet radiation data for developers Timestamped measured UV from Australian ground stations — our intended reference for the validation work in §8.
WOUDC — World Ozone and Ultraviolet Radiation Data Centre Archived broadband, multiband and spectral UV observations (WMO/Environment Canada), for historical comparison.
Copernicus Atmosphere Monitoring Service — ozone layer and UV radiation Modelled UV products that distinguish clear-sky from cloud-aware fields — background for §7 and a candidate second source.

Accessed 11 September 2026. Before redistributing third-party data through our downloads or API we check that provider's own attribution and redistribution terms — a citation is not a substitute for permission.

10. Citing this page

UVIndex.io. (2026). Methodology: how uvindex.io
produces every UV number (Method version 1.0).
Retrieved from https://uvindex.io/methodology

When citing a value rather than this page, quote the provider's timestamp with it, and attribute the underlying data as "OpenUV data, analysis by uvindex.io".

Change log

VersionDateChange
1.0 First published methodology: definition, provenance chain, cache and timestamp rules, derived formulas, limitations, validation protocol and references.

The method version is bumped whenever the way a displayed number is produced changes — provider, endpoint, cache lifetime, aggregation or a derived formula.

Where to go next