← Back to all posts

Real-Time DMS Sign Messages API: What's on the Highway Signs Right Now

April 30, 2026 · 6 min read
DMS Signs API

Dynamic Message Signs — the big electronic boards over the highway — are how a state DOT talks to drivers who are already on the road. Amber alerts, travel times, lane closures, weather warnings, evacuation routes — they all go up on a board, in the exact words the driver reads.

The catch: every state publishes its DMS inventory differently — from clean JSON APIs to multi-district web endpoints to obfuscated binary feeds. Some publish a clean “current message” field; others give you multiple message phases you have to reassemble into the line that’s actually displayed.

Road511 normalizes all of it into one endpoint. One API call returns the live text on every DMS across 45 jurisdictions — 12,668 active signs as of 14 August 2026.

What You Get

curl "https://api.road511.com/api/v1/features?type=signs&jurisdiction=GA&limit=10" \
  -H "X-API-Key: your_key"
{
  "data": [
    {
      "id": "GA-sign-GDOT--5467",
      "jurisdiction": "GA",
      "feature_type": "signs",
      "name": "GDOT-DMS-0204",
      "properties": {
        "message": "CRASH I-20 WB\nEXIT TO CANDLER RD\nLEFT LANE BLOCKED",
        "direction": "Southbound"
      }
    }
  ],
  "total": 212,
  "has_more": true
}

That is a real record, shape and all. Note the name: it is GDOT-DMS-0204, the agency’s own device identifier, not a friendly “I-85 NB at Clairmont Rd” string. Most DOTs publish the sign’s cabinet ID rather than a human-readable location, so if your UI needs to tell a driver where a sign is, plan to reverse-geocode the row’s latitude/longitude yourself — don’t plan on name.

The message field is the exact text on the sign, with the sign’s own line breaks preserved as newlines (\n). A dark or default sign comes back with an empty message or a source sentinel such as NO_MESSAGE. What else rides in properties varies by DOT, and less generously than you might hope: of the 12,668 active signs, 3,462 (27%) carry a direction and 4,164 (33%) a sign_type. Only message is effectively universal. Write your client so that every property except message may be absent.

One field that is not there, and that developers keep asking for: there is currently no per-sign “last changed” timestamp. No active sign in the inventory carries one today, because none of the upstream feeds we ingest stamps its own message-change time in a form we can pass through. The row’s last_updated tells you when we last read the feed, not when the operator last retyped the board. To know when a message actually changed, diff successive polls yourself.

Filter to the Signs That Are Saying Something

Combine type=signs with a bounding box to pull a metro area in one call:

curl "https://api.road511.com/api/v1/features?jurisdiction=GA\
&type=signs\
&bbox=-84.5,33.6,-84.2,33.9\
&limit=200" \
  -H "X-API-Key: your_key"

That box is metro Atlanta, and on 14 August 2026 it returned 70 signs — all 70 of them carrying text. Which is worth dwelling on, because the obvious first filter does nothing.

Dark boards are the exception, not the rule. Across the whole active inventory, 9,152 of 12,668 signs — 72% — are displaying non-empty text right now; only 3,407 are blank and a mere 109 return the NO_MESSAGE sentinel. So dropping empties and sentinels leaves you with roughly seven signs in ten, not a handful. If you have budgeted for “a tiny percentage,” re-budget.

The real filtering problem is a different one: most of that text is routine. Boards spend their lives showing travel times, posted speeds, and safety campaigns, and the incident messages hide among them. Here are four real Georgia boards from that same pull:

GDOT-DMS-0401  "I-285 SPEEDS:\nWEST\n64 MPH"
GDOT-DMS-0405  "TRAVEL TIME TO\nHAYNES BR: 3-5 MIN\nWINDWARD: 6-8 MIN"
GDOT-DMS-0204  "CRASH I-20 WB\nEXIT TO CANDLER RD\nLEFT LANE BLOCKED"
GDOT-DMS-0108  "ROADWORK 316 EB\nAT CEDARS CREEK\nRIGHT LN BLKD"

Two are wallpaper, two are events. No flag in the payload separates them — the DOT doesn’t publish one, so we don’t invent one. Classification is a keyword pass you write over message, and it is genuinely the interesting part of the integration: match on CRASH, CLOSED, BLOCKED, ACCIDENT, AMBER, SILVER, EVACUAT, and exclude the boards whose text is dominated by TRAVEL TIME, SPEEDS, and MPH. Build that list against your own corridors, and expect to keep tuning it — each DOT abbreviates differently, as RIGHT LN BLKD above should warn you.

GeoJSON for Map Overlays

Plan note. The GeoJSON endpoints need a paid plan (allow_geojson); on Free they answer 403 plan_geojson. The same query without /geojson returns the identical rows as JSON on every plan.

Same query, GeoJSON shape, ready to drop onto Leaflet, Mapbox, or QGIS:

curl "https://api.road511.com/api/v1/features/geojson?jurisdiction=GA\
&type=signs\
&bbox=-84.5,33.6,-84.2,33.9" \
  -H "X-API-Key: your_key"
const res = await fetch(
  'https://api.road511.com/api/v1/features/geojson'
  + '?jurisdiction=GA&type=signs&bbox=-84.5,33.6,-84.2,33.9',
  { headers: { 'X-API-Key': 'your_key' } }
);
const geojson = await res.json();

L.geoJSON(geojson, {
  filter: (f) => f.properties.message && f.properties.message !== 'NO_MESSAGE',
  pointToLayer: (f, latlng) => L.circleMarker(latlng, {
    radius: 7, color: '#f59e0b', fillOpacity: 0.85
  }),
  onEachFeature: (f, layer) => {
    const lines = (f.properties.message || '').split('\n').join('<br>');
    layer.bindPopup(`
      <strong>${f.properties.name}</strong>
      <pre style="font-family: monospace; font-size: 12px">${lines}</pre>
    `);
  }
}).addTo(map);

Why Aggregating This Matters

Is the sign faster than the 511 feed? This post used to say so, so we measured it. Over the 14 days to 27 September 2026 we took 27,700 moments at which a board started showing a crash or incident message and matched each one to the nearest 511 incident in the same jurisdiction. The median board message appeared about two minutes after the incident was already in the feed, and once chance matches are accounted for — we ran the same match against the signs shifted by 24 hours as a control — essentially none led the feed by more than ten minutes. Both timestamps are our own poll times, so the resolution is roughly ten minutes either way; what the data does not support is a sign that routinely beats the feed.

The value of sign text is not speed. It is what the board says, which no incident feed carries:

Coverage

DMS data lives in the signs feature type. We pull from every state and province that exposes a public sign feed — 45 jurisdictions, 12,668 active signs. The counts below are active records on 14 August 2026; hardware comes and goes, so read them as this month’s shape rather than a fixed number.

Jurisdiction Active signs Jurisdiction Active signs
Massachusetts (MA)2,192Maryland (MD)206
Texas (TX)1,290Maine (ME)155
Pennsylvania (PA)1,198British Columbia (BC)148
Florida (FL)1,137Oregon (OR)143
Michigan (MI)567Wisconsin (WI)141
New York (NY)486Iowa (IA)131
Virginia (VA)446Oklahoma (OK)115
Nevada (NV)405Wyoming (WY)102
North Carolina (NC)400Minnesota (MN)97
Missouri (MO)331North Dakota (ND)91
Illinois (IL)294Vermont (VT)91
California (CA)275Kentucky (KY)88
Indiana (IN)246New Hampshire (NH)82
Colorado (CO)245Montana (MT)80
Utah (UT)221Connecticut (CT)79
Arizona (AZ)221Tennessee (TN)72
Kansas (KS)214Louisiana (LA)67
Georgia (GA)21210 more jurisdictions11–56 each

The tail is long and worth knowing about: Nebraska, Alabama, Alberta, Ohio, Mississippi, South Carolina, Idaho, Delaware, Yukon and Alaska each publish between 11 and 56 boards. Alaska has 11. If your coverage requirement is “a sign on this specific corridor,” check the corridor rather than the state — a jurisdiction being in the list does not mean it is instrumented everywhere.

If a state publishes DMS data, we ingest it. New states roll in regularly — we’ve done the per-source unification work so you don’t have to.

Who Uses This

One Note on Polling and Freshness — Read This Before You Build an Alerting Product

Be realistic about latency, because this is the number people most often assume in our favour. As of 14 August 2026, of the 49 enabled sign feeds:

So the honest end-to-end figure is: a message you read may be up to ten minutes old on most states, plus whatever cache your own client adds. Polling faster on your side buys you nothing — you will re-read the same value we last fetched. If you need sub-minute DMS latency for a specific corridor, the poll interval is a per-source setting and we can raise it for a state on request; ask rather than assume.

It also means DMS text is not a faster incident feed: as measured above, the 511 feed usually has the incident first. You should not promise anyone “within seconds of the operator posting it,” and an AMBER-alert pipeline built on DMS should treat it as one signal among several rather than the fastest one available.

Try It

See what every highway sign is saying right now

One API call returns the live message on 12,668 DMS boards across 45 states and provinces. Free 14-day trial. No credit card.

Get Free API Key Explore the Map