SafeRoute NYC
Inspiration
We both ran track in high school, and one of us kept running through college in Indiana before moving here. We still want our daily runs, we just don't know every block of this city yet.
That hesitation is the whole problem. Running a familiar loop back home is nothing like running somewhere new after dark. It's why a lot of people never start.
The strange part is that the city already knows where the risk is. Every injury crash, every street robbery, every flooded block is public, timestamped and mapped. It just isn't in anyone's directions.
- A New Yorker is hurt in a traffic crash every 11 minutes
- Manhattan below 96th logs about 25 street robberies and assaults a day — and 42% of the robberies happen between 10 PM and 4 AM
- Nearly 90,000 Manhattan residents live in areas exposed to major coastal flooding, and floodwater carries sewage, bacteria and debris
What it does
Tell it where you're going. It draws two lines — the fastest way, and the safer way — with one sentence saying why:
"211 m further, avoiding 4 blocks with a history of street robberies and assaults and 5 blocks that flood in rain like this."
It flags specific blocks, not neighborhoods. It's a data signal about one stretch of one street, never a judgment about where anyone lives.
You can share a walk, too. Drift off your route or hit SOS, and your trusted contact gets your last known location.
How we built it
We score the whole city before anyone asks for a route. Every source is public:
- Motor Vehicle Collisions – Crashes (NYC Open Data) — 2.27M crashes since 2012. We score 2022 onward and only the ones that hurt somebody, weighted so a pedestrian death counts most.
- NYPD Complaint Data Historic — 10.07M reports since 2006. We keep only outdoor offences against a person from 2022 on: 37,340 of them.
- FloodNet: Street Flooding Events — 2,929 flood events actually measured by 294 street sensors, weighted by how often and how deep each spot floods.
- OpenStreetMap, via OSMnx — the walkable street network itself: 35,806 intersections and 110,220 segments.
- Open-Meteo — live rainfall, read separately for each borough.
Every record is snapped to its nearest walkable segment, so all 110,220 blocks end up carrying three independent risk scores.
After that, routing is just A* over a map where risky blocks cost more to cross:
$$\text{cost} = \text{length} \times (1 + 3 \cdot \text{crash} + 2 \cdot \text{crime} + 3 \cdot \text{flood} \cdot \text{raining})$$
Rain is live and per borough. On a dry night the flood term is exactly zero, so we never reroute you around weather that isn't happening.
Stack: Next.js · MapLibre · FastAPI · Supabase + PostGIS · Open-Meteo · Resend
Challenges we ran into
Most crime isn't street crime. 58% of NYPD complaints happened inside a building, mostly apartments. Scoring those onto the sidewalk would route people around other people's homes. Cutting down to outdoor offences against a person took 1.87M rows to 37,340.
We ran out of colors. With three hazards and three routes on one dark map, every purple we tried was indistinguishable from the flood blue for colorblind users. We measured it instead of trusting our eyes, then made the crime layer much lighter — and a soft glow rather than a line, since those reports are only accurate to the block.
Our own demo broke. Adding crime changed the safest route enough that our saved rain-vs-dry example stopped showing any difference. Now we re-pick that example automatically whenever the scoring changes.
What we learned
The hard part was deciding what not to use. No indoor incidents. No property crime. No flood penalty on a dry day. And no AI writing the explanation — that sentence is built from the two routes themselves, because a made-up reason in a safety app is worse than no reason at all.
We also learned that crime reports reflect policing as much as harm. That's why crime counts for less than crashes in our math: a crash is recorded where it actually happened, while a complaint is recorded to the middle of a block.
What's next
The rest of the five boroughs, SMS alongside email, and time-of-day weighting now that we know robbery is a night problem.
Built With
- carto
- fastapi
- framer-motion
- geojson
- geospatial
- httpx
- maplibre
- networkx
- next.js
- nominatim
- open-meteo
- openstreetmap
- osmnx
- pandas
- postgis
- postgresql
- psycopg2
- python
- react
- resend
- supabase
- tailwindcss
- typescript
- uvicorn

Log in or sign up for Devpost to join the conversation.