PermitParser
FILED &
NORMALIZED
New Haven County, CT

Find what's changing
in your neighborhood.

PermitParser scrapes, parses, and normalizes building permits and zoning filings from fractured municipal portals: PDFs, HTML tables, scanned agendas. All of it lands in one queryable, spatial record. Built to survive fifteen towns' worth of inconsistent government web software. Eight live, eight parser conventions (three of them OCR), one record shape.

LIVE FROM /api/v1 -
-
municipalities
-
records parsed
-
documents ingested
Loading recent filings…
Architecture

Four stages, and every source comes out the same shape

A PDF agenda and a JavaScript permit portal fail differently, so the pipeline is built to expect that: a schema-drift landing zone, a content-hash ledger, and a normalization boundary between messy source text and a queryable record.

01. fetch_latest

Discover

Polls a town's listing surface (a table, an agenda index) for documents published since the last run. Never downloads a full body just to check if it's new.

02. download_raw

Dedupe

SHA-256 of the raw bytes before anything touches disk. The same PDF fetched twice, whether from a re-run or an unchanged listing, costs one indexed lookup and never a duplicate row.

03. parse

Normalize

pdfplumber for a real text layer, PyMuPDF + Tesseract OCR when there isn't one. Pure functions with no I/O, validated into a strict Pydantic PermitRecord.

04. upsert

Serve

PostGIS-indexed, queryable by category, valuation, date range, or radius. A rescrape updates a record in place, never a duplicate for the same real-world filing.

Coverage

Live in eight towns

Every town in South Central Connecticut runs its own GIS, its own permit vendor, its own PDF export format. Each one gets checked and built before it's marked live. There are no placeholder rows.

Live

Branford

Planning & Zoning Commission agendas, CivicPlus AgendaCenter. PDF, statically scrapable.

Live

Madison

Planning & Zoning Commission agendas, same platform as Branford, different agenda layout. Added September 2026.

Live

Milford

Planning & Zoning Board agendas and Actions Taken sheets, attached behind the AgendaCenter packet index. Petitions carry no case number, so the town's own Map-Block-Parcel is the record key. Added September 2026.

Live

North Branford

Planning & Zoning Commission agendas and minutes. Applications are numbered on the agenda; the decision is the motion recorded in the minutes. Added September 2026.

Live

Orange

Town Plan & Zoning Commission agendas, scanned with no text layer, read by OCR. Items name the applicant and the property; the address is the record key. Added September 2026.

Live

Woodbridge

Town Plan and Zoning Commission agendas, also scanned and read by OCR. "Applicant: address" then the request; no case number, so the address is the key. Added September 2026.

Live

Middletown

Planning & Zoning Commission agendas and minutes. Each item ends with the town's case number; the decision is the vote recorded under the item in the minutes. Added September 2026.

Live

West Haven

Planning and Zoning Commission agendas, scanned and read by OCR, and minutes. One application carries several file numbers; votes in the minutes are matched back by number. Added September 2026.

Researched, not built

Hamden

Same platform, permissive robots.txt, but the commission posts Word files and nothing newer than early 2025.

Researched, not built

New Haven

Portal vendor not yet confirmed against a live scraper.

Researched, not built

Wallingford

Portal vendor not yet confirmed against a live scraper.

API

A public read layer

Every figure on this page comes from the same public, unauthenticated API. Filter by municipality, category, valuation, date range, or a straight-line radius search. Each town also has an RSS and a JSON feed of its filings, newest meeting first.

GET /api/v1/permits?municipality=branford&category=zoning_variance
GET /api/v1/permits?lat=41.28&lng=-72.81&radius_miles=2
GET /api/v1/permits/analytics/velocity?municipality=branford
GET /api/v1/feeds/branford.rss (also .json, and all.rss)
// live response...
One town at a time

Built to survive fifteen towns' worth of inconsistent government software.

Every design decision, the raw/normalized split, the config-driven scrapers, the honest "not built yet" coverage table, exists to make the next town an addition, not a rewrite.