Chicago 311 Complaints & Service Requests Scraper avatar

Chicago 311 Complaints & Service Requests Scraper

Pricing

from $1.60 / 1,000 311 complaint returneds

Go to Apify Store
Chicago 311 Complaints & Service Requests Scraper

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

Muhammad Afzal

Maintained by Community

Actor 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"
}
InputDefaultNotes
maxResults1001–10,000 records per run; this is also your cost cap
startDate / endDateemptyYYYY-MM-DD, applied to the request's created date
serviceRequestTypesallExact City type names, for example Graffiti Removal Request
statusesallOpen, Completed or Canceled
originsallExact channel names, for example Phone Call, Internet, Mobile Device
zipCodes / wards / communityAreasallStrings: 5-digit ZIPs, wards "1"–"50", community areas "1"–"77"
serviceRequestNumbersnoneExact IDs such as SR26-02160725
includeDuplicatesfalseKeep requests the City marks as duplicates
sortDirectionnewestnewest or oldest by created date
socrataAppTokenemptyOptional 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.

FieldWhat it means
serviceRequestNumberCity request ID, for example SR26-02160725
serviceRequestType / serviceRequestShortCodeRequest type and the City's short code
status / originWorkflow status and how the request came in
createdDate / lastModifiedDate / closedDateChicago local timestamps from the City
createdDepartment / ownerDepartmentDepartment that opened it and department responsible for it
streetAddress, streetNumber, streetDirection, streetName, streetTypePublished address and its parts
city / state / zipCodeCity, state and ZIP code
ward / communityAreaCity ward (1–50) and community area (1–77)
policeDistrict / policeBeatPolice geography when present
latitude / longitudeCoordinates when the City publishes them
isDuplicate / parentServiceRequestNumberDuplicate flag and the parent request
isLegacyRecord / legacyServiceRequestNumberRecords migrated from the City's older system
sourceDatasetId / sourceUrl / scrapedAtSource 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 os
from apify_client import ApifyClient
client = 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)FREEBRONZESILVERGOLD, PLATINUM, DIAMOND
311 complaint returned0.0020010.001950.00190.0016
Actor start, per started GB of allocated memory0.0062510.0060940.0059380.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.

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