Project Sidewalk

Welcome back

Project Sidewalk

Join Project Sidewalk

Map sidewalks. Help make your city accessible to everyone.

3–30 characters — letters, numbers, hyphens, and underscores

Pick a nickname — you don't have to use your real name. It's shown publicly on the leaderboard and your profile, and you can change it anytime.

  • At least 8 characters
  • One uppercase letter
  • One lowercase letter
  • One number
Passwords match

AccessScore: Intersections API

Experimental. There is no single correct way to measure whether an intersection is crossable, and this endpoint implements one algorithm: corner features pooled per intersection and weighted deliberately simply. The weights, the field names, and the scoring itself may change as we learn, and because the /v3 API is a preview surface, such changes are made in place rather than under a new version.

Read a score as one lens rather than a verdict, and pin your expectations if you build on it — or compute your own index from the Label Clusters API, whose clusters carry the same intersection_id.

The AccessScore: Intersections API returns an accessibility score in the range (0, 1) for each street intersection — higher is more accessible. Curb ramps, missing curb ramps, crosswalks, and pedestrian signals are corner features, so they are pooled on the intersection they sit at, across every street meeting there, rather than credited to whichever street the labeler happened to walk. The score summarizes what was found at the corners. It does not trace any one crossing from a ramp, over a crosswalk, to the ramp on the far side, so it is not a verdict on whether a particular crossing is passable.

Intersections are derived from Project Sidewalk's own street network: every place three or more streets meet. Bridges and tunnels that only cross a street are marked grade_separated and never scored. See the AccessScore: Streets API for how a street's score combines its own segment with its end intersections.

AccessScore extends the method introduced in Li et al., A Pilot Study of Sidewalk Equity in Seattle (Urban Access 2022).

AccessScore: Intersections Preview

Below is a live preview of intersection AccessScores from a sample region in Knox County, OH, retrieved directly from the API. Each intersection is colored from red (low accessibility) to green (high); gray intersections have no audited street yet, and hollow ones are grade-separated crossings. Hover an intersection to highlight it; click for its score and the corner features that produced it.

One method, not the method. There is no single correct way to measure whether an intersection is crossable — researchers and practitioners use many different approaches. AccessScore implements just one such algorithm, and it is experimental: the weighting is deliberately simple and subject to change. Treat these scores as one lens rather than a definitive measure, and compute your own index from the Label Clusters API if a different method suits your needs better.

Endpoint

Returns an intersection and its AccessScore for each intersection in the queried area, optionally filtered by the Query Parameters below.

GET /v3/api/accessScoreIntersections

Examples

/v3/api/accessScoreIntersections?filetype=geojson Get AccessScores for all intersections in GeoJSON (default)

/v3/api/accessScoreIntersections?filetype=geojson&inline=true Same, but opened in the browser

/v3/api/accessScoreIntersections?filetype=csv Get AccessScores for all intersections in CSV

/v3/api/accessScoreIntersections?regionId=8 Get scores for the intersections in a single region

How the score is computed

Where intersections come from. Project Sidewalk's street network is fully noded: wherever two streets meet, they share an endpoint. An intersection is a group of street endpoints (merged within about a meter) where three or more distinct streets meet; its degree is that count. Two endpoints meeting is a street that was split, not an intersection, and one is a dead end.

Bridges and tunnels. The street network stores a bridge crossing a street as if the two met, so those false intersections are detected from OpenStreetMap's bridge, tunnel, and layer tags: an intersection is grade_separated when two or more of the streets passing through it sit on different layers. A street that merely ends at a bridge abutment is a real intersection. A grade-separated intersection is listed for completeness but never scored, and no cluster is attributed to it.

Which clusters score an intersection. Project Sidewalk clusters proximal labels of the same type. Each cluster of an intersection type — CurbRamp, NoCurbRamp, Crosswalk, Signal — is attributed to the nearest non-grade-separated intersection within 25 m of it, on whichever street it sits. Measured on Seattle against the city's curb ramp inventory, about 85% of these clusters attach to the intersection the city keys the ramp to and 1% to a neighbouring one (their median distance to an intersection is 9–15 m); most of the remainder sit at junctions missing from our street network, the rest are mid-block crosswalks and driveway ramps. An unattached cluster stays with its street and scores its segment instead. The along-length types (Obstacle, SurfaceProblem, NoSidewalk) always score the segment.

The score. The attributed clusters contribute exactly as they do on a street — base(type) × ratingMultiplier + Σ tagAdjustments per cluster, a Bad curb ramp counting against, tags such as APS or missing tactile warning adjusting — and the intersection's score is the logistic (sigmoid) of the summed terms. There is no length to normalize by. An intersection is scored once any street meeting it has been audited; before that its score is null, since an absence of labels means an absence of data, not a perfect corner. The weights are the ones tabulated on the AccessScore: Streets API page, read from the same scoring engine.

What is not in the score yet. degree is reported but not scored: two curb ramps at a four-way intersection read as two ramps, not as an incomplete corner set. Which side of each street a ramp serves is likewise not yet modeled.

The per-type cluster_counts and sub_scores in each response let you see exactly how an intersection's score was composed: the sub_scores sum to logit(score). With severity_counts, tag_adjustments, and the scoring configuration, you can recompute an intersection's score under your own weights exactly as for a street, with no length factor.

Quick Download

Download intersection AccessScore data directly in your preferred format:

Generating your download...
This may take anywhere from a few seconds to a few minutes depending on the data size.

Note: This downloads scores for all intersections. For filtered data, use the API Query Parameters described below.

Query Parameters

All parameters are optional.

Note: When multiple location filters are provided (bbox, regionId, and regionName), bbox takes precedence over region filters, and regionId takes precedence over regionName. Every intersection's score is computed from all of its streets, whether or not they lie inside the filter.

ParameterTypeDescription
bbox string Filter by bounding box, as minLongitude,minLatitude,maxLongitude,maxLatitude (e.g., -74.04,40.88,-74.00,40.91), WGS84 (EPSG:4326). Returns the intersections inside the box. If omitted, the city's default bounding box is used.
regionId integer Return only intersections in the region with this id. Takes precedence over regionName; bbox takes precedence over both.
regionName string Return only intersections in the region with this name. Used only when bbox and regionId are absent.
filetype string Output format. Options: geojson (default), csv, shapefile, geopackage.
inline boolean Whether to display the file inline rather than as an attachment. Default: false.

Responses

Success Response (200 OK)

On success, the API returns 200 OK and the requested data in the specified filetype format.

GeoJSON Format (Default)

Returns a GeoJSON FeatureCollection where each feature is an intersection (Point, WGS84 / EPSG:4326).

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Point", "coordinates": [-74.0243, 40.8839] },
      "properties": {
        "intersection_id": 412,
        "region_id": 8,
        "degree": 4,
        "grade_separated": false,
        "street_edge_ids": [766, 767, 1203, 1204],
        "audit_count": 5,
        "score": 0.8176,
        "label_count": 11,
        "cluster_counts": { "CurbRamp": 3, "NoCurbRamp": 1, "Crosswalk": 2, "Signal": 0 },
        "sub_scores": { "CurbRamp": 1.875, "NoCurbRamp": -0.67, "Crosswalk": 0.5, "Signal": 0.0 },
        "severity_counts": {
          "CurbRamp": {"1": 2, "2": 1, "3": 0, "null": 0},
          "NoCurbRamp": {"1": 0, "2": 1, "3": 0, "null": 0},
          "Crosswalk": {"1": 0, "2": 2, "3": 0, "null": 0},
          "Signal": {"1": 0, "2": 0, "3": 0, "null": 0}
        },
        "tag_adjustments": { "CurbRamp": 0.0, "NoCurbRamp": 0.0, "Crosswalk": -0.25, "Signal": 0.0 }
      }
    },
    ...
  ]
}
GeoJSON Field Descriptions
Field PathTypeDescription
geometry.coordinatesarray[number]The intersection's position, in [longitude, latitude] (WGS84 / EPSG:4326): the centroid of the street endpoints meeting there.
properties.intersection_idintegerProject Sidewalk's identifier for this intersection. Stable across nightly rebuilds unless the street network itself changes.
properties.region_idintegerIdentifier of the region most of the intersection's streets belong to; null if none of them is in a region.
properties.degreeintegerHow many streets meet here (always at least 3).
properties.grade_separatedbooleantrue for a bridge or tunnel crossing rather than a place to cross. Never scored; holds no clusters.
properties.street_edge_idsarray[integer]The street_edge_id of every street meeting here (see the Streets API).
properties.audit_countintegerCompleted (high-quality) audits summed over those streets.
properties.scorenumberAccessScore in (0, 1); higher is more accessible. null when none of the intersection's streets has been audited, or it is grade-separated.
properties.label_countintegerNumber of labels contributing to this intersection's clusters.
properties.cluster_countsobjectNumber of clusters of each intersection type attributed here, keyed by label-type name (CurbRamp, NoCurbRamp, Crosswalk, Signal only).
properties.sub_scoresobjectContribution of each type to the pre-sigmoid total, keyed by label-type name; the values sum to logit(score).
properties.severity_countsobjectNumber of clusters of each type in each rating bucket ("1", "2", "3", or "null" for unrated clusters). The buckets of a type sum to its cluster_counts entry.
properties.tag_adjustmentsobjectThe summed adjustment of the active tags of each type: the part of sub_scores that no weight scales.

CSV Format

If filetype=csv, the first row is the header. The per-type objects are flattened into one column per intersection type, each named for its path through the JSON: cluster_counts.<type>, sub_scores.<type>, severity_counts.<type>.1 through .3 plus .null, and tag_adjustments.<type>; street_edge_ids is a JSON list, and the geometry becomes lat, lng.

intersection_id,region_id,degree,grade_separated,street_edge_ids,audit_count,score,label_count,cluster_counts.CurbRamp,cluster_counts.NoCurbRamp,cluster_counts.Crosswalk,cluster_counts.Signal,sub_scores.CurbRamp,…,sub_scores.Signal,severity_counts.CurbRamp.1,…,severity_counts.Signal.null,tag_adjustments.CurbRamp,…,tag_adjustments.Signal,lat,lng
412,8,4,false,"[766,767,1203,1204]",5,0.8176,11,3,1,2,0,1.875,…,0.0,2,…,0,0.0,…,0.0,40.8839,-74.0243
...

The full header, in order: the eight leading columns, then cluster_counts.<type> for each of the 4 intersection types, sub_scores.<type> for each, the four severity_counts.<type>.* buckets for each, tag_adjustments.<type> for each, then lat and lng. Types are always in the order CurbRamp, NoCurbRamp, Crosswalk, Signal.

Shapefile Format

If filetype=shapefile, the response is a ZIP archive of Shapefile components (.shp, .shx, .dbf, .prj). Because the DBF format truncates column names at 10 characters, the columns use short codes: intersecId, gradeSep, streetIds (comma-separated), and per type the same nCRamp / sCRamp / n1CRampn0CRamp / tCRamp codes as the street shapefile; the GeoJSON, CSV, and GeoPackage formats keep the full names.

GeoPackage Format

If filetype=geopackage, the response is a GeoPackage (.gpkg) file with full geometry and attributes (full snake_case column names).

Error Responses

  • 400 Bad Request: Invalid parameter values (e.g., malformed bounding box, non-positive or unknown region id).
  • 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

  • Treat the score as relative, not absolute: the weights are experimental. Use scores to compare intersections, not as a calibrated index.
  • Mind audit_count: a null score means no street at the intersection has been audited — absence of data, not a poor corner — and a low count means only some approaches have been seen.
  • Skip grade_separated intersections when counting crossings: they are listed so the network is complete, not because anyone crosses there.
  • Join to streets: street_edge_ids here and start_intersection_id / end_intersection_id on the Streets API are the same identifiers, so the two can be joined into a graph.

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.

On This Page