Community. Driven. Weather. Data. | Always Ad-Free | Developer FriendlyChecking statusDiscord
Become a supporter
Sign in
API

Low visibility

Fog, marine fog and smoke as polygons by visibility category, every 15 minutes, with a confidence, a cause and the sources behind each area. Plus everything known at a single point.


Base URL: https://api.wxalerts.org

Where visibility is down right now, and why: fog, marine fog and smoke, as polygons by category, refreshed every 15 minutes. Each area says how sure the product is and what it is based on. No polygon means normal visibility.

GET /v1/visibility?bbox=-123.2,37.4,-121.8,38.2
GET /v1/visibility?bbox=-123.2,37.4,-121.8,38.2&min_category=3
GET /v1/visibility/point?lat=37.62&lon=-122.38
GET /v1/visibility/point?q=mobile+al

Needs an API key (weather:read). Both endpoints are served only under /v1; the unprefixed paths answer 401. Browsers block calls from other websites (CORS allows only wxalerts.org), so call it from a server, script or app. Both send Cache-Control: private, max-age=120; a new analysis lands every 15 minutes, so polling faster than that learns nothing. The key’s rate limit applies.

WxAlerts sets no thresholds

This product describes; it does not decide. It never says “dangerous”, never issues an alert, and never hides a category as too minor to show. Every area carries its category, confidence, cause and sources, and what is worth drawing or alerting on is your call. A traffic app might alert only on very_low and worse at medium confidence or higher; a marine app might care about any marine_fog. Filter on the fields.

Categories

Prevailing visibility, from aviation and NWS practice.

category category_name visibility
1 reduced 3 to 5 mi (4828 to 8047 m)
2 low 1 to 3 mi (1609 to 4828 m)
3 very_low 1/4 to 1 mi (402 to 1609 m)
4 near_zero under 1/4 mi (under 402 m)
0 normal 5 mi or more. Never a polygon; used only by /visibility/point

Each lower edge is inclusive: 1609 m is low, 1608 m is very_low, 8047 m is normal.

Where it comes from

Four independent sources, fused on a 2.5 km grid:

source what it adds
analysis NOAA’s RTMA Rapid Update visibility analysis, every 15 minutes, the base layer everywhere
station airport (METAR) and buoy (NDBC) visibility, which pulls the analysis toward the measurement within 15 km
advisory NWS Dense Fog, Marine Dense Fog, Freezing Fog and Dense Smoke Advisories. Inside one, the category is at least very_low and the cause is the advisory’s
reports clusters of anonymized driver reports from partner apps. No single driver is trusted: ten or more independent reporters within 2 km and 30 minutes create an area, marked reported: true. Individual reports are never served by this API

sources on each area lists the ones that agree with it.

Confidence follows from how many independent sources agree: one is low, two medium, three or more high. A reported area is always high.

Cause is fog, marine_fog or smoke. Freezing fog is reported as fog.

Areas are grouped, not one per fog bank: each feature is every area sharing one category, confidence, set of sources and cause, as a single MultiPolygon. The same category can appear several times in one response with different confidence or sources.

GET /v1/visibility

The current areas that intersect a bounding box, clipped to it, as a GeoJSON FeatureCollection, least severe first so drawing in order puts the worst on top.

parameter
bbox required. west,south,east,north in degrees, west less than east and south less than north. At most 30 degrees a side
min_category 1 (default) to 4: only areas this bad or worse
{
  "type": "FeatureCollection",
  "server_time": "2026-11-09T19:12:04Z",
  "analysis_time": "2026-11-09T18:45:00Z",
  "published_at": "2026-11-09T19:08:21Z",
  "bbox": [-123.2, 37.4, -121.8, 38.2],
  "min_category": 1,
  "legend": [
    { "category": 1, "category_name": "reduced", "range_mi": "3 to 5 mi", "min_m": 4828.0, "max_m": 8047.0 },
    "..."
  ],
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "MultiPolygon", "coordinates": ["..."] },
      "properties": {
        "category": 4,
        "category_name": "near_zero",
        "cause": "marine_fog",
        "confidence": "high",
        "sources": ["analysis", "station", "advisory"],
        "reported": false,
        "vis_m_min": 180.0,
        "analysis_time": "2026-11-09T18:45:00Z"
      }
    },
    "..."
  ]
}

vis_m_min is the lowest analysed visibility inside the area, in metres. It can sit above the category’s range: where an advisory set the category (at least very_low), the analysis underneath may still read several miles. legend repeats the category table with its edges in metres (min_m inclusive, max_m exclusive, null for no floor). Coordinates are to 5 decimal places, about a metre. An empty features list is a clear analysis. A bbox that is missing, malformed or too large is a 422. Before the first analysis has been published the endpoint answers 503; retry.

GET /v1/visibility/point

Everything known at one place: the analysis, the nearest measurement, any advisory, and the model’s next six hours.

parameter
lat, lon the point. Or q (a place name) or location_id, as on /forecast. None of them is a 422; a name or id that matches nothing is a 404
{
  "server_time": "2026-11-09T19:12:05Z",
  "location": { "name": null, "display_name": null, "state": null, "lat": 37.62, "lon": -122.38 },
  "analysis_time": "2026-11-09T18:45:00Z",
  "published_at": "2026-11-09T19:08:21Z",
  "message": null,
  "current": {
    "category": 3, "category_name": "very_low", "cause": "fog", "confidence": "medium",
    "sources": ["analysis", "station"], "reported": false, "vis_m_min": 424.0
  },
  "station": {
    "station_id": "metar:KSFO", "source": "metar", "distance_km": 1.3,
    "visibility_m": 1207.0, "observed_at": "2026-11-09T18:56:00Z"
  },
  "advisories": [],
  "outlook": {
    "model": "hrrr", "cycle": "2026-11-09T18:00:00Z", "cell_id": 267091, "resolution_km": 6.0,
    "hours": [
      { "valid_time": "2026-11-09T19:00:00Z", "visibility_m": 13500.0, "category": 0, "category_name": "normal" },
      { "valid_time": "2026-11-09T20:00:00Z", "visibility_m": 17200.0, "category": 0, "category_name": "normal" },
      "..."
    ]
  },
  "legend": ["..."]
}
  • current is the worst area covering the point: the highest category, then the highest confidence, then a reported area. Outside every area it is category 0, normal, with cause, confidence and vis_m_min null and sources empty. Before the first analysis it is null and message says so; the other blocks still answer.
  • location is named only when you asked by q or location_id.
  • station is the nearest airport (source: metar) or buoy (ndbc) within 25 km that reported a visibility in the last 90 minutes, or null. station_id carries the source as a prefix (metar:KSFO, ndbc:PTOA1). A station can disagree with current: it is a single measurement at one spot, and the area is the fused picture.
  • advisories are the NWS fog and smoke advisories in force at the point, soonest to expire first: event (for example Dense Fog Advisory), phenomena (FG dense fog, MF marine dense fog, ZF freezing fog, SM dense smoke), the issuing office, expires and ends. Empty when none.
  • outlook is HRRR surface visibility for the next six hours, from the hour in progress, each mapped to the same categories. It is the lowest value in a 6 km block, so it leans pessimistic. null outside the HRRR grid (the contiguous United States and its surroundings).

May we use Microsoft Clarity to see how pages are used (clicks, scrolling and replays of a visit, with anything you type hidden), plus a random ID linking that to crash reports? Only to find bugs and confusing screens. Never advertising, never sold.