How the Dauphin County 911 dashboard works
Nothing here is reported, investigated, or interpreted. One county web page is fetched on a timer and redrawn in a form that works on a phone. This page explains that process in enough detail for you to decide how much weight it deserves.
One page, read on a four-minute timer
The whole dashboard rests on the WebCAD status page the Dauphin County Department of Public Safety publishes at dpswebcad.dauphincounty.gov, which anyone can open without a login. A function running at the edge requests that page, reads the tables out of its HTML, and returns the rows as JSON. Your browser then draws the JSON.
That is the entire pipeline. There is no database behind it, no archive, no editorial pass, and no second provider to reconcile against. A call missing from the dashboard was missing from the county page when it was last read, and a call that looks wrong here looks the same way there.
The read repeats every four minutes, and the header counts down to the next one so you can see how old what you are looking at is. Refresh forces the read early.
Dauphin publishes categories as headings, not as a column
This is the part worth understanding, because it shapes everything downstream. Some counties publish a single table with a category column. Dauphin instead breaks its page into several tables, each introduced by its own heading — fire, medical, traffic, controlled burns, road closures, out-of-service hydrants — and lists the relevant rows underneath.
The parser therefore walks headings before it walks rows. When a heading names a kind of call, every row beneath it is stamped with that heading as its category, with the wording trimmed down for display. When a heading names road closures or out-of-service hydrants, the rows beneath it are routed to the Advisories section instead of the incident list. Column positions are resolved per table from that table’s own header cells, rather than assumed, so a reordered column does not silently shift data into the wrong field.
Two consequences follow. Categories on this site are as good as the county’s own grouping, since they are that grouping. And a table the parser does not recognise is skipped rather than guessed at, so new sections the county adds will not appear here until the parser learns about them.
What each field on a card is
The feed is narrow, and it is easier to trust once you know exactly how narrow. These are the only values a card can show:
- Category
- Taken from the heading of the table the call was listed under, not from a column. A call sitting beneath the fire heading is categorised as fire because the county grouped it that way.
- Event type
- The county’s own wording for the call. Where a row carries an event sub type as well, the sub type is shown because it is the more specific of the two; otherwise the event type is shown on its own.
- Street
- The road the call is on, as published. It is a road name, not a mailing address — the feed carries no house numbers and none are inferred.
- Cross streets
- The intersecting road, when the county fills that column in. Frequently blank, in which case the card simply omits the line.
- Municipality
- The borough, township, or city the call falls in. This is the narrowest location the feed publishes and the only one the map can work from.
- Date/time
- When the call entered the county system. It arrives with no timezone attached, is treated as Eastern, and is shown both as a clock time and as an elapsed-time figure that counts up while the call stays open.
Not listed, because Dauphin does not publish them: responding units and stations, incident numbers, box or run-card areas, call status, and anything about the people involved. Those are absent from the source, so they are absent here.
Five filters, and how a heading reaches one
County headings are matched, in order, against a keyword list to give the filters and colour coding something consistent to work with:
- Fire — any heading containing “FIRE”, “RESCUE”, “HAZMAT”, “BURN”.
- EMS — any heading containing “MEDICAL”, “EMS”, “AMBULANCE”.
- Traffic — any heading containing “TRAFFIC”, “ROAD”, “MVA”.
- Police — any heading containing “POLICE”, “LAW”.
- Other — anything none of the rules above claimed, including headings this site has not been taught to recognise.
The list is read straight from the code the classifier uses, so this description cannot drift away from the behaviour. Note that controlled burns match on BURN and are grouped with fire calls, which is intentional: they occupy the same responders’ attention. If a grouping looks wrong to you, it is the keyword list at fault rather than the county, and the county’s original wording is kept on the card and remains searchable so you can still find the call.
Closures and hydrants ride along with the calls
Because they are tables on the same page, road closures and out-of-service hydrants come free with every read, and they surface in an Advisories block that stays hidden while the county is reporting neither. They arrive as single lines of text rather than structured rows, so they are shown as the county wrote them. A hydrant listed out of service is a maintenance note, not an incident, and nothing on this site infers a fire risk from one.
Why the map colours municipalities instead of dropping pins
A road name and a municipality is all the location the feed carries. No coordinates, no house numbers, no block ranges. Given that, the map draws one circle per municipality, scaled to that municipality’s land area, and colours it by the dominant category of the calls inside it.
Pins were rejected for three separate reasons, any one of which would be enough:
- A road name is not a point. Routes in this county run for miles and cross several municipalities, so a marker would put a precise-looking dot somewhere the call probably is not.
- Medical calls happen where people live. The county withholds those addresses deliberately, and reconstructing one would amount to publishing the location of whoever dialled 911.
- The geocoding would be unsound anyway. Address-level lookup needs the house numbers the feed does not contain, and the free services that could be pointed at it forbid this pattern of use.
Municipality outlines are derived from US Census Bureau TIGERweb data, which is public domain. Matching uses the municipality type as well as the name, because Halifax and Lykens each name both a borough and a township — on the bare name alone, calls would land in the wrong place roughly half the time.
Coverage, counted from the data itself
40 municipalities are matched: 23 townships, 16 boroughs, and one city, Harrisburg, covering approximately 525 square miles. The largest by land area are Middle Paxton Township (~54 sq mi), East Hanover Township (~40 sq mi), Jackson Township (~40 sq mi); the smallest are Williamstown Borough (~0.3 sq mi), Royalton Borough (~0.3 sq mi), Halifax Borough (~0.3 sq mi).
Those figures are computed at build time from the same municipality file the map is drawn from, rather than written down, so they cannot end up contradicting what you see. Areas are approximate because each municipality is modelled as a circle of equivalent area rather than its true outline. A call whose municipality is not in the set — mutual aid across a county line, most often — cannot be placed on the map, so it is counted and disclosed underneath it.
Every time on this site is Eastern
The county writes its timestamps without a timezone. Handing those to a browser would have them read in the visitor’s own zone, which turns a call from twenty minutes ago into one from three hours in the future for a reader on the west coast. They are therefore resolved explicitly as America/New_York wall-clock time, and the offset is resolved twice so that calls either side of a daylight saving change still land correctly. A card reading 8:07 PM means 8:07 PM in Harrisburg.
What this dashboard cannot do
- No history. Only open calls appear. When one clears it leaves on the next read and cannot be recovered here.
- No unit information. The feed does not name responding companies or apparatus, so neither does this site.
- Not complete. Not every call reaches the public page, and encrypted radio traffic never does.
- Tied to someone else’s HTML. The parser depends on the structure of the county page. If that page is restyled, sections can drop out until the parser is updated.
- Unattended. No one is watching this dashboard, and nothing you do on it reaches a responder.
Who is behind it
An independent project run by one person, with no connection to Dauphin County government or the Dauphin County Department of Public Safety. It is not endorsed by them and does not speak for any fire company, ambulance service, or police department. The name simply describes the subject of the data.
Parsing bugs, corrections, and questions are read at [email protected]. The privacy policy covers analytics and advertising, and the terms of use cover what you may rely on.