Chicago 311 Complaints & Service Requests Scraper
Pricing
from $1.60 / 1,000 311 complaint returneds
Chicago 311 Complaints & Service Requests Scraper
Export Chicago 311 complaints and service requests by date, type, status, ward or ZIP, with addresses and coordinates. About USD 2 per 1,000 records.
Pricing
from $1.60 / 1,000 311 complaint returneds
Rating
0.0
(0)
Developer
Muhammad Afzal
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 hours ago
Last modified
Categories
Share
Chicago 311 Complaints & Service Requests Scraper exports City of Chicago 311 service requests (potholes, graffiti, rats, street lights, noise and every other 311 type) from the City's official open-data portal, with type, status, dates, department, address, ward, community area and coordinates. It is built for civic researchers, journalists, neighborhood groups and operations analysts, and costs about USD 2.00 per 1,000 records on the FREE tier (USD 0.002001 each), charged only for records saved.
No City account, API key or login is needed. The Actor reads the City's unified 311 Service Requests dataset (v6vf-nfxy), which holds records created from July 2018 onward, about 14.9 million in a 2026-10-26 check.
How do I download Chicago 311 service request data?
Set a date range and any filters, choose how many records you want, and run. Each matching request becomes one row you can export as CSV, Excel or JSON, or read through the API. All filters are optional and combine with AND; several values inside one filter combine with OR.
{"maxResults": 500,"startDate": "2026-10-01","endDate": "2026-10-25","serviceRequestTypes": ["Pothole in Street Complaint", "Street Light Out Complaint"],"statuses": ["Open"],"wards": ["42"],"includeDuplicates": false,"sortDirection": "newest"}
| Input | Default | Notes |
|---|---|---|
maxResults | 100 | 1–10,000 records per run; this is also your cost cap |
startDate / endDate | empty | YYYY-MM-DD, applied to the request's created date |
serviceRequestTypes | all | Exact City type names, for example Graffiti Removal Request |
statuses | all | Open, Completed or Canceled |
origins | all | Exact channel names, for example Phone Call, Internet, Mobile Device |
zipCodes / wards / communityAreas | all | Strings: 5-digit ZIPs, wards "1"–"50", community areas "1"–"77" |
serviceRequestNumbers | none | Exact IDs such as SR26-02160725 |
includeDuplicates | false | Keep requests the City marks as duplicates |
sortDirection | newest | newest or oldest by created date |
socrataAppToken | empty | Optional data-portal app token for very large runs; stored as a secret |
Type, status and origin filters must match the City's wording exactly. If a filter returns nothing, run a small unfiltered query first and copy the values from the results.
What data does the Chicago 311 scraper return?
Each record is one 311 service request. Fields the City does not publish for a request are null, never guessed.
| Field | What it means |
|---|---|
serviceRequestNumber | City request ID, for example SR26-02160725 |
serviceRequestType / serviceRequestShortCode | Request type and the City's short code |
status / origin | Workflow status and how the request came in |
createdDate / lastModifiedDate / closedDate | Chicago local timestamps from the City |
createdDepartment / ownerDepartment | Department that opened it and department responsible for it |
streetAddress, streetNumber, streetDirection, streetName, streetType | Published address and its parts |
city / state / zipCode | City, state and ZIP code |
ward / communityArea | City ward (1–50) and community area (1–77) |
policeDistrict / policeBeat | Police geography when present |
latitude / longitude | Coordinates when the City publishes them |
isDuplicate / parentServiceRequestNumber | Duplicate flag and the parent request |
isLegacyRecord / legacyServiceRequestNumber | Records migrated from the City's older system |
sourceDatasetId / sourceUrl / scrapedAt | Source dataset, a query link for the record, and the extraction time |
A run summary goes to the OUTPUT record in the key-value store with the outcome (DATA, EMPTY, REJECTED or FAILED), the filters used, the record count and warnings.
When should you use it, and when not?
Use it to monitor 311 activity in a ward, community area or ZIP code; to compare open and completed requests by type or channel; to look up exact request numbers; or to feed maps and dashboards with geocoded complaint data.
Pick something else when:
- You need building code violations and inspections. Use Chicago Building Violations Scraper.
- You want permit filings as contractor leads. Use Building Permits Scraper.
- You want to file a new 311 request or check one you submitted. Use the City's CHI311 portal or app; this Actor only reads published data.
- You need caller names or contact details. The City does not publish them, and the Actor does not return them.
How do I filter Chicago 311 complaints by ward, ZIP code or type?
Put the values in wards, zipCodes, communityAreas or serviceRequestTypes. For example, every open rat complaint in wards 1 and 32 this month:
{"maxResults": 1000,"startDate": "2026-10-01","serviceRequestTypes": ["Rodent Baiting/Rat Complaint"],"statuses": ["Open"],"wards": ["1", "32"]}
Common types in autumn 2026 included 311 INFORMATION ONLY CALL, Aircraft Noise Complaint, Graffiti Removal Request, Garbage Cart Maintenance, Rodent Baiting/Rat Complaint, Abandoned Vehicle Complaint and Pothole in Street Complaint. Information-only calls and aircraft noise reports often have no ward or coordinates, so add a ward or ZIP filter when you want mappable records.
Call it from code
JavaScript (apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('muhammadafzal/chicago-311-complaints-scraper').call({maxResults: 200,startDate: '2026-10-01',zipCodes: ['60614'],});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.map((i) => [i.serviceRequestNumber, i.serviceRequestType, i.status]));
Python (apify-client):
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("muhammadafzal/chicago-311-complaints-scraper").call(run_input={"maxResults": 200, "startDate": "2026-10-01", "wards": ["42"]})for item in client.dataset(run.default_dataset_id).iterate_items():print(item["serviceRequestNumber"], item["serviceRequestType"], item["ward"])
Add an Apify schedule to refresh a ward or ZIP export daily or weekly.
Use it from an AI assistant
Chicago 311 Complaints & Service Requests Scraper works from Claude, ChatGPT, Cursor or any MCP client through Apify's MCP server. Add https://mcp.apify.com/?tools=muhammadafzal/chicago-311-complaints-scraper as a server, then ask, for example: "Pull the last two weeks of open pothole complaints in ward 42 and list the five streets with the most requests." Set maxResults in the request to keep the answer size and cost predictable.
What does the output look like?
Two records, shortened:
[{"serviceRequestNumber": "SR26-02160725","serviceRequestType": "Graffiti Removal Request","serviceRequestShortCode": "GRAF","status": "Open","origin": "Internet","createdDate": "2026-10-26T06:13:45.000","closedDate": null,"createdDepartment": null,"ownerDepartment": "Streets and Sanitation","streetAddress": "59 S RIVERSIDE PLZ","zipCode": "60606","ward": 42,"communityArea": 28,"policeDistrict": "01","latitude": 41.880667854211,"longitude": -87.638653695165,"isDuplicate": false,"sourceUrl": "https://data.cityofchicago.org/resource/v6vf-nfxy.json?sr_number=SR26-02160725"},{"serviceRequestNumber": "SR26-02160723","serviceRequestType": "Alley Light Out Complaint","status": "Open","origin": "Phone Call","createdDepartment": "311 City Services","ownerDepartment": "CDOT - Department of Transportation","streetAddress": "5816 W RICE ST","zipCode": "60651","ward": 29,"communityArea": 25,"latitude": 41.895954000941,"longitude": -87.771015000002}]
How much does Chicago 311 data cost? Pricing
You pay per saved record plus a start fee. Apify platform usage is included. Empty, rejected and failed runs write no records and pay no record events.
| Event (USD) | FREE | BRONZE | SILVER | GOLD, PLATINUM, DIAMOND |
|---|---|---|---|---|
| 311 complaint returned | 0.002001 | 0.00195 | 0.0019 | 0.0016 |
| Actor start, per started GB of allocated memory | 0.006251 | 0.006094 | 0.005938 | 0.005 |
The default memory is 256 MB, so a run pays one start event.
- Default 100 records, FREE tier: USD 0.006251 + 100 × 0.002001 = USD 0.21.
- 2,000 records a week for a ward, GOLD tier: USD 0.005 + 2,000 × 0.0016 = USD 3.21 per run.
The status message at the start of a run and the resultEventPriceUsd value in OUTPUT show the live record price for your pricing tier.
How fresh is the data, and what are the limits?
The City keeps this dataset current; same-day requests were present in a 2026-10-26 check. Statuses and other fields change as departments work requests, so re-run to refresh. Pages of 1,000 rows are read in created-date order without deep offsets, records are deduplicated by request number, and rate limits and server errors are retried with backoff.
An owner test run returned 100 records in about 12 seconds. Records are saved and charged a page (up to 1,000) at a time, and an owner test of 10,000 records finished in under 30 seconds, inside the 300-second default timeout. If a run nears its timeout, it stops requesting pages, keeps every saved record and says so in the status message and OUTPUT. maxResults is capped at 10,000 per run; split larger exports by date range.
FAQ
Is Chicago 311 data public?
Yes. The City publishes 311 service requests on its open-data portal. This Actor returns only the fields the City publishes, which do not include who made the request.
Do I need an API key or a City account?
No. Public extraction works without one. An optional data-portal app token can raise rate limits for very large runs.
Can I get complaints for one address or street?
There is no address filter. Filter by ZIP code, ward or community area, then filter streetAddress in your spreadsheet or code.
What is the difference between a complaint and a service request?
The City logs both in the same 311 dataset. Types ending in "Complaint" (rats, potholes, noise) sit next to requests such as graffiti removal and garbage cart maintenance; serviceRequestType tells them apart.
Why are some records missing a ward or coordinates?
The City leaves them blank for some types, such as information-only calls and airport noise reports. Those fields come back as null.
Does it include closed requests?
Yes. Leave statuses empty for all records, or set Completed or Canceled.
Related Actors
- Chicago Building Violations Scraper: City of Chicago building code violations.
- Building Permits Scraper: permit filings as contractor leads.
- Colorado, Oregon & Connecticut Business Entity Search: official state business registry records.
- Seattle Restaurant Inspections Scraper: another city open-data export.
Legal and responsible use
This Actor reads public government data. Follow the City of Chicago data portal's terms and attribution rules. Street addresses can be sensitive in aggregate, so keep exports only as long as needed and do not use 311 records to harass, profile or re-identify people. A 311 request is an allegation, not proof that a condition existed. This Actor is not affiliated with or endorsed by the City of Chicago.
Last verified: 2026-10-27