Wet Bulb Globe Temperature (WBGT) is the index sports medicine, military, and occupational health organisations actually use to evaluate heat stress risk — not heat index, not feels-like. The NCAA, OSHA, and the UK’s Health and Safety Executive all reference WBGT in their heat exposure guidelines. It accounts for radiant heat load and airspeed, not just air temperature and humidity. And it’s almost never in a weather API response.
You can build a decent approximation from what WeatherAPI does return. Not a perfect one — that requires a black globe thermometer in the actual environment. But for scheduling decisions, alert triggers, and outdoor exposure logic, a derived WBGT is far more defensible than using feelslike_c or raw humidity thresholds.
What WBGT Actually Is
WBGT combines three temperature components with fixed weights:
- Wet bulb temperature (Tw) — weighted at 0.7. This dominates the index and captures evaporative cooling capacity, which is what humidity actually affects.
- Globe temperature (Tg) — weighted at 0.2. Measures radiant heat from the sun and surrounding surfaces. A black globe thermometer absorbs radiation the way human skin roughly does.
- Dry bulb temperature (Ta) — weighted at 0.1. Ordinary air temperature.
So: WBGT = 0.7 * Tw + 0.2 * Tg + 0.1 * Ta
The outdoor version (as opposed to the indoor/shade version used in some industrial settings) includes the globe temperature. That’s the term that makes WBGT genuinely different from heat index — it bakes in direct solar load, which humidity-only indices don’t capture at all.
The Fields You Need from WeatherAPI
From the /forecast.json or /current.json response:
temp_c— dry bulb, straightforwardhumidity— relative humidity in percentwind_kph— needed for globe temperature estimationuv— UV index, used as a proxy for solar irradiance when direct irradiance isn’t availableis_day— determines whether the radiant load term applies at all
If you’re on a plan that includes solarradiation_wm2 in the hourly forecast object, use that directly instead of the UV proxy — it’s more precise. If not, the UV index is a workable stand-in. The relationship between UV index and total shortwave irradiance isn’t fixed, so treat any conversion as an approximation, not a real unit conversion.
Step 1: Derive Wet Bulb Temperature
There’s no wetbulb_c field. You derive it. The Stull (2011) formula is computationally cheap and accurate enough for ambient conditions between roughly -20°C and 50°C at relative humidities above 5%:
Tw = Ta * atan(0.151977 * (RH + 8.313659)^0.5)
+ atan(Ta + RH)
- atan(RH - 1.676331)
+ 0.00391838 * RH^1.5 * atan(0.023101 * RH)
- 4.686035
Where Ta is dry bulb temperature in °C and RH is relative humidity as a percentage (0–100).
In Python:
import math
def wet_bulb_stull(temp_c, rh):
return (
temp_c * math.atan(0.151977 * (rh + 8.313659) ** 0.5)
+ math.atan(temp_c + rh)
- math.atan(rh - 1.676331)
+ 0.00391838 * rh ** 1.5 * math.atan(0.023101 * rh)
- 4.686035
)
Stull’s formula has documented error of roughly ±0.35°C across most of the parameter space you’ll actually hit. That’s acceptable. Don’t use the simplified psychrometric approximation (Tw ≈ Ta - (1 - RH/100) * (Ta - Tdew)) — it’s faster to type but degrades noticeably below 30% RH, exactly the conditions where getting wet bulb right matters most.
Step 2: Estimate Globe Temperature
This is where the real approximation happens. A physical globe thermometer reads higher than ambient because it absorbs radiation and sheds heat more slowly as wind drops. Without actual radiometric measurements, you estimate globe temperature from air temperature, solar irradiance (or UV as a proxy), and wind speed.
A simplified form based on Hunter and Minyard’s approach:
def globe_temp(temp_c, solar_wm2, wind_kph):
wind_ms = wind_kph / 3.6
# Avoid divide-by-zero on calm days
wind_ms = max(wind_ms, 0.1)
tg = temp_c + 0.5 * (solar_wm2 / (wind_ms ** 0.4)) - 0.5
return tg
If you only have UV index rather than solarradiation_wm2, a rough conversion is solar_wm2 ≈ uv_index * 25 for midday conditions. At low sun angles this overestimates; at high sun angles it underestimates. Apply it only when is_day == 1 and treat the result as directionally correct, not metrically precise.
At night, globe temperature converges toward air temperature — solar load is zero and nocturnal radiative cooling from the globe is small enough to ignore in a simplified model. Set Tg = Ta when is_day == 0.
Step 3: Combine Into WBGT
def wbgt(temp_c, rh, solar_wm2, wind_kph, is_day):
tw = wet_bulb_stull(temp_c, rh)
tg = globe_temp(temp_c, solar_wm2, wind_kph) if is_day else temp_c
ta = temp_c
return round(0.7 * tw + 0.2 * tg + 0.1 * ta, 2)
Run this against WeatherAPI’s hourly forecast and you get a WBGT trace through the day — which is immediately more useful than a single daily feels-like peak for anything involving scheduled outdoor activity.
How to Map WBGT to Risk Levels
The commonly referenced thresholds — from ACSM, the US Army, and NIOSH — are roughly:
- Below 28°C WBGT: Low risk, normal activity generally safe
- 28–32°C: Moderate risk; rest breaks warranted for sustained exertion
- 32–35°C: High risk; limit heavy exertion, especially for unacclimatised individuals
- Above 35°C: Extreme; suspend outdoor exertion
These aren’t universal. Military thresholds differ from athletic ones, and acclimatisation status shifts the numbers meaningfully. But they’re defensible starting points for alert logic, grounded in published occupational health guidance rather than invented.
Pulling It Together with a WeatherAPI Request
import requests, math
API_KEY = "your_key"
LOCATION = "32.7767,-96.7970" # Dallas, TX
url = f"https://api.weatherapi.com/v1/forecast.json?key={API_KEY}&q={LOCATION}&hours=24&aqi=no"
resp = requests.get(url).json()
hours = resp["forecast"]["forecastday"][0]["hour"]
for h in hours:
ta = h["temp_c"]
rh = h["humidity"]
wind = h["wind_kph"]
is_day = h["is_day"]
uv = h.get("uv", 0)
solar_est = uv * 25 if is_day else 0
score = wbgt(ta, rh, solar_est, wind, is_day)
print(f"{h['time']} WBGT: {score}°C")
Dallas in July will regularly hit the 30–33°C WBGT range by early afternoon. That’s the moderate-to-high band, which most people scheduling outdoor events treat as business as usual. It shouldn’t be.
Where This Breaks Down
The globe temperature estimation is the weakest link. Real WBGT measurements use a 15cm hollow black copper sphere — under full sun with low wind, globe temperature can run 10–15°C above ambient. The simplified formula gets the direction right but will underestimate peak radiant load on hot, calm, cloudless days. If the use case is occupational safety with real stakes, treat this as a planning signal, not a substitute for on-site measurement.
wind_kph in the API is surface wind at the standard 10m measurement height, not at body height (roughly 1.2m). Wind speed at 1.2m is typically 60–75% of 10m wind over open terrain, less in urban settings. The practical effect is a slight underestimate of globe temperature on calm days near the surface — directionally biased toward optimism, which is the wrong direction for heat safety.
The model also ignores local albedo. Concrete and asphalt return significantly more shortwave radiation upward than grass does. A forecast pinned to a park coordinate won’t capture what’s happening on an artificial turf field or a rooftop nearby.
Why This Is Still Worth Building
Most apps handling heat risk are using feelslike_c or a raw humidity threshold. Both miss the point. The wet bulb term alone — weighted at 0.7 — already outperforms those approaches because it directly captures evaporative cooling capacity. The globe term is what separates shade from direct sun exposure, which is the actual decision most users are trying to make.
For construction site scheduling, youth sports leagues, military training planners, or outdoor event ops, a derived WBGT is more defensible than raw temperature or a generic feels-like. You can also track it hourly and flag the specific window when conditions cross a threshold, not just label a whole day as “hot.”
One thing worth getting right in the UI: don’t present derived WBGT as equivalent to measured WBGT in safety-critical contexts. Label it “estimated heat stress index” or similar. It’s more honest, and it’s less likely to cause a problem if someone treats the number as ground truth when it isn’t.
