> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/api/llms.txt)

# Map Matching V4

> **Note (legacy)**
> 
> v4 of the Map Matching API is a legacy product. It is no longer in active development. To learn more about Mapbox's newer web services APIs see [the Map Matching v5 documentation](https://docs.mapbox.com/api/api/navigation/map-matching/).

The Mapbox Map Matching API snaps fuzzy, inaccurate traces from a GPS unit or a phone to the OpenStreetMap road and path network using the Directions API. This produces clean paths that can be displayed on a map or used for other analysis.

**Limits**

-   Maximum 60 requests per minute
-   Maximum 100 coordinates per request
-   Results must be displayed on a Mapbox map using one of our [libraries or SDKs](https://mapbox.com/developers)

## Retrieve a match

Returns a path on the road and path network closest to the input traces.

**POST** : `https://api.mapbox.com/matching/v4/{profile}.json`

| URL Parameter | Description |
| --- | --- |
| `profile` | A directions profile ID; either `mapbox.driving`, `mapbox.walking`, or `mapbox.cycling` |

<table><thead><tr><th>Query Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>geometry</code><br>(optional)</td><td>Format of the returned geometry. Allowed values are: <code>geojson</code> (default, as <a href="https://tools.ietf.org/html/rfc7946#appendix-A.2">LineString</a>), <code>polyline</code> (<a href="https://developers.google.com/maps/documentation/utilities/polylinealgorithm">documentation</a>) with precision 6, <code>false</code> (no geometry, but <code>matched points</code>)</td></tr><tr><td><code>gps_precision</code><br>(optional)</td><td>An integer indicating the assumed precision of the used tracking device, in meters. Use higher numbers (5-10) for noisy traces and lower numbers (1-3) for clean traces. The default value is 4.</td></tr></tbody></table>

**NOTE**: the `polyline` coordinates in the Map Matching V4 are incorrectly returned as `longitude,latitude` pairs, they should be `latitude,longitude`. The Map Matching V5 API corrects this bug, but it is maintained here for backward compatibility for existing customers.

### Example request

```
$ curl -X POST \
  --header "Content-Type:application/json" \
  -d @trace.json \
  "https://api.mapbox.com/matching/v4/mapbox.driving.json?access_token={your_access_token}"
```

```python
>>> from Mapbox import MapMatcher
>>> service = MapMatcher()
>>> response = service.match(line, profile='mapbox.driving')
```

```javascript
var mapboxClient = new MapboxClient('{your_access_token}');

mapboxClient.matching(
  {
    type: 'Feature',
    properties: {
      coordTimes: [
        '2015-04-21T06:00:10Z',
        '2015-04-21T06:00:15Z',
        '2015-04-21T06:00:20Z'
      ]
    },
    geometry: {
      type: 'LineString',
      coordinates: [
        [13.419756889343262, 52.50171780290061],
        [13.419885635375975, 52.50237416816131],
        [13.420631289482117, 52.50294888790448]
      ]
    }
  },
  function (err, res) {
    // res is a document with directions
  }
);
```

```bash
mapbox mapmatching trace.geojson
```

```java
MapboxMapMatching client = new MapboxMapMatching.Builder()
  .setAccessToken("{your_access_token}")
  .setProfile(DirectionsCriteria.PROFILE_DRIVING)
  .setTrace(lineString)
  .build();
```

```
// This API cannot be accessed with the Mapbox Objective-C libraries
```

```swift
// This API cannot be accessed with the Mapbox Swift libraries
```

### Example request body

Request body must be one [GeoJSON Feature](https://docs.mapbox.com/help/glossary/geojson/) with a [LineString geometry](http://geojson.org/geojson-spec.html#linestring). The LineString may have up to 100 positions.

If your traces are in `GPX` or `KML` format, you can use [toGeoJSON](https://github.com/mapbox/togeojson) to transform them to GeoJSON.

```json
{
  "type": "Feature",
  "properties": {
    "coordTimes": [
      "2015-04-21T06:00:00Z",
      "2015-04-21T06:00:05Z",
      "2015-04-21T06:00:10Z",
      "2015-04-21T06:00:15Z",
      "2015-04-21T06:00:20Z"
    ]
  },
  "geometry": {
    "type": "LineString",
    "coordinates": [
      [13.418946862220764, 52.50055852688439],
      [13.419011235237122, 52.50113000479732],
      [13.419756889343262, 52.50171780290061],
      [13.419885635375975, 52.50237416816131],
      [13.420631289482117, 52.50294888790448]
    ]
  }
}
```

<table><thead><tr><th>Property</th><th>Description</th></tr></thead><tbody><tr><td><code>coordTimes</code><br>(optional)</td><td>an array of timestamps corresponding to positions in the LineString; can be numbers in <a href="https://en.wikipedia.org/wiki/Unix_time">Unix time</a> (seconds since the Unix epoch) or strings in <a href="https://tools.ietf.org/html/rfc3339">RFC 3339</a> format.</td></tr></tbody></table>

It is recommended to include timestamps, since they help improve the quality of the matching. The timestamps must be ascending. For best results, your timestamps should have a sample rate of about 5 seconds.

Some pre-processing tips to achieve the best results:

-   The Map Matching API is limited to processing traces with up to 100 coordinates. If you need to process longer traces, you can split the trace and make multiple requests.
-   Clusters of points (like a person waiting at a train crossing for a few minutes) often don't add more information to a trace and should be removed.
-   Map matching works best with a sample rate of 5 seconds between points. If your trace has a higher sample rate, you may want to downsample your trace.
-   [GeoJSON-tidy](https://github.com/mapbox/geojson-tidy) removes clusters and re-samples traces. If you know the provided traces are of poor quality, you must do some GeoJSON tidying. Otherwise Map Matching results can also expected to be poor.

### Example response

The response is a [GeoJSON FeatureCollection](http://geojson.org/geojson-spec.html#feature-collection-objects) aligned with the OpenStreetMap road/path network. It may include one or more [GeoJSON Features](http://geojson.org/geojson-spec.html#feature-objects); on clean matches, only one feature is returned, but when the matching algorithm cannot decide the correct match between two points, it will omit that line and create several sub-matches, each as a feature. The higher the number of features, the more likely that the input traces are poorly aligned to the road network.

```json
{
  "code": "Ok",
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [13.418805, 52.500599],
          [13.418851, 52.500659],
          [13.419145, 52.501095],
          [13.419276, 52.501286],
          [13.419618, 52.501754],
          [13.419981, 52.502249],
          [13.420042, 52.502335],
          [13.420494, 52.502984]
        ]
      },
      "properties": {
        "confidence": 0.8165256193474186,
        "distance": 120,
        "duration": 31,
        "matchedPoints": [
          [13.418805122375488, 52.50059890747071],
          [13.419144630432129, 52.50109481811523],
          [13.419617652893066, 52.50175094604492],
          [13.420042037963867, 52.50233459472656],
          [13.420494079589844, 52.50298309326172]
        ],
        "indices": [0, 1, 2, 3, 4]
      }
    }
  ]
}
```

| Property | Description |
| --- | --- |
| `code` | a string depicting the state of the response; see below for options |
| `geometry` | geometry type for returned line; will be a GeoJSON LineString. If the `geometry` option in request was `polyline`, will be an [encoded polyline](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) |
| `confidence` | a number between `0` (low) and `1` (high) indicating level of confidence in match |
| `distance` | the total distance traveled in the matching, in meters |
| `duration` | the expected travel time in the matching, in seconds |
| `matchedPoints` | an array of coordinate pairs denoting the location an input point was matched with |
| `indices` | a list of indices connecting `matchedPoints` with input points |

All routing responses will include a `code` property that describes the type of result. If a server error occurs, the HTTP status code will be 500 or higher and the response will not include a `code` property.

| Code option | Description |
| --- | --- |
| `Ok` | Normal case |
| `NoMatch` | The input did not produce any matches. `features` will be an empty array. |
| `TooManyCoordinates` | There are more than 100 points in the request. |
| `InvalidInput` | `message` will hold an explanation of the invalid input. |
| `ProfileNotFound` | Profile should be `mapbox.driving`, `mapbox.walking`, or `mapbox.cycling`. |