NYC Restaurant Inspection Data Scraper (DOHMH Grades JSON) avatar

NYC Restaurant Inspection Data Scraper (DOHMH Grades JSON)

Pricing

from $3.00 / 1,000 inspection row delivereds

Go to Apify Store
NYC Restaurant Inspection Data Scraper (DOHMH Grades JSON)

NYC Restaurant Inspection Data Scraper (DOHMH Grades JSON)

Scrape official NYC Open Data restaurant inspections (DOHMH): one row per inspection and violation with score, grade, action, violation codes and descriptions, borough, cuisine, address and coordinates. Filter by date, borough, cuisine or grade. Establishment data only, no personal contact fields.

Pricing

from $3.00 / 1,000 inspection row delivereds

Rating

0.0

(0)

Developer

Steadfetch

Steadfetch

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 hours ago

Last modified

Share

Extract official New York City restaurant inspection results from the NYC Open Data Socrata API. Structured JSON with inspection dates, scores, grades, violation codes and establishment location. No browser, no login, no CAPTCHA.

What it does

The Actor queries the official DOHMH dataset DOHMH New York City Restaurant Inspection Results (Socrata resource 43nn-pn8j) and returns one dataset item per inspection or violation row.

  • Date window: since and until filter on inspection_date. Default is the last 30 days.
  • Location and type filters: borough, cuisine and grade (A, B or C), all applied server-side with SoQL.
  • Normalized output: scores and coordinates become numbers, dates become YYYY-MM-DD, and missing values become null.
  • Deduplication: key is camis + inspection_date + violation_code, both inside a run and across monitor runs.
  • Monitor mode: with mode: "monitor" the Actor persists delivered keys in its key-value store and only emits rows that were never delivered before for the same borough, cuisine and grade scope.
  • Schema validation: every item is validated against .actor/dataset_schema.json before it reaches the dataset. With strictSchema: true (the default) an invalid item fails the run.

No charge for noise: errors, retries, duplicate rows, rows already delivered by a monitor run and the source placeholder date 1900-01-01 are never pushed, so they are never billed.

Source, licence and privacy

  • Source: official NYC Open Data API, dataset published by the NYC Department of Health and Mental Hygiene (DOHMH). It is keyless and updated daily by the City.
  • Terms: re-read on 2026-10-20. The NYC Open Data home page links to the NYC.gov Terms of Use, which require lawful use and do not prohibit lawful automated access to public data; the Socrata metadata for this dataset has no separate licence field. The Actor attributes DOHMH and links the public source URL on every row. Store publication keeps the CTO sign-off item in PUBLISHING.md.
  • Privacy: establishment data only. The Actor never selects the source phone column ($select excludes it), and no phone, email, officer or other personal contact field is published. No personal data is collected.

Example output

{
"url": "https://data.cityofnewyork.us/resource/43nn-pn8j.json?camis=40393413",
"title": "V & S PIZZERIA OF SHEAPSHEAD BAY",
"scrapedAt": "2026-10-20T08:18:21.885Z",
"camis": "40393413",
"business_name": "V & S PIZZERIA OF SHEAPSHEAD BAY",
"borough": "Brooklyn",
"building": "1723",
"street": "EMMONS AVENUE",
"zipcode": "11235",
"cuisine_description": "Pizza",
"inspection_date": "2026-10-17",
"action": "Violations were cited in the following area(s).",
"violation_code": "10F",
"violation_description": "Non-food contact surface or equipment made of unacceptable material, not kept clean, or not properly sealed, raised, spaced or movable to allow accessibility for cleaning on all sides, above and underneath the unit.",
"critical_flag": "Not Critical",
"score": 11,
"grade": "A",
"grade_date": "2026-10-17",
"latitude": 40.583369830769,
"longitude": -73.951275749439,
"source_url": "https://data.cityofnewyork.us/resource/43nn-pn8j.json?camis=40393413"
}

Input

Minimal run:

{
"since": "2026-09-01",
"maxResults": 10
}

Filtered monitor run:

{
"since": "2026-09-01",
"borough": "Manhattan",
"cuisine": "Pizza",
"grade": "A",
"maxResults": 500,
"mode": "monitor"
}
FieldTypeDescription
sincestringOptional ISO date (YYYY-MM-DD). Default: last 30 days.
untilstringOptional ISO date (YYYY-MM-DD), inclusive.
boroughstringOptional case-insensitive borough: Manhattan, Brooklyn, Queens, Bronx or Staten Island.
cuisinestringOptional case-insensitive DOHMH cuisine description, for example Pizza or American.
gradeA, B or COptional grade filter.
maxResultsintegerDefault 1000, maximum 5000.
modefull or monitorDefault full. monitor emits only rows never delivered before in the same borough/cuisine/grade scope.
strictSchemabooleanDefault true; fail the run on schema violations.

No API key or login is required. An optional SOCRATA_APP_TOKEN Actor secret can be configured to raise Socrata rate limits; it is never part of the input and is never logged.

Output fields

FieldTypeNotes
camisstringDOHMH establishment id (required).
business_namestringSource dba (required).
boroughstring or nullSource boro.
building, street, zipcodestring or nullEstablishment address.
cuisine_descriptionstring or nullDOHMH cuisine label.
inspection_datedateRequired; 1900-01-01 is dropped.
actionstring or nullInspection action text.
violation_code, violation_descriptionstring or nullViolation detail; null when no violation was recorded.
critical_flagstring or nullCritical / Not Critical / Not Applicable.
scorenumber or nullPublished inspection score.
gradestring or nullA, B, C, N, P or null, as published.
grade_datedate or nullPlaceholder dates become null.
latitude, longitudenumber or nullWGS84; 0/0 placeholders become null.
url, source_urlstringPublic NYC Open Data API URL for the establishment.
scrapedAtstringISO 8601 UTC timestamp of the run.

Project structure

.actor/actor.json Actor definition (payPerEvent, dataset schema, output schema)
.actor/input_schema.json INPUT options (date window, borough, cuisine, grade, maxResults, mode)
.actor/dataset_schema.json Item JSON Schema (fields) + table view for the Store
.actor/pay_per_event.json PPE pricing (two synthetic platform events)
src/query.ts Pure SoQL filter and API URL construction (no phone column)
src/fetch.ts Socrata HTTP client: pagination, retry/backoff
src/extract.ts Pure normalization, dedupe and monitor helpers (fixture-tested)
src/main.ts Entry point: fetch, validate, monitor filter, push
src/validate-output.ts Ajv validator shared by the run and the tests
test/ Offline fixtures and Vitest suites (no network, no credit)

Pay-per-event pricing

The Actor uses Apify pay-per-event pricing with the two synthetic platform events:

EventCharged whenPrice
apify-actor-starta run starts (synthetic, automatic)0.00005 USD per run (Apify-recommended default; includes 5 seconds of free compute)
apify-default-dataset-itemone inspection row is saved to the dataset (synthetic, automatic)0.003 USD per row = 3.00 USD per 1,000 results

There is no custom per-item event and no Actor.charge() call: the platform already charges apify-default-dataset-item per pushed item, so adding another event would bill users twice.

The price sits inside the direct-competitor band (0.001-0.01 USD per inspection) and inside Steadfetch's 1-10 USD per 1,000 results band.

Measured cost: a 1,000-row run takes about 4.0 seconds at the 256 MB minimum memory, using one free Socrata request. At Apify's 0.20 USD per GB-hour compute reference that is about 0.00006 USD of compute per 1,000 rows, well under the 0.10 USD target and leaving a gross margin above 99%. Larger runs reuse the same page size and do not need a browser or proxy.

Development

npm install
npm test # lint + typecheck + offline Vitest suites (no credit)
npm run publish:check # Steadfetch publish gate
npm run schemas:validate
npm run smoke # local Apify run (no platform credit)

The default test suite runs against the committed fixture test/fixtures/socrata-inspections.json and never touches the network. It covers the SoQL filters, the prohibited phone column, pagination, retry/backoff, deduplication, monitor state and output-schema validation.

FAQ

Do I need an API key? No. The NYC Open Data Socrata endpoint is public and keyless.

Does it use a browser? No. The source is a JSON API, so plain HTTP is roughly 10x cheaper than rendering the web front end.

Does it return personal data? No. Only establishment fields are returned. The phone column is not even selected from the API, and no other contact field is published.

When am I charged? Once per run start (apify-actor-start) and once per inspection row saved to the dataset (apify-default-dataset-item). Errors, retries, duplicates and the 1900-01-01 placeholder are not charged.

How does monitor mode avoid charging twice? It stores the dedupe keys it delivered in an Actor key-value store. On the next run with the same borough, cuisine and grade scope it skips those keys before pushing, so they are not billed again. Use mode: "full" when you want the complete matching window on every run.

Why can one inspection produce several rows? The source publishes one row per violation citation. The Actor keeps that grain, which is what compliance and analytics teams need, and deduplicates identical camis + inspection_date + violation_code rows.

Is the output schema stable? Yes. New fields are additive and the required fields in .actor/dataset_schema.json do not change.

Maintenance

This Actor is tested daily: automated runs check that the NYC Open Data API is reachable and that the output still matches the published schema. Failures are reported as issues in the Steadfetch Actors repository.