How-to
How to run Code Violation Leads: Property Owners, Fines & Violation Types
Step-by-step: the exact input, what each field does, and the rows that come back from City open data (PHL, Detroit, Chicago, Mesa, NYC).
You open this actor when you want a list of properties a city has cited, and the name and mailing address of whoever owns each one. Philadelphia, Detroit, Chicago, Mesa and New York City all publish their violations as open data, but each in its own format, and only Detroit puts the owner’s mailing address on the violation. Everywhere else the owner sits in a second dataset, the county or city property roll (Philadelphia’s has 583,717 parcels), and you join the two yourself by parcel number or address. This guide runs the export the listing uses as its example: open weed violations in Philadelphia from the last 30 days where the owner mails from somewhere else.
What you’ll need
Nothing but an Apify account. The actor talks to City open data (PHL, Detroit, Chicago, Mesa, NYC) directly.
No API key and no proxy. All five feeds and the four owner sources (the Philadelphia OPA roll, the Maricopa and Cook County Assessors, NYC MapPLUTO) answer plain requests with no login, so the run uses nothing you pay for beyond the per-row price.
Step 1 — Open the actor
Open Code Violation Leads: Property Owners, Fines & Violation Types on the Apify Store and press Try for free. The actor’s own page on this site lists its live health and pricing.
Step 2 — Fill in the input
| Field | Type | Required | What it does |
|---|---|---|---|
mode | string | no | Export: every violation in the cities you pick that matches your filters (dates, violation type, ZIP, owner). Lookup: the violation history of the addresses, parcel numbers or… (default export) |
cities | array | no | Which cities to search. Each city is its own open-data feed. One per line: philadelphia (Philadelphia, PA); detroit (Detroit, MI); chicago (Chicago, IL); mesa (Mesa, AZ);… (default []) |
city | string | no | One city, for saved tasks and API calls that send a single value. Use Cities above for several. |
lookups | array | no | One per line: a street address (1251 N 17th St), a parcel number (Philadelphia OPA account, Detroit parcel ID, Mesa APN, NYC BBL) or an owner’s name (Philadelphia and Detroit… (default []) |
lookup | string | no | One address, parcel number or owner name, for saved tasks and API calls that send a single value. |
lastDays | integer | no | Violations from the last N days. Empty: the last 30 days in export mode, all time in lookup mode. 0 means all time (large cities hold millions of rows: New York City added… |
dateFrom | string | no | YYYY-MM-DD, inclusive. Overrides ‘Last N days’. |
dateTo | string | no | YYYY-MM-DD, inclusive. Empty means up to today. |
categories | array | no | Keep only violations of these types (matched on the violation’s own wording). Empty means every type. One per line: lawn_weeds (Weeds, grass & overgrowth); trash_junk (Trash,… (default []) |
keywords | array | no | Keep only violations whose description contains any of these words (e.g. sprinkler, demolition). Combined with Violation types: both must match. (default []) |
zips | array | no | Keep only these 5-digit ZIP codes. Chicago’s feed has no ZIP, so there it comes from the matched property record and rows without an owner match are left out. (default []) |
status | string | no | Open (still unresolved), closed (complied or dismissed) or any. Empty: open in export mode, any in lookup mode. |
includeUnfounded | boolean | no | Mesa records complaints an inspector found to be no violation, and duplicates; they are left out unless this is on. |
unpaidOnly | boolean | no | Only tickets with a balance due. Detroit is the city that publishes balances; other cities are skipped with a note when this is on. |
propertyTypes | array | no | Keep only these property types, from the property record (Philadelphia and New York City publish it). Rows with no type known are left out when this is set. One per line:… (default []) |
ownerTypes | array | no | Keep only owners of these kinds, read from the owner’s name. One per line: individual (Individual); company (Company (LLC, Inc…)); trust (Trust or estate); government… (default []) |
absenteeOnly | boolean | no | Only owners whose mailing address is somewhere other than the property (another state, another city, or another address in the same city). |
withOwnerOnly | boolean | no | Leave out violations the actor could not match to an owner. |
groupBy | string | no | Violation: one row per violation. Property: one row per address, with its violation count, types and the list of violations. Owner: one row per owner, with how many properties… (default violation) |
minViolations | integer | no | With one row per property or owner: keep only those with at least this many violations in the date range. (default 1) |
maxResults | integer | no | Cap for EACH city (and each lookup). Rows are newest first; with one row per property or owner, the most-cited come first. (default 1000) |
Two fields decide most of what comes back. lastDays (or dateFrom / dateTo) sets the window: leave it empty in export mode and you get the last 30 days; set it to 0 and you get everything the city has ever published, which in New York City meant 15,035 rows for a single week on 2026-11-01. maxResults is a cap per city, not per run, so three cities at 1,000 can return 3,000 rows. Then categories narrows by what is wrong with the property: lawn_weeds matches Philadelphia’s “EXTERIOR AREA WEEDS”, Detroit’s “Excessive weeds or plant growth” and Chicago’s “CUT OR REMOVE HIGH WEEDS” alike. status defaults to open in export mode and to any status in lookup mode.
Lookup mode answers the other question. Set mode to lookup, keep cities, and put street addresses, parcel numbers or owner names in lookups. Owner-name search works in Philadelphia and Detroit, the two feeds that carry the owner on the violation.
A working input:
{
"cities": [
"philadelphia"
],
"lastDays": 30,
"categories": [
"lawn_weeds"
],
"absenteeOnly": true,
"maxResults": 100
}
Step 3 — Run it
Press Start. Rows are pushed to the dataset as they’re found, so the run log fills in as it works.
Without the 100-row cap, the input above returned 864 violations on 2026-11-01. The whole of Philadelphia’s open violations for the same 30 days was 8,571 rows in 14 seconds, measured outside Apify through one proxy. Our first run on Apify, a three-row Philadelphia sample from a test account, finished in 9 seconds. If a run comes back with a single “no_match” row, nothing matched the filters in that window: widen the dates or drop a type. A “blocked” row names the city whose feed did not answer, and you are not charged for it.
Step 4 — Read the output
Each run returns a labelled table, not raw JSON:
Every row looks like this — a real row from a real run:
{
"city": "Philadelphia",
"state": "PA",
"violation_id": "VI-2026-091859",
"case_number": "CF-2026-147729",
"violation_date": "2026-10-30",
"status": "open",
"status_detail": "OPEN / IN VIOLATION",
"categories": [
"lawn_weeds"
],
"violation_code": "PM15-302.4",
"violation_description": "EXTERIOR AREA WEEDS",
"severity": "STANDARD",
"department": "CLIP - VACANT LOT INVESTIGATOR",
"address": "1531 W FLORA ST",
"zip": "19121",
"parcel_id": "471033600",
"property_type": "vacant_land",
"owner_name": "DAVIDS CONSTRUCTION LLC",
"owner_type": "company",
"owner_mailing_address": "723 MARTENS LANE",
"owner_mailing_city": "SPRINGFIELD",
"owner_mailing_state": "PA",
"owner_mailing_zip": "19064",
"absentee": "out_of_city",
"absentee_basis": "mails to SPRINGFIELD",
"owner_source": "Philadelphia OPA property roll",
"source_url": "https://phl.carto.com/api/v2/sql?q=SELECT+%2A+FROM+violations+WHERE+violationnumber+%3D+%27VI-2026-091859%27",
"source_dataset": "https://opendataphilly.org/datasets/licenses-and-inspections-code-violations/",
"source_fields": {
"casenumber": "CF-2026-147729",
"casetype": "NOTICE OF VIOLATION",
"violationcodetitle": "EXTERIOR AREA WEEDS",
"violationstatus": "OPEN",
"opa_account_num": "471033600",
"opa_owner": "DAVIDS CONSTRUCTION LLC"
}
}
| Field | Example value | Meaning |
|---|---|---|
city | Philadelphia | The city whose feed the row came from |
violation_id | VI-2026-091859 | The city’s own ID for the violation or ticket |
case_number | CF-2026-147729 | The city’s case, inspection or ticket number |
violation_date | 2026-10-30 | When the violation was cited |
status | open | open, closed or no_violation |
status_detail | OPEN / IN VIOLATION | The city’s own status words |
categories | ["lawn_weeds"] | Violation types matched from the city’s wording (lawn_weeds, trash_junk, roof_exterior…) |
violation_code | PM15-302.4 | The code or ordinance cited |
Most people come for owner_name and the four owner_mailing_* columns. In a 7-day export on 2026-11-01 the owner was on 99% of Philadelphia rows, all of Detroit’s, 97% of Mesa’s and 54% of Chicago’s. Chicago misses are mostly large and condominium buildings: one street address covers several parcels and several owners, so the actor gives none rather than guess. New York City rows carry the owner’s name from MapPLUTO but never a mailing address. absentee compares the two addresses; of those 8,571 open Philadelphia violations, 1,202 had an owner mailing from another state and 1,292 from another city. source_fields keeps every column the city published, under the city’s own names.
Step 5 — Export it
Open the Dataset tab and export to CSV, JSON, or Excel — or pull the same rows from the API, which is what you want if this is going to run on a schedule.
What it costs
$0.004 per violation row. If you ask for one row per property it is $0.006 per property row, and one row per owner is $0.01 per owner row, however many violations each lists. Owner names and mailing addresses cost nothing extra, and notice rows are free. The example input above, capped at 100 rows, costs $0.40; uncapped it was 864 rows, $3.46. All 8,571 open Philadelphia violations from 30 days would be $34.28, so set maxResults to what you want to spend.
Where the data comes from
This reads City open data (PHL, Detroit, Chicago, Mesa, NYC) directly. The target is Keyless open-data APIs: Socrata SODA (Chicago, Mesa, New York City), Carto SQL (Philadelphia) and an ArcGIS FeatureServer (Detroit), filtered at the source. Owners are joined in batches from the Philadelphia OPA roll, the Maricopa and Cook County Assessors and NYC MapPLUTO; Detroit’s tickets carry the owner. Every night a canary runs this actor against that live source and diffs the result against a frozen fixture — what “verified” means.
Each city’s feed is free, and Philadelphia’s even offers yearly CSV downloads. The work is everything around it: three query languages (Socrata, Carto and ArcGIS), status words that differ by city (Philadelphia’s “SVN ISSUED” is open, Mesa’s “No Violation” is a complaint that turned out to be nothing), and an owner that lives in a different dataset, found by parcel number in Philadelphia, Mesa and New York City and by street address in Chicago.
See it used
Open code violations in Philadelphia with property owners turns a month of open violations into a mailing list for a property-services business.
If you want every absentee-owned property in a county, cited or not, with assessed values and sale history, US County Property Records Export reads the assessor rolls this actor joins against.
Last updated 2026-11-01