# US Code Violations - 9 jurisdictions, one case model (`formal_sadness_xvx/us-code-violations`) Actor

Property, housing and code violations from 9 US jurisdictions (~4.2M records) normalised into one schema with separate case-status and resolution fields.

- **URL**: https://apify.com/formal\_sadness\_xvx/us-code-violations.md
- **Developed by:** [Rishi Vinodkumar](https://apify.com/formal_sadness_xvx) (community)
- **Categories:** Lead generation, News, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 code violations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## US Code Violations — 9 jurisdictions, one case model

Property, housing and building code violations from nine US jurisdictions,
normalised into a single schema.

**~4,249,022 violation records across 9 actively-maintained sources.**

| Source | State | Records | Last verified |
|---|---|---:|---|
| Chicago | IL | ~2,020,658 | 2026-07-29 |
| Montgomery County | MD | ~954,255 | 2026-07-22 |
| Chicago (ordinance hearings) | IL | ~838,859 | 2026-07-30 |
| Kansas City | MO | ~174,999 | 2026-07-01 |
| New Orleans | LA | ~111,441 | 2026-07-30 |
| Mesa | AZ | ~80,580 | 2026-07-28 |
| Norfolk | VA | ~44,835 | 2026-07-29 |
| New York City (BIC) | NY | ~18,026 | 2026-07-29 |
| Cambridge | MA | ~5,369 | 2026-07-22 |

### Why this is harder than it looks

The other actors in this repo reconcile *spellings*. This one reconciles
*processes*. All nine publish a "status" field, and they are not describing the
same thing:

| Jurisdiction | Field | Vocabulary | What it actually means |
|---|---|---|---|
| Chicago | `violation_status` | `OPEN` / `COMPLIED` / `NO ENTRY` | violation state |
| Montgomery County | `disposition` | `Triennial Completed` / `Citation issued` | **inspection** outcome |
| Kansas City | `case_status` | `In-Compliance` / `In-Violation` | case state |
| Norfolk | `status` | `Closed - Corrected` / `Work in Progress` | case state |
| NYC BIC | `violation_disposition` | `Settled` / `Barred by CPLR` / `Judgement` | **court** outcome |
| Cambridge | `violation_status` | `Corrected` / `Cited` | violation state |
| Chicago ordinance | `case_disposition` | `Liable` / `Non-Suit` / `Default` / `Not Liable` | **hearing** outcome |
| New Orleans | `currentstatus` | `Violations Abated` / `Payment Received` | abatement pipeline |
| Mesa | `status` | `In Violation` / `Legal Action` / `Closed` | case state |

Collapsing those into one enum would look tidy and be a lie — a court
settlement is not a re-inspection result. So the schema carries **two
orthogonal fields**:

```
case_status  OPEN | CLOSED | UNKNOWN
resolution   CORRECTED | CITED | DISMISSED | NO_ACCESS | OTHER | NONE
```

plus `raw_status` (always the original string) and `status_semantics`
(`case` / `inspection` / `legal`) so you never silently compare a court
judgement against a housing re-inspection.

The mapping is substring-based and **order-sensitive**: `"Closed - Corrected"`
contains both `closed` and `corrected`; `"Not Corrected"` contains
`corrected`; `"Settled - Pending"` contains `settled`; and `"Not Liable"`
contains `"Liable"`, where a flipped order would turn ~107k dismissals into
citations. `test_status.py` pins all 43 observed strings.

### Four traps found while building this

**1. Montgomery County is mostly not violations.** Its 954k rows are dominated
by routine triennial inspections (`Triennial Completed`, 547k of them). Filter
`resolution = CITED` to find actual enforcement. Auto-inference also picked
`date_closed` as the event date, which would have silently excluded every
*open* case — we use `date_filed`.

**2. Kansas City's dates run into the future.** `date_found` contains
data-entry typos as far ahead as October 2029. Set `violatedBefore` if you are
building time series. `verify.py` flags this rather than reporting the feed
healthy.

**3. Chicago has two violation feeds.** `chicago` is building violations;
`chicago_ordinance` is administrative hearing outcomes — what the city actually
did about them. Its `violation_date` contains typos reaching **year 6111**, so
always set `violatedBefore`.

**4. NYC BIC is not what you expect.** It is the Business Integrity Commission
— trade waste and public markets — not the Department of Buildings. Narrow, but
the only source here with monetary penalties and court dispositions.

### Who this is for

- **Real-estate investors** sourcing distressed-property leads
- **Contractors** (roofing, façade, abatement) finding properties under order
- **Property managers and compliance vendors** monitoring portfolios
- **Journalists and researchers** tracking enforcement patterns

### Usage

Open violations with an address, last quarter:

```json
{
  "sources": ["chicago", "norfolk", "cambridge"],
  "violatedAfter": "2026-05-01",
  "openOnly": true,
  "requireAddress": true,
  "maxResults": 5000
}
```

Actual enforcement actions only (skips routine inspections):

```json
{ "violatedAfter": "2026-01-01", "violatedBefore": "2026-07-31", "resolution": ["CITED"] }
```

### Local development

```bash
pip install requests
python local_run.py --coverage
python local_run.py --after 2026-05-01 --limit 10
python local_run.py --open-only --after 2026-01-01 --limit 20
python local_run.py --resolution CITED --after 2026-01-01
python verify.py         # health-check every source
python test_status.py    # status-classification regression tests
```

### Legal

Public, logged-out municipal open-data endpoints via each jurisdiction's
official Socrata API. No authentication, no account, no terms accepted, no
anti-bot circumvention. Code violations are public records attached to
*properties*; `property_owner` is populated only where the jurisdiction
publishes it as part of that public record. Rate limits respected with
exponential backoff.

# Actor input Schema

## `sources` (type: `array`):

Which jurisdictions to fetch. Defaults to all 9.

## `violatedAfter` (type: `string`):

Only violations recorded on or after this date (YYYY-MM-DD).

## `violatedBefore` (type: `string`):

Strongly recommended. Kansas City's date\_found contains typos into 2029 and Chicago ordinance hearings reach year 6111; without an upper bound those rows sort to the top of a newest-first fetch.

## `openOnly` (type: `boolean`):

Shortcut for caseStatus = \[OPEN]. Normalises across six different vocabularies (OPEN / New / In-Violation / Work in Progress / Not Corrected).

## `caseStatus` (type: `array`):

Filter by normalised case state. Orthogonal to resolution: a case can be CLOSED with any resolution.

## `resolution` (type: `array`):

How the case ended. Orthogonal to case status because jurisdictions describe different processes: Montgomery reports inspection outcomes, NYC BIC reports court dispositions.

## `search` (type: `string`):

Substring match across description, violation type, address, owner and raw status.

## `requireAddress` (type: `boolean`):

Drop records with no resolvable street address.

## `maxResultsPerSource` (type: `integer`):

Caps results from each source. Leave empty for no limit.

## `maxResults` (type: `integer`):

Hard cap across all sources. Use this to bound cost.

## `includeRawRecord` (type: `boolean`):

Attach the original source record under `raw`, so nothing is lost to normalisation.

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

A free Socrata app token raises rate limits above the shared anonymous pool. Only worth setting for large sweeps.

## Actor input object example

```json
{
  "sources": [
    "chicago",
    "norfolk"
  ],
  "violatedAfter": "2026-01-01",
  "openOnly": false,
  "requireAddress": false,
  "maxResults": 1000,
  "includeRawRecord": false
}
```

# 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 = {
    "sources": [
        "chicago",
        "norfolk"
    ],
    "violatedAfter": "2026-01-01",
    "maxResults": 1000
};

// Run the Actor and wait for it to finish
const run = await client.actor("formal_sadness_xvx/us-code-violations").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 = {
    "sources": [
        "chicago",
        "norfolk",
    ],
    "violatedAfter": "2026-01-01",
    "maxResults": 1000,
}

# Run the Actor and wait for it to finish
run = client.actor("formal_sadness_xvx/us-code-violations").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "sources": [
    "chicago",
    "norfolk"
  ],
  "violatedAfter": "2026-01-01",
  "maxResults": 1000
}' |
apify call formal_sadness_xvx/us-code-violations --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=formal_sadness_xvx/us-code-violations",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/OtXXxI1KX60uS38l4/builds/Ey1eu4GFQr2pjmJCN/openapi.json
