AccessScore: Spotlight API #
The AccessScore: Spotlight API returns the highest- and lowest-scoring neighborhoods, or streets, in Pittsburgh, PA — the feed behind the AccessScore Spotlight module on the home page and on /cities. It answers from a snapshot written once a night, at the end of the label-clustering run, so asking for it never sets a whole city's AccessScore recomputing.
This endpoint returns JSON only. It is a page feed rather than a data export: the scores it ranks are downloadable in every format from the AccessScore: Regions API and the AccessScore: Streets API.
One method, not the method. There is no single correct way to measure street- and neighborhood-level accessibility. AccessScore implements one experimental algorithm, and a ranking built on it reflects what volunteers have found so far rather than an official assessment. Read qualifying and total alongside the lists: in most cities only part of the map has enough data to be ranked at all.
Endpoint#
GET /v3/api/accessScoreSpotlight
Examples#
/v3/api/accessScoreSpotlight The top and bottom 5 neighborhoods in this city
/v3/api/accessScoreSpotlight?unit=streets The top and bottom 5 streets
/v3/api/accessScoreSpotlight?unit=regions&n=10 Ten rows in each list
/v3/api/accessScoreSpotlight?scope=cities The same ranking across every publicly launched Project Sidewalk city
What gets ranked#
A score only describes the part of a place that volunteers have actually looked at, so a unit has to clear a bar before it is ranked anywhere.
- Neighborhoods need a score and at least
min_completionof their street length explored — the same distance-based completion the home page's choropleth colors, published asmin_region_completionby the AccessScore configuration. The AccessScore tool applies the same floor, so the two can never disagree about who is ranked. - Streets are grouped by OSM way within a neighborhood, because a street edge is one block of a way and a list of edges would print the same street name a dozen times. Each row is that named stretch: its score is the length-weighted mean of its explored edges, and its
street_edge_idis the longest edge in the group. A stretch is ranked once it has been explored, is at least 100 m long, and carries either three or more label clusters or none at all — a confirmed absence of problems is a finding, while one or two clusters on a long street says little either way.
Streets that score alike are ordered by how many validations their labels have received (the best-checked first), then by a random number drawn once per nightly run, so a list of equal scores stays in one order for the day rather than reshuffling between two page loads.
Query Parameters#
All parameters are optional.
| Parameter | Type | Description |
|---|---|---|
unit |
string |
What to rank: regions (default) or streets. |
n |
integer |
How many rows each list holds, 1–25. Default: 5. |
scope |
string |
cities ranks across every publicly launched Project Sidewalk deployment and stamps each row with the city it came from. Omitted, the ranking covers this city alone. |
Responses#
Success Response (200 OK)#
{
"unit": "regions",
"min_completion": 0.8,
"min_street_length_m": 100,
"highest_min_score": 0.5,
"lowest_max_score": 0.5,
"qualifying": 66,
"total": 79,
"computed_at": "2026-09-16T03:14:22Z",
"top": [
{
"region_id": 281,
"name": "Capitol Hill",
"score": 0.842,
"completion_rate": 0.97,
"audited_distance_m": 128411.2,
"total_distance_m": 132382.7,
"cluster_count": 6120
}
],
"bottom": [
{
"region_id": 304,
"name": "South Park",
"score": 0.313,
"completion_rate": 0.88,
"audited_distance_m": 41220.7,
"total_distance_m": 46841.7,
"cluster_count": 1493
}
],
"nearest": []
}
Field Descriptions #
| Field Path | Type | Description |
|---|---|---|
unit | string | Which unit was ranked: regions or streets. |
min_completion | number | The share of a neighborhood's street length that must be explored before it is ranked, in [0, 1]. |
min_street_length_m | number | The length a stretch of street must reach before it is ranked, in meters. |
highest_min_score | number | The score a ranked unit needs to appear in top, in [0, 1]. |
lowest_max_score | number | The score a ranked unit must be under to appear in bottom, in [0, 1]. The two lists never overlap; a unit between the two bars, if they differ, is in neither. |
qualifying | integer | How many units cleared every bar and are therefore ranked. |
total | integer | How many units the city has in all. |
computed_at | string | The nightly run that produced these rows, as the timestamp it stamped on every row it wrote (ISO 8601). null before the first run. Under scope=cities this is the oldest of the contributing cities' runs, so it is true of every row rather than only the freshest one. |
top | array | With n or more units ranked: the best of those scoring at least highest_min_score, best first — fewer than n rows when fewer clear it, and empty when none does. With fewer than n ranked there is no highest-and-lowest to show, so this holds every ranked unit, best first. |
bottom | array | With n or more units ranked: the worst of those scoring under lowest_max_score, worst first; empty otherwise. Never overlaps top. |
nearest | array | Neighborhoods closest to the completion floor, best-explored first — the "help the next one across the line" list. Populated only when fewer than n units qualify, and only for unit=regions without scope=cities; empty otherwise. |
Neighborhood Row #
| Field Path | Type | Description |
|---|---|---|
region_id | integer | Project Sidewalk's identifier for the neighborhood. |
name | string | The neighborhood's name. |
score | number | Its AccessScore in [0, 1]; null when none of its streets has been explored (only ever seen in nearest). |
completion_rate | number | The share of its street length explored, in [0, 1]. |
audited_distance_m | number | How much of that street length has been explored, in meters. |
total_distance_m | number | Its whole street length in meters — the neighborhood's size, which the module prints under the name so a score can be weighed against it. |
cluster_count | integer | How many label clusters the score is built from, on its streets and at its intersections: the evidence behind the number. |
Street Row #
| Field Path | Type | Description |
|---|---|---|
osm_way_id | integer | The OSM way the stretch belongs to. |
street_edge_id | integer | The longest street edge in the group, which is what the AccessScore tool's ?sel= opens on. |
region_id | integer | The neighborhood the stretch lies in. |
region_name | string | That neighborhood's name. |
name | string | The way's OSM name; null for an unnamed way. |
score | number | Length-weighted AccessScore of its explored edges, in [0, 1]. |
length_m | number | The whole stretch's length in meters, explored or not. |
cluster_count | integer | Scored label clusters along it, the evidence behind the score. |
validation_count | integer | Validations cast on its labels. |
Cross-city Rows #
With scope=cities, every row additionally carries city_id, city_name, and city_url — the deployment it came from and its public address. Only publicly launched cities are listed, and qualifying and total are the sums across them.
Error Responses#
400 Bad Request: An unknownunit, or annoutside 1–25.500 Internal Server Error: An unexpected error occurred on the server.
Error Response Body #
All errors are returned as RFC 7807 “problem details” with the application/problem+json content type and the following structure:
{
"type": "about:blank", // RFC 7807 problem-type URI ("about:blank" means no type beyond the status)
"title": "Invalid Parameter", // Short, human-readable summary of the problem type (stable for a given code)
"status": 400, // HTTP status code (also repeated in the body)
"detail": "Invalid value for the bbox parameter. Expected format: minLng,minLat,maxLng,maxLat.", // This occurrence
"code": "INVALID_PARAMETER", // Stable, machine-readable error code you can branch on
"parameter": "bbox" // Extension member: the specific parameter at fault (omitted when not applicable)
}
Best Practices#
- Print
qualifyingoftotalbeside the lists. A top five drawn from six ranked neighborhoods means something quite different from one drawn from sixty. - Say when it was computed. These rows change once a night, so a label placed today moves them tomorrow —
computed_atis what tells a reader that. - Drill down: use the AccessScore: Regions API and AccessScore: Streets API for the full, unranked scores and the per-type breakdowns behind them.
Contribute#
Project Sidewalk is an open-source project created by the Makeability Lab and hosted on GitHub. We welcome your contributions! If you found a bug or have a feature request, please open an issue on GitHub.
You can also email us at sidewalk@cs.uw.edu
Project Sidewalk in Your City!#
If you are interested in bringing Project Sidewalk to your city, please read our Wiki page.