CityScroll brings New York City's scattered public-data systems into one place — so you can follow a procurement from solicitation through award to payment, see one vendor across every agency they work with, and get an email the morning something you care about appears. No single city website connects these threads. CityScroll does.
- Use it: cityscroll.org
- Changelog: cityscroll.org/changelog.html
- System Stats: cityscroll.org/stats.html
Follow a contract end to end — across systems that don't link to each other.
A single notice page joins the City Record announcement, the Checkbook NYC registration and payment record, the PASSPort solicitation detail, and the OCP award corroboration — on one timeline, with every source named.
See one vendor across every agency and every year.
A vendor profile resolves name variants (punctuation, casing, legal suffixes), totals every award on record, lists the agencies they win from, and links to every notice that names them.
Search procurement notices and get daily alerts.
Browse open RFPs, recent awards, and closing-soon solicitations in one filterable view, or describe what you want in plain English ("construction contracts over $500k"). Get a morning email digest when new matches appear.
See the data honestly — with its quirks explained.
The Data page computes live totals from NYC Open Data: how many notices by section, the procurement mix, top agencies and vendors. It also explains the data-entry errors it corrects for (phantom $96 trillion awards, fake 2099 deadlines, 312 raw agency-name strings for ~150 real agencies).
Follow contracts from RFP → Intent to Award → Award → Registration → Payments. Each stage names its source and links back to it. Solicitation pages include bidding deadlines, PASSPort detail, agency contacts, and document links. Export any view as CSV or Excel.
Every vendor and agency has a deep-linkable profile page. Vendor pages resolve name variants, total awards across all agencies, and list every notice that names them. Agency pages show their procurement history and award patterns.
Historical Checkbook NYC contract terms are used to estimate expiration and renewal timing, displayed as a timeline on profiles, with six-month early-warning alerts. These are labeled estimates, not active solicitations.
A plain-language guide to how civil-service hiring works, with open and upcoming exams in one filterable list. Fees, minimum salaries, and pay-schedule history are shown when DCAS has published them, with a direct link to the official application step.
Rezonings and land-use actions in plain English, linked to the official City Planning ZAP registry and tax-lot (MapPLUTO) boundary polygons. Project detail pages show decision documents, action approvals, and disposition votes beyond the status chips on the portal.
Municipal asset auctions (real estate, equipment, timber) and building demolition filing statuses.
This week's public hearings by affected borough or neighborhood, with the hearing venue kept separate from the place a decision concerns. Regulatory changes and public comment windows, enriched with official comment/adoption links and deadlines from the NYC Rules feed.
- Plain-English search: Type what you're looking for — "shelter services contracts," " rezonings in Brooklyn," "education contracts over $200K" — and CityScroll translates it into the right filters.
- Email digests: Describe a watch in plain English, confirm via double opt-in, and receive a morning email when new matches appear. Delivers in your chosen language.
- Subscribe by email: Write to
subscribe@crol-list.orgin plain English; the message is parsed into a watch and a confirmation link is sent back. - RSS, JSON, and iCal feeds: Live feeds for any lens, so you can wire CityScroll into your own tools.
- MCP for AI assistants: Point any MCP client at
api.cityscroll.org/mcpto search notices and create watches programmatically (docs). - Multilingual: The interface switches to Spanish, Simplified Chinese, Russian, and other languages via the header selector. Notice text stays in English (it's the official record); an unofficial translation is available on demand for shipping languages.
- Workspace: Pin records, write local notes, export CSV/JSON dossiers, and generate shareable snapshot links.
- Exports: Download any lens as Excel-safe CSV or a typed Excel workbook, export notice details with a contract-trail sheet, or print a clean permalink-stamped view to PDF.
The executable registry is site/data/source_contracts.json;
the generated source ledger records coverage, cadence, freshness,
required fields, and known gaps. Required pull-request checks validate recorded upstream
shapes; a separate daily workflow runs the live verifier and reports publisher drift.
| Live source | Used for | Product freshness |
|---|---|---|
City Record Online dg92-zbpx |
Core notices, feeds, alerts, profiles, hearings, property records, prior-cycle matches, and aggregates. | Live browser queries use a five-minute cache; Worker mirrors and materialized views refresh daily. |
| NYCIDA/Build NYC subsidy project records | City Record ↔ Build NYC subsidy timeline joins for application, hearing, board, closing, and compliance stages. | Freshness depends on the Build NYC document publication page; the worker caches joined lifecycle records for read-path latency. |
Checkbook NYC registered contracts Contracts |
Pending and registered contract amounts, paid-to-date totals, contract terms, and the procurement lifecycle timeline. | Queried live for contract details and daily for watched renewal estimates. |
Checkbook NYC spending transactions Spending |
Individual payment records in the procurement lifecycle (solicitation to payment). | Queried by PIN for the contract lifecycle timeline. |
Recent Contract Awards (OCP) qyyg-4tf5 |
OCP award side-car on the procurement lifecycle: award date and amount corroboration against City Record, with both sources named when they disagree. | Joined into the precomputed contract lifecycle on the Worker; edge-cached with the lifecycle read model. |
Checkbook NYC NYCHA contracts Contracts_NYCHA |
Exact NYCHA solicitation-to-award matches. | Queried by exact notice PIN on demand, with bounded daily prewarming. |
NYS Authorities Budget Office — local authorities 8w5p-k45m |
Possible award matches for mapped local-authority profiles. | Checked weekly; the last good cache is retained if the upstream request fails. |
NYS Authorities Budget Office — local development corporations d84c-dk28 |
Possible award matches for mapped local-development-corporation profiles. | Checked weekly; the last good cache is retained if the upstream request fails. |
NYS Authorities Budget Office — state authorities ehig-g5x3 |
Possible award matches for mapped state-authority profiles, including the MTA. | Checked weekly; the last good cache is retained if the upstream request fails. |
Citywide Payroll Data k397-673e |
Title and pay history in the Staffing experience. | Queried live with a five-minute browser cache. |
Civil Service List (Active) vx8i-nprf |
Competitive-list checks and active-list totals. | Queried live for list checks and captured in the Staffing build. |
Zoning Application Portal — projects hgx4-8ukb |
Rezoning search, status, milestones, applicants, and comments handoff. | Queried live with a five-minute browser cache and used by daily subscriptions. |
Zoning Application Portal — tax lots 2iga-a6mk |
Tax-lot joins from ZAP projects to MapPLUTO. | Queried live with a five-minute browser cache. |
| Zoning Application Portal — project outcomes (Planning Labs API) | Land detail decision documents, action approvals, disposition votes/recommendations, and DOB NOW tax-lot filing side-car beyond Open Data status chips. | Worker materializes per-project outcomes on GET /zap-outcomes with a one-day edge cache; the browser never calls the ZAP API for this panel. |
| MapPLUTO | Tax-lot boundary geometry. | Queried live for matched ZAP tax lots. |
| NYC GeoSearch | Address, neighborhood, borough, and BBL resolution. | Queried live; the verifier checks availability and response shape, not underlying data age. |
DOB NOW job application filings w9ak-ipjd |
Current demolition-filing verification. | Queried live only when a demolition check is requested. |
Legacy DOB job application filings ic3t-wcy2 |
Legacy demolition-filing verification. | Queried live as the fallback for demolition checks. |
Current Solicitations (OCP / Open Data) 3khw-qi8f |
Procurement lifecycle solicitation-stage package enrichment: document links, due dates, and contact fields joined to City Record notices by request_id or PIN. | Joined at lifecycle compute time and cached with the procurement timeline in D1; a stale or unreachable view leaves City Record stages intact and marks the package-documents sub-slot unknown. |
| NYC Rules RSS feed | Rule lifecycle enrichment: official comment/adoption page links, comment deadlines, hearing dates, adoption and effective dates joined to City Record Agency Rules notices. | Daily materialized join in the Worker; a stale or unreachable feed falls back to City Record notices only with an explicit enrichment-gap marker. |
| NYC Council Legistar API | Meeting outcomes surface: matching notices to Council agenda trees, matters, action outcomes, roll-call votes, attachments, and supporting documents. | Daily edge materialization (cron) fetches authenticated Events (180-day window), strict-joins City Record hearing notices, and materializes EventItems (agenda + matters + outcomes), best-effort roll-call votes, item attachments, and hearing documents (agenda/minutes PDFs) into the meeting-outcomes KV read model. Token reaches the Worker as secret LEGISTAR_API_TOKEN, synced idempotently from the GitHub Actions secret on each deploy. |
| PASSPort Public contracts | Pending and pre-registration contract stages on the procurement lifecycle when Checkbook is unmatched, plus registered-stage enrichment when EPIN joins a City Record PIN. | Worker rebuilds the D1 passport_contracts table on the daily scheduled run; lifecycle reads join from that edge materialization with no live browser fetch to PASSPort. |
| PASSPort Public solicitations (RFx) | RFx detail on solicitation lifecycle stages (due date, method, status, commodity) joined by EPIN to City Record PINs. | Worker rebuilds the D1 passport_rfx table on the daily scheduled run; solicitation lifecycle stages read joined RFx detail from that materialization. |
Doing Business Search - Entities 72mk-a8z7 |
Vendor identity enrichment on vendor profiles: Doing Business Search listing, ownership structure, organization phone, and doing-business start date when organization_name stems match a City Record award vendor. | Worker re-fetches the full entity list during the daily vendor-profile rebuild and attaches stem-joined rows to matching profiles. Schema probes tolerate multi-month publisher lag via max_stale_days. |
The external-award registry currently maps 13 agency names to 12 distinct ABO authorities across 8w5p-k45m, d84c-dk28, ehig-g5x3, adds 1 exact NYCHA mapping, and records 16 verified coverage gaps. ABO joins remain possible matches rather than exact contract identity.
MOCS Local Law 63 plan rows are disabled. The current official page publishes rotating per-agency spreadsheets without a stable machine manifest; the former configured dataset is non-tabular, and the former documented dataset does not exist. CityScroll does not show official plan forecasts until a source passes the executable contract.
This repository holds the complete system: a static client (site/) and a serverless
Cloudflare Worker backend (worker/) that handles email alerts, feeds, public metrics, and
the plain-English search assistant. Civil-service exam sources are normalized at build time
into site/data/staffing_exams.json, so career exploration needs one small static file and no
runtime API fan-out. Source provenance and refresh rules live in
site/data/exam_sources/. The project is designed to be forked and
pointed at any city's open-data portal.
For the code map and how the pieces fit together, see CONTRIBUTING.md; for backend routes, storage, and deploy steps, see worker/README.md.
Both unit layers run automatically in CI on every pull request and push to main
(.github/workflows/ci.yml); the Playwright functional suite runs on manual dispatch.
Run tests from the repository root:
- Unit Tests: Run
node --testto verify entity stem compilers, name resolution, and date logic. - Worker Tests: Run
node --testinside theworker/directory. - Functional (Playwright) Tests: Driven against a headless Chromium browser using:
Requires Python 3 and Playwright (
./test/functional/run.sh
pip install playwright && playwright install chromium). - Production E2E Tests: Run the public demo-link contract against the canonical deployment using:
CROL_BASE=https://cityscroll.org/ python3 test/functional/20_demo_links.py




