Methodology Back to tracker
How this tracker works

Methodology

The NYC FOIL Tracker pulls public freedom-of-information request data from NYC OpenRecords, the city's central FOIL portal. This page documents exactly what's collected, how the numbers are computed and what the tracker doesn't capture.

Data source

OpenRecords (a860-openrecords.nyc.gov) is the public-facing portal New York City agencies use to receive FOIL requests and post responses. The tracker reads the public "View all requests" listing and individual request pages — no private records, no agency-only views.

What's pulled

For each request the scraper captures:

Coverage gap (important)

The "Filed in 2026" stat shows the total reported by OpenRecords (around 600,000 requests). The "Tracked here" number is what the scraper has details for — currently around 35,000. This is not a complete archive of every New York City FOIL request ever filed.

OpenRecords' public listing is a rolling window: older requests fall off the public-facing pages over time, and the listing is paginated with practical limits. The tracker captures what's currently visible on the site. Agency-level totals shown in the "By agency" table reflect the scraped subset, not the agency's lifetime FOIL volume.

How the headline stats are computed

Avg. response (days)

Mean number of calendar days from dateSubmitted to final agency action (dateClosed), averaged across all closed requests in the tracked subset that have both dates recorded. Open requests are excluded. This is a calendar-day average; New York's FOIL law uses business days for legal deadlines, so the tracker number is slightly higher than the equivalent business-day figure.

Denial rate

Denials as a share of requests with a recorded determination (Fulfilled + Denied + Partially Denied). Open requests, withdrawn requests and requests with no determination message are excluded from the denominator. "Partially Denied" requests are counted as fulfilled for this calculation — only outright denials count as denials.

Past due date

An open request whose dateDue (the agency's own stated due date) is earlier than today. OpenRecords' due dates reflect the agency's statutory acknowledgment-and-response timeline plus any extensions the agency has requested. A request marked "past due" means the agency has missed its own extended deadline, not just the initial 5-business-day acknowledgment.

Open > 30 / 90 days

Open requests where dateSubmitted is more than 30 (or 90) calendar days ago. This is independent of whether the agency requested extensions — it's a simple "how long has this been sitting" measure.

Denied last 30 days

Closed requests with determination = "Denied" and dateClosed within the last 30 calendar days. Useful for spotting recent denial patterns by agency or topic.

"Under review" placeholders

Newly filed requests show a placeholder title of "* Under Review" for the first several business days while OpenRecords processes them. These are real requests but with no public subject yet, so the tracker hides them by default. Toggle "Show 'under review' placeholders" in the filter bar to include them.

Topic tagging

The "By topic" panel and the topic filter use simple keyword patterns to bucket requests by subject matter. Patterns match against the request title only (no body text — OpenRecords doesn't expose request bodies publicly). Many requests have generic titles ("Complaint Report", an address) or no title yet, so they cluster into "Other / unclassified" — currently around 65% of titled requests. The patterns favor high-confidence matches over coverage; if a title doesn't contain a recognizable keyword, it stays untagged rather than getting forced into a bucket.

A request can land in more than one topic (e.g., a body-cam request at NYPD matches both "Police / NYPD records" and "Vehicle / parking / traffic" if it mentions a traffic stop). The "Other / unclassified" bucket only contains requests that match zero topics. The full pattern list lives in index.html (TOPIC_PATTERNS) and is mirrored in generate-feeds.mjs.

RSS feeds

The tracker publishes RSS feeds so reporters can subscribe to specific slices in their feed reader. Available feeds:

Feeds regenerate every time the scraper runs. The full feed index is at feed/INDEX.md.

Requester identity

OpenRecords does not display requester names, emails or affiliations on the public-facing detail page. Only the requester (when logged in) and the receiving agency can see who filed a given request. As a result, the tracker has no way to surface "who's filing the most FOILs" or "what did The New York Times ask for last week" without privileged data access. The public detail page markup has no such field.

Update cadence

The scraper runs automatically every six hours. The "Last updated" timestamp at the top of the tracker shows when the current data was pulled.

Limitations and caveats

Source code and corrections

The scraper, data file and this front-end are all open source. If you spot an error or have a methodology question, file an issue on GitHub.

← Back to the tracker