The problem
Every campaign in the county can download the same voter export. Turning it into something a volunteer can carry down a street is the hard part, and it is usually solved by renting a commercial canvassing platform for the cycle.
This campaign wanted the targeting without the per-seat bill, and it needed to work in places where phones lose signal. The raw file makes that awkward: 137 columns, duplicated headers, and a vote history that records only the elections someone turned out for, with no marker for the ones they skipped.
What we built
The Secretary of State file arrives with 137 columns, repeated headers and vote history smeared across five columns per election type. The importer reads it by position rather than by name, then normalizes it into household, voter and vote-history tables, keeping the full original row as JSON so nothing is lost.
Voters are grouped into households, so a door is knocked once rather than once per registered voter. Routes run street by street, up the odd side and back down the even side, with unnumbered addresses last.
Each voter gets a 0–100 propensity score from the generals they actually voted in, weighted toward recent elections and adjusted for whether they were old enough to vote at the time. Volunteers filter by party, minimum score, or super-voters only.
The whole voter file lives on the phone in a local database. Canvassers record results at the door with no connection, and each result carries an identifier so it can sync later without duplicating.
The call that made the scores trustworthy
The obvious way to score turnout is to compare elections voted against elections since someone registered. On this file it would have been wrong. The registration date is a re-registration date, so anyone who moved or updated their record looks like a perfect voter who simply had fewer chances.
Scoring that way pushed 67% of the county into the top band. Scoring against each voter's actual eligibility, worked out from their age at each election, put 56% there instead. The second number is the believable one, and it is the difference between a list that sends volunteers to the right doors and one that flatters everybody.
This is the part of the work that does not show up in a feature list: knowing which field in a government export means what it appears to mean.
Where the voter data lived
The voter file stayed on the devices that needed it. It was never committed to the code repository, and the app does not need a connection to work, so a canvasser carries the data and nothing else does.
Door results are written locally with their own identifiers, so syncing them to a shared backend later cannot create duplicates.
The outcome
The campaign reports that its candidate won, and that it spent far less on voter-contact tooling than the opposing campaign did.
That result is the client's own account of their race, not a figure we measured. What we can show is the app: the import, the routing, the scoring, and the fact that it all ran offline in the field.
- A full county voter file, usable on a volunteer’s own phone
- Households grouped so nobody knocks the same door twice
- Turnout scoring the campaign could explain and defend
- No per-seat platform fee for the cycle
Have a data set nobody can use yet?
Exports, spreadsheets and legacy systems are usually one good model away from being the thing your team works from. Bring yours to a working session.