To populate the Minneapolis Crime Map, Glass on the Street, I’m parsing data directly from the city of Minneapolis' ArcGIS API. The city provides API access to all of their crime data as well as a bunch of other public city data free of charge without the need for API keys or tokens. All the data is made available from a service called ArcGIS.
Try it out right here. See the last seven days of crime data from the city of Minneapolis
This crime data is part of a larger data set from the city that's publicly available on their Open Data Portal and the API data uses their ArcGIS map service. The base URL for Minneapolis crime data is:
https://services.arcgis.com/afSMGVsC7QlRK1kZ/arcgis/rest/services/Crime_Data/FeatureServer/0/
Each part of the URL is an identifier to the city’s crime data in the ArcGIS system and it goes like this:
afSMGVsC7QlRK1kZis the city’s identifier to tell ArcGIS what organization the request is aboutCrime_Dateis the service offered or requestedFeatureServer/0means it’s the first layer of the service
This data comes to the city from the police department. The format is the FBIs National Incident-Based Reporting System(NIBRS) standard. More about the NIBRS standard here. For the MPLS crime stats the data begins back on January 01, 2019 and goes through the present day.
Query
The REST API is set up as query system using a where clause to filter data from the known columns. For Glass on the Street crimes are filtered where the Occurred_Date is in the last seven days. I use the last seven days because the crime stats can be updated after they are posted as well as back dated. So getting the last week allows me to go over the existing dataset to update anything new/updated that comes through. This is also where you can filter by crime type or any other property in the fields list - more on that in the API Explorer.
My full query is here:
https://services.arcgis.com/afSMGVsC7QlRK1kZ/arcgis/rest/services/Crime_Data/FeatureServer/0/query?where=Occurred_Date >= TIMESTAMP '2026-10-16 05:00:00' AND Occurred_Date < TIMESTAMP '2026-10-23 05:00:00'&outFields=Case_Number,Address,Occurred_Date,Offense,Offense_Category,Type,Neighborhood,Ward,Precinct,wgsXAnon,wgsYAnon,NIBRS_Code,NIBRS_Crime_Against,Crime_Count&returnGeometry=false&orderByFields=Occurred_Date ASC,OBJECTID ASC&resultOffset=0&resultRecordCount=1000&f=json
Query parameters
| Parameter | What it does |
|---|---|
where |
A SQL-style filter, such as a date range on Occurred_Date. where=1=1 means "no filter." |
outFields |
The columns to return. |
returnGeometry |
Set to false to skip the geometry object. The coordinates are already in wgsXAnon and wgsYAnon. |
orderByFields |
Sort order. Adding OBJECTID as a tiebreaker keeps paging stable. |
resultOffset |
The row to start from. Add the page size for each following page. |
resultRecordCount |
Rows per page. Stop when a page returns fewer than this. |
f |
The response format, such as json. |
Fields
| Field | What it is |
|---|---|
Case_Number |
MPD's case ID. |
Occurred_Date |
When the offense happened, in epoch milliseconds (UTC). |
Offense |
MPD's offense name. |
Offense_Category |
The broader NIBRS category. |
Type |
Separates offenses from other record types, such as shots-fired calls. |
NIBRS_Code |
The FBI's NIBRS offense code. |
NIBRS_Crime_Against |
Whether the offense is against a person, property or society. |
Crime_Count |
MPD's offense count for the row. |
Neighborhood |
City neighborhood. |
Ward |
City council ward. |
Precinct |
MPD precinct. |
Address |
Block-range address, not an exact one. |
wgsXAnon |
Anonymized block-midpoint X coordinate, in Web Mercator meters. |
wgsYAnon |
Anonymized block-midpoint Y coordinate, in Web Mercator meters. |
Results
Based on the query above, the response is a JSON object with an array of different crimes that include all the fields that were part of the request body;
{
"exceededTransferLimit": true,
"features": [
{
"attributes": {
"Case_Number": "26-716709",
"Address": "0015XX LAUREL AVE",
"Occurred_Date": 1792129500000,
"Offense": "Destruction/Damage/Vandalism of Property ",
"Offense_Category": "Destruction/Damage/Vandalism of Property ",
"Type": "Crime Offenses (NIBRS)",
"Neighborhood": "Lowry Hill",
"Ward": 7,
"Precinct": 4,
"wgsXAnon": -10384426.0039823,
"wgsYAnon": 5617428.35059222,
"NIBRS_Code": "290",
"NIBRS_Crime_Against": "Property ",
"Crime_Count": "1"
}
},
{
"attributes": {
"Case_Number": "26-299753",
"Address": "0004XX 1ST AVE NE",
"Occurred_Date": 1792132500000,
"Offense": "Theft of Motor Vehicle Parts or Accessories ",
"Offense_Category": "Larceny/Theft Offenses ",
"Type": "Crime Offenses (NIBRS)",
"Neighborhood": "Nicollet Island - East Bank",
"Ward": 3,
"Precinct": 2,
"wgsXAnon": -10381091.0865404,
"wgsYAnon": 5619907.02006897,
"NIBRS_Code": "23G ",
"NIBRS_Crime_Against": "Property ",
"Crime_Count": "1"
}
}
]
}
How we parse it
For Glass on the Street, the data is parsed into a DTO object in C# and then saved to a MySQL database.
Occurredis in epoch-millisecond time format, which is then parsed to central US time.- Offense is used as our category primary key.
wgsXAnonandwgsYAnonare used to place the crime on the map. The data is anonymous and will be set to the middle of the block. If you look atAddressit is also an anonymous address that snaps to the block level and not the individual building or house.Case_numberrefers back to the MPD case file. I don't do anything with this number but I could see it being useful for references in other applications
Revised data
Records post to this API get posted late (days after the crime occurred) and are updated frequently. Sometimes data for the previous day(s) will come back empty. That's because the city has not yet posted data for those days but they will show up eventually.
I found this API because I built Glass on the Street because my car windows kept getting smashed and I wanted a tool to track this type of crime.
Try it yourself and change some of the parameters like Occurred_Date or Offense. To only return car related crimes, change the Offense query to look like this:
(Offense LIKE '%Theft From Motor Vehicle%'
OR Offense LIKE '%Theft of Motor Vehicle Parts or Accessories%'
OR Offense LIKE '%Motor Vehicle Theft%'
OR Offense LIKE '%Destruction/Damage/Vandalism of Property%')