# US Crime Incidents - 8 agencies, one offence taxonomy (`formal_sadness_xvx/us-crime-incidents`) Actor

Police incident data from 8 US agencies (~16.3M records) normalised into one schema, with NIBRS crime-against buckets and explicit provenance for every classification.

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

## Pricing

from $2.00 / 1,000 record scrapeds

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 Crime Incidents — 8 agencies, one offence taxonomy

Police incident data from eight US agencies, normalised into a single schema.

**~16,313,654 incident records across 8 actively-maintained sources.**

| Source | State | Records | Last verified |
|---|---|---:|---|
| Chicago | IL | ~8,604,907 | 2026-07-23 |
| Austin | TX | ~2,659,603 | 2026-07-25 |
| Seattle | WA | ~1,551,250 | 2026-07-29 |
| Dallas | TX | ~1,506,789 | 2026-07-30 |
| San Francisco | CA | ~1,050,739 | 2026-07-28 |
| Montgomery County | MD | ~502,468 | 2026-07-30 |
| New York City | NY | ~279,513 | 2026-07-29 |
| King County | WA | ~158,385 | 2026-07-31 |

### What this reconciles

Four incompatible offence taxonomies:

| Agency | Taxonomy | Offence fields |
|---|---|---|
| Chicago | IUCR | `primary_type` + `description` |
| Seattle | NIBRS | `nibrs_offense_code_description` + crime-against |
| Dallas | NIBRS | `nibrs_crime` + `nibrs_crimeagainst` |
| King County | NIBRS | `nibrs_code_name` |
| NYC | NY penal law | `ofns_desc` + `law_cat_cd` |
| San Francisco | bespoke | `incident_category` + `incident_subcategory` |
| Montgomery County | bespoke | `crimename1` / `crimename2` / `crimename3` |
| Austin | UCR | `crime_type` + `ucr_code` |

NIBRS defines a `crime_against` axis — **PERSON / PROPERTY / SOCIETY** — which
is the closest thing to a cross-jurisdiction comparable. Four sources publish
it directly; for the rest it is derived from offence text.

**Every record states which.** `crime_against_source` is `published`,
`derived`, or `none`. A derived value presented as authoritative is
indistinguishable from a real one, and that is how bad crime statistics get
made. Set `publishedClassificationOnly` to restrict to agency-stated buckets.

### Location precision varies by design

Police agencies deliberately blur incident locations. This is **not** missing
data:

| Agency | Precision | Address | Coordinates |
|---|---|---|---|
| Montgomery County | `street` | full street address | yes |
| Dallas | `street` | street address | **no** |
| Chicago | `block` | `012XX W ADDISON ST` | yes |
| Seattle | `block` | block address | yes |
| King County | `block` | block address | **no** |
| San Francisco | `coordinates_only` | **none** | yes |
| NYC | `district_only` | borough + precinct | yes |
| Austin | `census_block` | **none** | **no** |

`location_precision` travels with every record so a census-block centroid is
never mistaken for a street address. Use `requireCoordinates` or
`requireAddress` to filter — but note each excludes three sources.

### Traps found while building this

**1. `updated_on` is not when the crime happened.** Chicago, King County and
others carry row-maintenance timestamps that are always fresher than the
occurrence date — every row gets touched on every refresh. A "pick the most
recent date column" heuristic selects them every time, yielding an event date
that means "when the row was last edited". Chicago uses `date`; King County
uses `incident_datetime`.

**2. NYC really does spell it `HARRASSMENT`.** Two Rs, in the live data.
Matching only the correct spelling silently drops every harassment complaint in
the city.

**3. Non-crimes must not inflate real buckets.** `Missing Person` contains
"person" and would count as a crime against a person; `Found Property` contains
"property". These map to `OTHER`.

**4. Robbery is PERSON, not PROPERTY,** under NIBRS — despite the property
element — because it involves force against a victim. `Theft from person`
remains PROPERTY.

**5. Austin's `occ_date_time` is stale text stopping in 2025** while `occ_date`
is live. Dallas's `date2_of_occurrence_2` contains typos into 2028.

### Output

```json
{
  "source": "chicago",
  "state": "IL",
  "incident_id": "JK344134",
  "occurred_date": "2026-07-23",
  "offense": "THEFT",
  "offense_category": "THEFT",
  "offense_detail": "OVER $500",
  "crime_against": "PROPERTY",
  "crime_against_source": "derived",
  "severity": "UNKNOWN",
  "taxonomy": "IUCR",
  "premise": "APARTMENT",
  "beat": "0523",
  "neighborhood": "53",
  "arrest": false,
  "address": "120XX S PERRY AVE",
  "location_precision": "block",
  "latitude": 41.675426798,
  "longitude": -87.624988687
}
```

Only Chicago publishes an `arrest` flag. Only NYC publishes severity as
felony/misdemeanor/violation; NIBRS sources report Group A/B instead, so most
records are `UNKNOWN` on that axis.

### Who this is for

- **Proptech and insurance** pricing location risk
- **Retail site selection** screening candidate locations
- **Journalists and academics** doing cross-city comparison
- **Public-safety analytics** vendors needing a multi-agency feed

### Usage

Mappable violent crime, last quarter:

```json
{
  "sources": ["chicago", "seattle", "montgomery_md"],
  "occurredAfter": "2026-05-01",
  "crimeAgainst": ["PERSON"],
  "requireCoordinates": true,
  "maxResults": 5000
}
```

Statistics-grade — agency-stated classifications only:

```json
{ "occurredAfter": "2026-01-01", "publishedClassificationOnly": true }
```

### Local development

```bash
pip install requests
python local_run.py --coverage
python local_run.py --after 2026-06-01 --limit 10
python local_run.py --against PERSON --coords --after 2026-01-01
python local_run.py --published-only --after 2026-01-01
python verify.py           # health-check every source
python test_classify.py    # classification regression tests
```

### Legal

Public, logged-out municipal open-data endpoints via each agency's official
Socrata API. No authentication, no account, no terms accepted, no anti-bot
circumvention. These are aggregate incident reports published deliberately at
blurred precision; no source here identifies victims or suspects, and this
actor does not attempt to re-identify anyone. Rate limits respected with
exponential backoff.

# Actor input Schema

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

Which agencies to fetch. Defaults to all 8.

## `occurredAfter` (type: `string`):

Only incidents that occurred on or after this date (YYYY-MM-DD).

## `occurredBefore` (type: `string`):

Only incidents that occurred on or before this date (YYYY-MM-DD).

## `crimeAgainst` (type: `array`):

NIBRS crime-against axis. Four sources publish this directly; for the rest it is derived from offence text and flagged as such in crime\_against\_source.

## `publishedClassificationOnly` (type: `boolean`):

Restrict to records where the agency itself states the crime-against bucket, excluding our derived inferences. Use this when publishing statistics. Limits results to Seattle, Dallas, King County and Montgomery County.

## `severity` (type: `array`):

Only New York City publishes felony/misdemeanor/violation directly. NIBRS sources report Group A/B instead. Most records are UNKNOWN.

## `arrestsOnly` (type: `boolean`):

Only Chicago publishes an arrest flag; this excludes every other source.

## `requireCoordinates` (type: `boolean`):

Excludes Austin, Dallas and King County, which publish no coordinates.

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

Excludes Austin, San Francisco and NYC, which publish no address. Note most sources blur to block level by design.

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

Case-insensitive substring match across the record's text fields.

## `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",
    "seattle",
    "montgomery_md"
  ],
  "occurredAfter": "2026-01-01",
  "publishedClassificationOnly": false,
  "arrestsOnly": false,
  "requireCoordinates": 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",
        "seattle",
        "montgomery_md"
    ],
    "occurredAfter": "2026-01-01",
    "maxResults": 1000
};

// Run the Actor and wait for it to finish
const run = await client.actor("formal_sadness_xvx/us-crime-incidents").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",
        "seattle",
        "montgomery_md",
    ],
    "occurredAfter": "2026-01-01",
    "maxResults": 1000,
}

# Run the Actor and wait for it to finish
run = client.actor("formal_sadness_xvx/us-crime-incidents").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",
    "seattle",
    "montgomery_md"
  ],
  "occurredAfter": "2026-01-01",
  "maxResults": 1000
}' |
apify call formal_sadness_xvx/us-crime-incidents --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

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