OpenCMA

Changelog

Current version: v0.8.0

v0.8.0

Latest

Added

  • Public API. A free, no-signup API for property and nightlife data. No API key or login — call it straight from a browser or script. Two endpoints: GET /api/v1/property?address=… returns a property summary (parcel, assessed & market value, local tax rates, location/environment/value scores, FEMA flood, neighborhood demographics, and a nightlife snapshot), and GET /api/v1/nightlife?lat=&lng= (or ?address=) returns NightlifeFit scores and the nearest nightlife district. Generous rate limit of 60 requests/minute.
  • Developer docs at /docs. One page covering both endpoints with copy-paste curl and fetch examples, response fields, and how to build map share links. Linked from the header as "API".
  • /llms.txt — a machine-readable summary of the API so AI assistants can use it directly.
  • Named pins in map share links. /map share URLs can now carry a label per pin (e.g. an address or price tag), so a link can open the map with your custom set of properties already pinned and named.

Added

  • NightlifeFit now credits the workday crowd. Downtown blocks and commercial corridors where lots of young people *work* (but few live) score in the right range — previously these areas read as "no peer fit" because the score only saw residents.

Changed

  • Heatmap methodology card updated to describe the score in plain language.

v0.7.8

Added

  • GO / STAY / PEER breakdown bars on the expanded pin panel — see which sub-score is high or low instead of just the composite NightlifeFit number.
  • Freeways and rivers count as walking barriers. A bar across the highway from your block no longer pumps that block's NightlifeFit score — the path isn't actually walkable.
  • Seattle (King + Snohomish) added as the fourth heatmap city. 13 named centers including Capitol Hill, Belltown, Ballard, Fremont, and University District.

v0.7.7

Added

  • Tour mode (T): with 2+ pins dropped, press T to fly through them one at a time with a progress indicator. Esc stops.
  • Share-link button in the bottom-right corner copies a URL with the active city, all pins, and the current viewport. Recipients land on exactly the same view.
  • Fit-pins button recenters the viewport on the bounding box of all dropped pins.
  • Sales sparkline on the pin panel — a small inline chart of the property's qualified sale prices over time when the parcel has ≥2 of them. Endpoint dot is green when the most recent sale beat the first, red when lower, gold flat.
  • Drag-to-reorder pins in the side panel — useful for arranging tour-mode order.

Fixed

  • Pins dropped via search now land on the actual lot. The pin used to land on the road or in the front yard (sometimes ~20m off); it now snaps onto the parcel as soon as the property data resolves.

v0.7.6

Added

  • Hover-link between markers and side-panel rows. Hover a marker and its matching row highlights; hover a row and the marker grows.
  • Map viewport persists per-city across reloads. Zoom in on a block, refresh, you're still there. Switching cities still fits the new bounds.
  • Drop-and-bounce animation when a pin is freshly dropped or restored via undo. Reload-restored pins skip the animation so a saved set doesn't all bounce at once.
  • Browser tab title now includes the active city — "Map · Greater Seattle, WA — OpenCMA" — so multiple /map tabs are distinguishable from the tab strip.

Removed

  • 1-4 age-band keybinds — the buttons in the layers panel are clear enough; the keybinds were never that useful.

v0.7.5

Added

  • ⌘Z / Ctrl+Z undoes pin removal, with a 5-second toast and an Undo button. Covers single-pin removals and clear-all alike.
  • ? opens a keyboard-shortcuts overlay listing every binding. A faint "?" pill in the bottom-right makes it discoverable.

Fixed

  • Click-on-map could pick the wrong parcel. A click within ~10m of a lot boundary used to return a neighbor about as often as the actual parcel. The pin now reliably lands on the lot it sits inside.
  • Typed-address search resolved to the wrong parcel when the address was close to a neighbor's lot. Search now prefers the parcel that matches the typed address text over whichever parcel sits under the interpolated coordinates.
  • Pin card title and the full-report page now show the same address — character-for-character match. Previously the pin showed an approximate label while /property/lookup showed the parcel's recorded address.

v0.7.4

Added

  • Named nightlife clusters on the heatmap. High-score regions get a label — Tremont, Mission District, Hayes Valley, Capitol Hill, etc. Click any name to fly to that center.
  • Centers list in the layers panel — every named cluster with a quick fly-to.
  • Component view selector: paint GO-only, STAY-only, or PEER-only on the heatmap instead of the composite, to see what's driving (or missing from) the score.
  • Hover preview pill under the cursor shows the cell's NightlifeFit score and median home value.
  • Parcel-polygon highlight for the expanded pin at zoom 15+ — see the actual lot outline.
  • Shareable map URLs — pins survive in the URL so you can send a friend a link with your exact pin set.
  • Opening the full report from a pin paints instantly with the property data already loaded in the pin panel.
  • Map search biased toward the active city — searching for "Main St" in Cleveland no longer surfaces a New York match first.

Changed

  • Bay Area is the default city on /map.
  • Heatmap overlays start off — you opt in to nightlife or home-value coloring.
  • Layers panel collapses and the panel scrolls when its contents overflow.
  • Heatmaps fade out as you zoom in so streets and parcel polygons stay legible.
  • Esc collapses the expanded pin.
  • Refresh button on cached pin entries when the data might be stale.
  • Age-band toggles are instant — switching bands repaints the heatmap with no reload.

v0.7.3

Added

  • /map page: full-screen interactive map with floating controls. Bay Area, Cleveland, and Columbus heatmaps.
  • Pin system on /map: drop pins by clicking, persist across reloads, share via URL. Each pin's panel includes building info, sales, tax, Walk Score, flood data, and demographics.
  • Age-range selector on the heatmap: 18-24, 20-34, 25-39, 30-44 — each band shows the score weighted for that cohort.
  • Home Values overlay: a tract-level choropleth of median home prices plus a price-histogram legend.
  • Cross-city pins: prior pins keep their original score when you switch cities, so a Cleveland pin doesn't silently re-score against the Bay Area map.

Changed

  • Better address autocomplete in the search bar.
  • Pin address split into a street line and a city/state line for cleaner two-line rendering.
  • Map controls brought into the same softened design system as the rest of the site.

Fixed

  • California condo unit-switching no longer silently resurrects the original unit when the chosen unit can't be found.

v0.7.2

Changed

  • NightlifeFit scoring methodology rebuilt on a research-anchored model. The new score reflects how nightlife actually works: a location needs supply, late-hours options, *and* a peer cohort to score well — high values in one dimension can't fully compensate for a weak one. The full methodology lives in docs/plans/nightlife-scoring-v2.md.

v0.7.1

Added

  • NightlifeFit scoring on the property report: a 0–100 score for "how much of a night out is near this address," with a small inline heatmap.
  • Age-range selector: 18-24 / 20-34 / 25-39 / 30-44. Each band weights the score for that cohort.
  • Demographics age × gender pyramid on the property report.

Changed

  • Tighter NightlifeFit threshold for the 18-24 band so the score reflects that cohort's smaller, more selective nightlife footprint.

v0.7.0

Added

  • Property Verdict: an at-a-glance summary card sits above the full report. Estimated value band with YoY change, top three strengths and risks as clickable chips that smooth-scroll and pulse-highlight the supporting card, plus separate "For owners" and "For renters" pull-quotes that surface different framing of the same context.
  • Streaming property data: /api/property?stream=1 returns an NDJSON stream. Each upstream source emits its own line as it settles, so the verdict renders within 1–2 s after the subject scrape and the rest of the cards fade in over the following seconds. Uses race-emit semantics so a slow source no longer holds up the others.
  • Santa Clara CMA via Prop 13 inference: SCC has no public sale-price feed; the scraper now scrapes the assessor’s per-parcel page in parallel for the closest 25 nearby parcels and uses each parcel’s net assessed value at its last transfer as a proxy. The CMA card shows a clear disclosure banner whenever values are inferred this way and the confidence is forced to "low".
  • Recently Viewed section on the home page (localStorage-backed, max 10 entries). Direct URL visits and shared links are saved automatically too.
  • Global keyboard shortcut: press / or Cmd/Ctrl-K anywhere to focus the address search.
  • StreamingSlot wrapper for always-rendered cards (Walk Score, Flood, Demographics, Amenities, Trails) — they show a soft skeleton while their chunk is in flight instead of flashing their own empty-state UI for several seconds.
  • Streaming progress pill in the verdict header — pulsing dot + "Loading · N loaded" while the stream is in flight; disappears at completion.
  • Faded skeleton stripes at the bottom of each column while streaming so users know more cards may still appear there.
  • Per-unit cache in the streaming hook (LRU, 24 entries) — switching back to a previously loaded unit paints instantly while a fresh stream runs in the background.
  • Geocoding progress hint: "Looking up address…" label on the loading skeleton when the request only carries an address.
  • Bay Area housing-policy overlays in the verdict: Priority Development Areas, Transit Priority Areas, High-Quality Transit Areas, Plan Bay Area Growth Geographies, Equity Priority Communities, and Priority Conservation Areas now drive verdict chips in plain English.

Changed

  • Removed letter-grade UI from the report: the overall A+/.../F grade and V·T·L·E·I sub-grade strip in the verdict were too subjective for a public report. The Neighborhood Radar still works off the underlying numeric scores.
  • PropertySummaryCard absorbed into the verdict header: no more duplicate address block. The verdict now shows a single "key facts" line under the address (property type, beds/baths, sqft, year built, lot size when notable). PropertyDetailsCard still owns the comprehensive assessed/market split + tax abatement.
  • Plain-English verdict chips: dropped SB 35 / AB 2097 / Alquist-Priolo / CalEnviroScreen jargon. The full regulatory mechanics still live in the Bay Area Context card legend.
  • Per-source 60 s timeout + 5 min master deadline on the streaming aggregator. Stuck upstreams surface as error chunks instead of hanging the slot forever.
  • EPA ECHO radius dropped from 3 mi → 1 mi and pagesize from 20 → 10. Urban-area responses were 19–21 MB which Next.js refused to cache (>2 MB) and which blocked the event loop on parse.

v0.6.0

Added

  • Bay Area housing-policy overlays (MTC / Caltrans Plan Bay Area 2050 Plus): every address in the 9-county Bay Area now shows Priority Development Area, Transit Priority Area, High-Quality Transit Area, Plan Bay Area Growth Geography (HRA / LR / TRA), Equity Priority Community, and Priority Conservation Area. Drives SB 9 / SB 35 / density-bonus / AB 2097 / AFFH eligibility.
  • scripts/test-ca.mjs: deterministic CA scraper test suite. Each case pins parcel ID, source module, owner pattern, and value/sqft ranges across SF / Santa Clara / San Mateo edge cases. Supports --county=, --tag=, --bail.
  • --ca mode in scripts/test-report.mjs with CA-aware sanity checks (no false-positive on 100% Prop 13 assessment ratio; skip "missing owner" for sources that don't expose owners).
  • Two design docs catalogue verified-live statewide CA sources: docs/plans/california-new-sources.md (Williamson Act, Important Farmland, Alquist-Priolo) and docs/plans/mountain-view-sources.md.

Fixed

  • SF address search returned the wrong parcel: searchByAddress was stripping the house number and matching only by street name (LIKE '%MARKET%'), so "1390 Market St" returned "765 Market St" and "650 California St" returned "680 California Ave". Now pads the house number to 4 digits and requires it before the street name in property_location, with an OR branch for range-end addresses (a 636–650 parcel matches either query).

v0.5.0

Added

  • Condo / multi-unit disambiguation: when multiple parcels share the same address (stacked condos, apartments), the system now detects sibling units and shows a unit selector pill bar on the property report page. Clicking a different unit instantly switches the report via searchByParcel.
  • Home page interactive map: click anywhere on the map to drop a pin, reverse-geocode the location, and jump to a property report. Lazy-loaded with MapLibre GL.
  • SF scraper: actual sale dates: the San Francisco scraper now uses the current_sales_date field from the Socrata assessor roll (2.1M records) instead of relying solely on Prop 13 reassessment inference.
  • Coverage page: interactive MapLibre maps showing Ohio and California counties color-coded by data tier, with click/hover popups and summary stats.
  • Nearby Trails overlay: OSM-sourced hiking, cycling, walking, and multi-use trails within ~2 miles, rendered as colored dashed lines on the map.
  • Changelog page at /changelog displaying version history.
  • Version display in the site footer.
  • Konami code easter egg on the home page.

Changed

  • Improved pickBestAddressMatch to compare unit numbers when multiple parcels share the same house number.
  • NearbyTrails legend now matches the order trails are listed (sorted by count).

Fixed

  • Home page map click now passes countyFips, tractCode, and stateFips to the property lookup page (was causing "failed to load data" errors).

v0.4.0

Added

  • Monterey County scraper with assessed values and rich planning data.
  • San Joaquin County scraper.
  • Esri county boundary service for coverage map GeoJSON.
  • OGRIP spatial query retry logic and wider buffer for reliability.

Fixed

  • OGRIP spatial queries now use JSON geometry format with spatialReference (comma-separated format was returning 400 errors).
  • Long float coordinates rounded to 6 decimal places to prevent OGRIP 400 errors.
  • Address search fallback in aggregator when spatial query returns empty.

v0.3.0

Added

  • Wood County (Bowling Green) scraper using bgohio.org address points + OGRIP parcels.
  • Ohio school district income tax lookup via spatial boundary + rate CSV.
  • 6 new CA county scrapers: Alameda, Marin, Nevada, San Mateo, Santa Cruz, Ventura.
  • Orange, Riverside, Contra Costa CA county scrapers.
  • Mobile-friendly responsive UI across all components.
  • IPv6/DNS fix for CA ArcGIS services (dns.setDefaultResultOrder('ipv4first')).
  • 12-second timeout on all CA ArcGIS queries.

Fixed

  • IPv6 TLS handshake failures on services5.arcgis.com (Alameda).
  • Sacramento and San Diego scrapers migrated to working endpoints.
  • Alameda scraper switched from LA County's data (wrong org) to county-hosted endpoint.
  • Invalid ArcGIS WHERE clauses in Ventura and Contra Costa scrapers.

v0.2.0

Added

  • California expansion: San Francisco, San Diego, LA, Sacramento, Sonoma, Humboldt, Santa Clara, Tahoe (Placer/El Dorado) county scrapers.
  • CA hazard zones: fault, liquefaction, landslide, fire (SRA + LRA), tsunami — replicating $60-100 NHD reports for free.
  • CalEnviroScreen 4.0: environmental burden scores per census tract.
  • CA sales tax rates via CDTFA API.
  • EnviroStor: CA Department of Toxic Substances Control cleanup sites.
  • CA fire history: historic wildfire perimeters 1878-2025.
  • USGS earthquake data (100km radius, 10yr history).
  • USFWS wetlands overlay.
  • EPA ECHO facilities and Superfund/NPL sites.
  • Ohio EPA: brownfields, spills, waste facilities.
  • Ohio DNR: karst geology, oil/gas wells, groundwater DRASTIC, dams, water wells.
  • Ohio sales disclosures and city building inspections.
  • CMA engine: comparable selection, dollar adjustments, value estimation, market stats.
  • Nivo charts: radar, scatter, bar, sunburst, heatmap, tax burden.
  • Map overlays: heatmap, isochrone, amenities, EPA sites (toggleable via Zustand store).
  • Report card scoring system.
  • About page with data sources and methodology.
  • CardLegend component for color-coded indicators.

Changed

  • Renamed project from "Ohio Property Intelligence" to OpenCMA.
  • Aggregator uses Promise.allSettled() for all parallel API calls.
  • Nearby sales run concurrently with property scrape (halved timeout wait).

v0.1.0

Added

  • Initial release with 6 Ohio county scrapers: Cuyahoga, Franklin, Hamilton, Summit, Lucas, Montgomery.
  • OGRIP statewide parcel fallback for all 88 Ohio counties.
  • Census Bureau geocoder integration.
  • FEMA flood zone lookup.
  • Walk Score integration.
  • Census ACS demographics.
  • OpenStreetMap nearby amenities.
  • OpenRouteService isochrones.
  • Municipal income tax lookup.
  • Property report page with map, details, tax history, sales history.
  • Address search with autocomplete suggestions.