Philadelphia L&I - Code Violations, Inspections & Complaints avatar

Philadelphia L&I - Code Violations, Inspections & Complaints

Pricing

from $0.03 / 1,000 philadelphia l&i code case records

Go to Apify Store
Philadelphia L&I - Code Violations, Inspections & Complaints

Philadelphia L&I - Code Violations, Inspections & Complaints

Philadelphia L&I enforcement records (public open data, 5.2M rows, three linked tables): violation notices, inspector visit outcomes and resident complaints, with violation code and title, case status, dates, address, owner, parcel and geocode.

Pricing

from $0.03 / 1,000 philadelphia l&i code case records

Rating

0.0

(0)

Developer

Wenhao Yang

Wenhao Yang

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

The enforcement record of the Philadelphia Department of Licenses & Inspections: 5,200,849 rows across three linked tables from the City's current L&I system, spanning 2007 to today.

L&I is the City's building-code and property-maintenance enforcement arm. A case moves through three stages, and this actor carries all three rather than making you buy them separately or guess which one answers your question:

Record setRowsWhat it is
violations2,019,604The notices themselves - what was cited, under which code, and what happened
investigations2,117,950Inspector visits and their outcomes - passed, failed, closed
complaints1,063,295What a resident reported, and what came of it

All three are keyed on the case number, so a violation and its inspections share an identifier.

Low cost

From $0.00005 per record, down to $0.00003 at Gold Pay-per-event: you are charged per record delivered, and nothing for the query.

What you get

FieldMeaning
caseNumberThe L&I case. Links a violation to its inspections
violationCode / violationCodeTitleWhat was cited - the code and its plain-English title (99.9% populated)
violationStatus / caseStatusWhere it stands. Violations: COMPLIED 1,571,553 / CLOSEDCASE 124,309 / CLOSED 102,698 / OPEN 93,150 plus 10 more
caseTypeNOTICE OF VIOLATION 621,558 / SITE VIOLATION NOTICE 21,279 / WARNING 1,492 and 3 more
violationDate / caseCreatedDate / violationResolutionDate / mostRecentInvestigationThe dates, from 2007-01-01 forward
investigationType / investigationStatus / investigationCompletedThe inspector's visit - HCEU INSP 677,596 / PRECOURT 142,381 / CSUINITIAL 131,904 and 66 more types; outcomes FAILED 1,273,492 / PASSED 565,376 / CLOSED 261,849
complaintCode / complaintCodeName / complaintDate / complaintStatusThe complaint - MAINTENANCE RESIDENTIAL 169,545 / COMMUNITY LIFE IMPROVEMENT PROGRAM 84,181 / PROPERTY MAINTENANCE COMPLAINT EXTERIOR 79,769 and 134 more
ticket311The linked Philly311 ticket, where one exists
underAppeal / publicNotice / caseResponsibility / unitResponsibleCase handling
address / zip / censusTract / councilDistrictThe property
opaOwner / opaAccountNumber / parcelIdOwner of record, OPA account and parcel
latitude / longitude / jobIdCoordinates and the L&I system's job id

Modes

  • rows (default) - records of the chosen corpus matching your filters.
  • aggregate - one count row per group, with the dimensions that record set actually has.

Example inputs

Every inspection under one case - caseNumber is the number that links a violation to the inspections it produced.

{ "corpus": "investigations", "caseNumber": "CF-2026-073037" }

Notices where the case is still in violation - caseStatus is available on the violations and complaints record sets.

{ "corpus": "violations", "caseStatus": "IN VIOLATION", "maxResults": 25 }

Complaints filed in one ZIP - corpus picks the record set; each one carries its own filters.

{ "corpus": "complaints", "zip": "19139", "maxResults": 25 }

What neighbours complain about - one count per complaint code on the complaints record set.

{ "corpus": "complaints", "mode": "aggregate", "groupBy": "complaintCode" }

Fail the inspection, then check the notice - status filters the investigations record set; the case number then resolves against corpus=violations.

{ "corpus": "investigations", "status": "FAILED" }

How cases end in one district - councilDistrict is available on the violations record set; district 5 holds 96,107 violation rows.

{ "corpus": "violations", "councilDistrict": 5, "mode": "aggregate", "groupBy": "caseStatus" }

Filters and groupings are per record set

The three tables have genuinely different columns, and this actor does not paper over that. A filter that does not exist on the record set you chose is rejected with an error rather than quietly ignored - so you never receive unfiltered rows believing you had filtered them.

The clearest case: councilDistrict is populated on the violations (640,943 rows) and complaints (415,435) tables, and the investigations table has the column but every single one of its 2,117,950 rows is empty. Filtering on it there would return zero rows and read as "no cases in that district", which is the wrong conclusion. It is refused on that record set instead.

Complaints do not always become cases

caseNumber is populated on only 27.3% of complaints, and complaintStatus on 39.2%. Most complaints are resolved without ever opening an L&I case, so the case number is a partial link across the three tables, not a guarantee. Joining the complaints table to the violations table on case number is correct where a case number exists and meaningless where it does not.

The old L&I tables are still online - do not use them

Two similarly-named services from L&I's previous system, LI_VIOLATIONS (1,451,562 rows) and LI_PERMITS (1,051,902 rows), remain published. Both are frozen in March 2020: LI_VIOLATIONS holds nothing after 2020-03-12, and 2020 carries only 18,090 rows against 108,346 in 2017, 117,090 in 2018 and 121,805 in 2019. They are retired legacy that the City has not taken down.

This actor reads the live tables. If you have seen those older services and wondered why they stopped, that is why.

Example output

One complaint - corpus=complaints, zip=19139 returns records like this one:

{
"platform": "philly-li-violations",
"source": "philadelphia-licenses-inspections",
"mode": "rows",
"groupKey": "",
"groupCount": "",
"groupBy": "",
"corpus": "complaints",
"address": "38 S 54TH ST",
"addressObjectId": "15486788",
"caseCompletedDate": "",
"caseCreatedDate": "",
"caseNumber": "",
"casePriority": "",
"caseResponsibility": "",
"caseStatus": "",
"caseType": "",
"censusTract": "008500",
"complaintCode": "WNP",
"complaintCodeName": "WORK UNDERWAY WITHOUT PERMITS",
"complaintDate": "2026-09-22",
"complaintNumber": "CM-2026-129370",
"complaintResolutionDate": "",
"complaintStatus": "IN REVIEW",
"councilDistrict": "3",
"initialInvestigationDate": "",
"investigationCompleted": "",
"investigationProcessId": "",
"investigationStatus": "",
"investigationType": "",
"jobId": "",
"latitude": "2675079.99501881",
"longitude": "238159.5386170289",
"mostRecentInvestigation": "",
"opaAccountNumber": "603147400",
"opaOwner": "SAAT CAPITAL INVESTMENTS LLC",
"parcelId": "200870",
"publicNotice": "",
"systemOfRecord": "ECLIPSE",
"ticket311": "",
"underAppeal": "",
"unit": "",
"unitResponsible": "CONSTRUCTION COMPLAINT INVESTIGATOR",
"unitType": "",
"violationCode": "",
"violationCodeTitle": "",
"violationDate": "",
"violationNumber": "",
"violationResolutionCode": "",
"violationResolutionDate": "",
"violationStatus": "",
"zip": "19139-3311",
"sourceUpdatedAt": "2026-09-23"
}

corpus=complaints, mode=aggregate, groupBy=complaintCode - one row per group:

MR 169,545
VL 100,484
CP 84,181
PME 79,769
BC 59,622

Source

Counts below are a live snapshot - the layers are edited continuously, so exact figures move between reads. The order of magnitude and the ratios are stable.

City of Philadelphia, Department of Licenses & Inspections, published on the City's ArcGIS open-data service as VIOLATIONS, CASE_INVESTIGATIONS and COMPLAINTS - public open data, no login and no key.

Output

Every record carries the same key set regardless of mode or record set - the fields above plus corpus, and the aggregate columns (groupKey, groupCount, groupBy), which are "" outside aggregate mode. Fields that belong to another record set are "" rather than absent, so the schema is stable across all three. Every record carries sourceUpdatedAt, the date the City last edited that layer.

  • Philadelphia Building Permits - the permits these violations are raised against.
  • Philly311 Service Requests - the resident reports that feed the complaints table.