# US Restaurant Health Inspections (6 Cities) (`huffworks/restaurant-health-inspections`) Actor

Restaurant health inspections from NYC, Chicago, San Francisco, Austin, Seattle and Cincinnati open data: scores, grades, pass/fail and violations.

- **URL**: https://apify.com/huffworks/restaurant-health-inspections.md
- **Developed by:** [Greg Huff](https://apify.com/huffworks) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 inspection records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does US Restaurant Health Inspections do?

**US Restaurant Health Inspections** pulls **restaurant and food-facility health inspection results** from six official US open-data APIs (**New York City, Chicago, San Francisco, Austin, King County (Seattle) and Cincinnati**) and gives them back in **one normalized format**: one record per inspection with the establishment, address, date, inspection type, the score or grade exactly as the department published it, a normalized **pass / conditional / fail** result, and every **violation** with its code, description and critical flag where the department publishes one.

Every record links back to the official dataset and to the exact API query it came from. Nothing is scraped from inspection websites: the Actor reads only the published Socrata (SODA) JSON endpoints, which the departments provide for public reuse. **No API key, no login, no proxy.**

- ✅ **Six health departments, one schema**: stop writing six parsers for six column layouts.
- 🔎 **Filter at the source**: business name, street, ZIP or ZIP prefix, date range, violation severity, result.
- 🏷️ **Latest inspection per establishment**: one row per restaurant for snapshots and monitoring.
- 💸 **Pay only for records**: $1.70 per 1,000 inspections, nothing for empty queries.
- ⏱️ **Fast**: 3,000 inspections across all six jurisdictions took 12 seconds in our test run.

### Who uses inspection data?

- **Food-delivery and restaurant analysts**: flag partners with failed or closure inspections, score markets.
- **Restaurant software vendors (POS, food safety, compliance)**: find prospects that just failed or were re-inspected, enrich CRM records.
- **Insurers and underwriters**: inspection history and critical violations per location.
- **Local journalists**: weekly lists of closures and failed inspections by neighborhood or ZIP.
- **Franchise and multi-unit operators**: monitor every one of your locations ("starbucks", "chipotle") across cities in one run.

### What data can you extract?

| Field | Example | Notes |
| --- | --- | --- |
| jurisdiction | nyc | nyc, chicago, san-francisco, austin, king-county, cincinnati |
| establishmentId | 50071318 | The department's own id (CAMIS, license, permit, business id) |
| name | THE COFFEE CLUB | Business (DBA) name as published |
| address, city, state, zip | 9526 4 AVENUE, Brooklyn, NY, 11209 | San Francisco publishes no ZIP |
| latitude, longitude | 40.6156, -74.0313 | Where published (not King County) |
| inspectionDate | 2026-10-15 | YYYY-MM-DD |
| inspectionType | Cycle Inspection / Initial Inspection | As published |
| scorePublished | 20 | As published; direction differs by city (see below) |
| gradePublished | A | NYC letter grade, King County rating, Austin color band |
| resultPublished | Violations were cited in the following area(s). | The department's own words |
| result | conditional | Normalized: pass, conditional, fail, or null |
| violationCount, criticalViolationCount | 4, 3 | Critical count only where a flag is published |
| violations | code, description, critical, criticalPublished, points, comments | null for Austin (scores only) |
| details | cuisine, risk level, facility type, permit type, neighborhood | Jurisdiction-specific extras |
| sourceDatasetUrl, sourceApiUrl | https://data.cityofnewyork.us/d/43nn-pn8j | Official dataset page and the query used |
| scrapedAt | 2026-10-17T04:46:45.898Z | When the record was saved |

### Jurisdictions, fields, update cadence and licenses

All six were checked on 2026-10-17 through each dataset's metadata (`/api/views/<id>.json`) and live queries.

| Jurisdiction | Dataset | Rows (2026-10-17) | Updated | What it publishes | Critical flag | License / terms |
| --- | --- | --- | --- | --- | --- | --- |
| New York City, NY (DOHMH) | [43nn-pn8j](https://data.cityofnewyork.us/d/43nn-pn8j) | ~297,000 violation rows for currently active restaurants (oldest 2007) | Daily | score (points, lower is better), letter grade, action, cuisine, violations | Yes: Critical / Not Critical | No license on the dataset record; NYC Open Data terms of use |
| Chicago, IL (CDPH) | [4ijn-s7e5](https://data.cityofchicago.org/d/4ijn-s7e5) | ~317,000 inspections since 2010 | Daily | result (Pass / Pass w/ Conditions / Fail...), risk level, facility type, violations with inspector comments | No | City of Chicago [Data Terms of Use](https://www.chicago.gov/city/en/narr/foia/data_disclaimer.html) (as-is, no warranty) |
| San Francisco, CA (DPH) | [tvy3-wexg](https://data.sf.gov/d/tvy3-wexg) | ~22,800 inspections since 2024 | Daily | rating status (Pass / Conditional Pass / Closure), permit type, violation codes and text | No | ODC Public Domain Dedication (PDDL) 1.0 |
| Austin, TX (Austin Public Health) | [ecmv-9xxi](https://data.austintexas.gov/d/ecmv-9xxi) | ~20,400 inspections since Oct 2023 | Every 2 weeks | score out of 100, color band; **no violation detail** | No | Public Domain |
| King County / Seattle, WA | [r878-4sxa](https://data.kingcounty.gov/d/r878-4sxa) | ~110,000 violation rows since 2021 | Frequent (no stated cadence; updated 2026-10-16) | score (points, lower is better), Satisfactory / Unsatisfactory, rating, risk category, violations with points | Yes: RED / BLUE | Public Domain |
| Cincinnati, OH | [rg6p-b3h3](https://data.cincinnati-oh.gov/d/rg6p-b3h3) | ~346,000 violation rows since 2009 | Frequent (no stated cadence; updated 2026-10-17) | action status (Approved / Not In Compliance), license, neighborhood, violations with comments | No | Public Domain |

#### How is the normalized result decided?

The departments use different words, so `result` is our mapping; `resultPublished`, `scorePublished` and `gradePublished` always keep the original.

| Jurisdiction | pass | conditional | fail | null |
| --- | --- | --- | --- | --- |
| NYC | grade A or score 0-13; re-opened | grade B or score 14-27 | grade C or score 28+; closed by DOHMH | no score or grade (administrative) |
| Chicago | Pass | Pass w/ Conditions | Fail | Out of Business, No Entry, Not Ready |
| San Francisco | Pass | Conditional Pass | Closure | no status published |
| Austin | score 90+ | 70-89 | under 70 | no score |
| King County | Satisfactory | (none) | Unsatisfactory | Complete (educational visits) |
| Cincinnati | Approved - No Violations / Violations Abated | Approved - Minor Violations | Not In Compliance | Cancelled and other statuses |

### How to use it

1. Click **Try for free** (or **Start**).
2. Pick the **Jurisdictions** you need (all six by default).
3. Optionally filter by **Business name contains**, **Street address contains**, **ZIP code (or prefix)** and an **Inspected from / to** date range (absolute, or relative like "90 days").
4. Choose a **Minimum violation severity** and a **Normalized result** if you only want, say, failed inspections with a critical violation.
5. Turn on **Only the latest inspection per establishment** for one row per restaurant.
6. Set **Maximum inspections**, click **Start**, then download JSON, CSV or Excel from the **Output** tab or read it through the Apify API.

### Input example

This is the prefilled input: the 10 newest inspections from each jurisdiction.

```json
{
    "jurisdictions": ["nyc", "chicago", "san-francisco", "austin", "king-county", "cincinnati"],
    "maxItems": 60
}
```

Failed inspections with a critical violation in the last 30 days, one per restaurant:

```json
{
    "jurisdictions": ["nyc", "king-county"],
    "dateFrom": "30 days",
    "minSeverity": "critical",
    "results": ["fail"],
    "onlyLatestPerEstablishment": true,
    "maxItems": 500
}
```

### Output example

```json
{
    "jurisdiction": "nyc",
    "jurisdictionName": "New York City, NY (DOHMH)",
    "recordId": "nyc:50071318:2026-10-15:Cycle Inspection / Initial Inspection",
    "establishmentId": "50071318",
    "name": "THE COFFEE CLUB",
    "address": "9526 4 AVENUE",
    "city": "Brooklyn",
    "state": "NY",
    "zip": "11209",
    "latitude": 40.615596980304,
    "longitude": -74.031285941951,
    "inspectionDate": "2026-10-15",
    "inspectionType": "Cycle Inspection / Initial Inspection",
    "scorePublished": 20,
    "gradePublished": null,
    "resultPublished": "Violations were cited in the following area(s).",
    "result": "conditional",
    "violationCount": 4,
    "criticalViolationCount": 3,
    "violations": [
        {
            "code": "04L",
            "description": "Evidence of mice or live mice in establishment's food or non-food areas.",
            "critical": true,
            "criticalPublished": "Critical",
            "points": null,
            "comments": null
        },
        {
            "code": "08A",
            "description": "Establishment is not free of harborage or conditions conducive to rodents, insects or other pests.",
            "critical": false,
            "criticalPublished": "Not Critical",
            "points": null,
            "comments": null
        }
    ],
    "details": { "borough": "Brooklyn", "cuisine": "Coffee/Tea", "gradeDate": null, "scoreNote": "Lower is better (0-13 = A, 14-27 = B, 28+ = C)." },
    "sourceDatasetUrl": "https://data.cityofnewyork.us/d/43nn-pn8j",
    "sourceApiUrl": "https://data.cityofnewyork.us/resource/43nn-pn8j.json?$where=...",
    "scrapedAt": "2026-10-17T04:46:45.898Z"
}
```

(Two of the four violations shown.) `sample-output.json` next to this README has full records.

### How much does it cost to get restaurant inspection data?

This Actor uses **pay-per-event** pricing: a fixed price per inspection record saved, nothing for platform compute.

| Event | Price | When it is charged |
| --- | --- | --- |
| Inspection record | **$1.70 per 1,000** ($0.0017 each) | Each inspection saved to your dataset |
| Actor start | $0.00005 per GB of memory | Once when a run starts, charged by Apify |

Apify Silver subscribers pay $1.50 and Gold $1.40 per 1,000. **Example:** a weekly run of 2,000 inspections costs about **$3.40**. The free Apify plan's monthly credit covers a few thousand records.

You stay in control: set **Maximum inspections**, or a **maximum cost per run** in the run options, and the Actor stops cleanly when it gets there.

### Limits

- **Six jurisdictions only.** Other cities publish inspections in other formats; Los Angeles County, for example, publishes CSV files rather than a query API, so it is not included.
- **Austin publishes scores only**, with no violation detail: `violations` is null and Austin is skipped by the violation filters.
- **Critical flags are published only by NYC and King County.** "At least one critical violation" skips the other four, and `criticalViolationCount` is null there.
- **San Francisco has no ZIP column** and is skipped when you filter by ZIP. Its violations are parsed from one text field; `details.violationCountPublished` keeps the department's own count, which can differ by one.
- **Scores are not comparable across cities**: NYC and King County count penalty points (lower is better), Austin scores out of 100.
- **Maximum inspections is shared evenly** across the chosen jurisdictions, smallest result sets first, so unused capacity rolls over to the bigger ones.
- The data is only as fresh and correct as each department's feed; future-dated and placeholder dates (for example 1900-01-01) are dropped.
- Socrata throttles anonymous use by IP. Normal runs never hit it; for very large runs add a free **Socrata app token** in Advanced settings.

### FAQ

#### Is it legal to use this data?

These are public records that the health departments publish on their open-data portals for reuse. Four datasets are public domain or PDDL; Chicago and NYC publish under their portals' terms of use, which provide the data as-is. Check the terms yourself before republishing at scale.

#### Does it scrape restaurant inspection websites?

No. It reads only the official Socrata open-data APIs listed above. No browser, no login, no proxy.

#### Can I monitor new inspections every day?

Yes. Schedule the Actor with **Inspected from** set to "2 days" and connect a webhook, Google Sheets, Make, Zapier or n8n. Use `recordId` to de-duplicate across runs.

#### Can you add my city?

Open an issue with the city or county. Any department that publishes inspections through an open-data API can be added.

### Support

Found a problem or a field that looks wrong? Open an issue on the **Issues** tab with the run ID and the `recordId`, and we will look at it.

# Actor input Schema

## `jurisdictions` (type: `array`):

Health departments to query. Each one is an official Socrata open-data API.

## `nameContains` (type: `string`):

Case-insensitive text that must appear in the business (DBA) name, e.g. "starbucks" or "taco".

## `addressContains` (type: `string`):

Case-insensitive text that must appear in the street address, e.g. "broadway".

## `zip` (type: `string`):

Full ZIP ("10012") or a prefix ("606" for most of Chicago). San Francisco publishes no ZIP column and is skipped when this is set.

## `dateFrom` (type: `string`):

Earliest inspection date: YYYY-MM-DD or relative, like "90 days" or "1 year". Empty means no lower limit.

## `dateTo` (type: `string`):

Latest inspection date (YYYY-MM-DD or relative). Empty means today. Future-dated rows are always dropped.

## `minSeverity` (type: `string`):

"All inspections" includes clean ones. "At least one violation" skips Austin (no violation detail). "At least one critical violation" uses the critical flag as each department publishes it, which only NYC (Critical) and King County (RED) do.

## `results` (type: `array`):

Keep only these normalized outcomes. Empty keeps all, including inspections with no assessable result (e.g. "Out of Business"). The README lists how each department's wording maps to pass, conditional and fail.

## `onlyLatestPerEstablishment` (type: `boolean`):

Return one record per establishment: its most recent inspection within the date range and name/address/ZIP filters. The severity and result filters are applied to that latest inspection, so "fail" plus this option means "places whose latest inspection failed".

## `maxItems` (type: `integer`):

Stop after this many inspection records in total, shared evenly across the jurisdictions (left-over capacity rolls over to the next one). You pay per record, so this also caps the cost.

## `maxRowsPerJurisdiction` (type: `integer`):

Safety limit on raw rows read from each API (several rows make one inspection in NYC, King County and Cincinnati). Raise it for very selective filters over long date ranges.

## `socrataAppToken` (type: `string`):

Not needed. Socrata serves these APIs without a token at lower rate limits; a free app token from any Socrata portal raises them for very large runs. Sent only as the X-App-Token header.

## Actor input object example

```json
{
  "jurisdictions": [
    "nyc",
    "chicago",
    "san-francisco",
    "austin",
    "king-county",
    "cincinnati"
  ],
  "minSeverity": "all",
  "results": [],
  "onlyLatestPerEstablishment": false,
  "maxItems": 60,
  "maxRowsPerJurisdiction": 50000
}
```

# Actor output Schema

## `results` (type: `string`):

All results as JSON. Add ?format=csv or ?format=xlsx to download another format.

## `overview` (type: `string`):

The Overview view defined in dataset_schema.json.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "jurisdictions": [
        "nyc",
        "chicago",
        "san-francisco",
        "austin",
        "king-county",
        "cincinnati"
    ],
    "maxItems": 60
};

// Run the Actor and wait for it to finish
const run = await client.actor("huffworks/restaurant-health-inspections").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "jurisdictions": [
        "nyc",
        "chicago",
        "san-francisco",
        "austin",
        "king-county",
        "cincinnati",
    ],
    "maxItems": 60,
}

# Run the Actor and wait for it to finish
run = client.actor("huffworks/restaurant-health-inspections").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "jurisdictions": [
    "nyc",
    "chicago",
    "san-francisco",
    "austin",
    "king-county",
    "cincinnati"
  ],
  "maxItems": 60
}' |
apify call huffworks/restaurant-health-inspections --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,huffworks/restaurant-health-inspections"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RwkYNbtBNi9PHM6os/builds/kx4ml4uWt7jZIBBBS/openapi.json
