Source: https://developers.woosmap.com/products/map-api/concepts/polyline-encoding/

> For clean Markdown of any page, append `.md` to the page URL.

> For a complete documentation index, see https://developers.woosmap.com/llms.txt

# Polyline Encoding



## Overview

Polyline encoding is a lossy compression algorithm that stores a series of coordinates as a single ASCII string. The Woosmap [Directions API](/products/distance-api/features/route/) returns route geometries as encoded polylines.

When using the Map JS API with `DirectionsRenderer`, decoding and display are handled automatically. The `DirectionResult` object also provides a pre-decoded `overview_path` property if you need direct access to the coordinates.

## Polyline Encoding Algorithm

The encoding process converts coordinates into ASCII characters using a base64-like scheme. Each encoded value is summed with 63 (the ASCII character `?`) to ensure printable characters.

Key points:

- Coordinates are multiplied by 1e5 and rounded to integers
- Points store only the **offset from the previous point** (delta encoding)
- A continuation bit indicates when more data follows for a single value
- Negative values use two’s complement with bit inversion

> **Note:** Backslash characters in encoded strings must be escaped as double-backslashes in string literals.

### Encoding Steps

1. Take the signed value (e.g., `-179.9832104`)
2. Multiply by 1e5, round → `-17998321`
3. Convert to binary using two’s complement for negatives
4. Left-shift one bit
5. Invert if original was negative
6. Break into 5-bit chunks, reverse order
7. OR with 0x20 if more chunks follow
8. Add 63, convert to ASCII

### Example

Encoding three points: `(38.5, -120.2)`, `(40.7, -120.95)`, `(43.252, -126.453)`

| Latitude | Longitude | Δ Lat | Δ Lng | Encoded Point |
| --- | --- | --- | --- | --- |
| 38.5 | -120.2 | +3850000 | -12020000 | `_p~iF~ps\|U` |
| 40.7 | -120.95 | +220000 | -75000 | `_ulLnnqC` |
| 43.252 | -126.453 | +255200 | -550300 | `_mqNvxq\@` |

**Result:** `_p~iF~ps|U_ulLnnqC_mqNvxq@`

## Using the Map JS API

The simplest way to display a route is with `DirectionsRenderer`, which handles decoding automatically:

```javascript
const directionsService = new woosmap.map.DirectionsService();
const directionsRenderer = new woosmap.map.DirectionsRenderer({ map: map });

directionsService.route({
  origin: { lat: 48.8566, lng: 2.3522 },
  destination: { lat: 45.764, lng: 4.8357 }
}).then((response) => {
  directionsRenderer.setDirections(response);
});
```

If you need the decoded coordinates directly, use the `overview_path` property:

```javascript
directionsService.route({
  origin: { lat: 48.8566, lng: 2.3522 },
  destination: { lat: 45.764, lng: 4.8357 }
}).then((response) => {
  const path = response.routes[0].overview_path; // Already decoded!
  
  const routeLine = new woosmap.map.Polyline({
    path: path,
    strokeColor: "#4285F4",
    strokeWeight: 4
  });
  routeLine.setMap(map);
});
```

## Manual Decoding

If you need to decode polylines outside the Map JS API context (e.g., server-side or with raw API responses):

```javascript
function decodePolyline(encoded, precision = 5) {
  const coordinates = [];
  const factor = Math.pow(10, precision);
  let index = 0;
  let lat = 0;
  let lng = 0;

  while (index < encoded.length) {
    let byte;
    let shift = 0;
    let result = 0;

    do {
      byte = encoded.charCodeAt(index++) - 63;
      result |= (byte & 0x1f) << shift;
      shift += 5;
    } while (byte >= 0x20);

    const latitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);

    shift = 0;
    result = 0;

    do {
      byte = encoded.charCodeAt(index++) - 63;
      result |= (byte & 0x1f) << shift;
      shift += 5;
    } while (byte >= 0x20);

    const longitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);

    lat += latitudeChange;
    lng += longitudeChange;

    coordinates.push([lat / factor, lng / factor]);
  }

  return coordinates;
}
```

```typescript
type LatLngTuple = [latitude: number, longitude: number];

function decodePolyline(encoded: string, precision: number = 5): LatLngTuple[] {
  const coordinates: LatLngTuple[] = [];
  const factor = Math.pow(10, precision);
  let index = 0;
  let lat = 0;
  let lng = 0;

  while (index < encoded.length) {
    let byte: number;
    let shift = 0;
    let result = 0;

    do {
      byte = encoded.charCodeAt(index++) - 63;
      result |= (byte & 0x1f) << shift;
      shift += 5;
    } while (byte >= 0x20);

    const latitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);

    shift = 0;
    result = 0;

    do {
      byte = encoded.charCodeAt(index++) - 63;
      result |= (byte & 0x1f) << shift;
      shift += 5;
    } while (byte >= 0x20);

    const longitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);

    lat += latitudeChange;
    lng += longitudeChange;

    coordinates.push([lat / factor, lng / factor]);
  }

  return coordinates;
}
```

## Interactive Playground

Encode coordinates or decode polyline strings and see the results on the map:

https://demo.woosmap.com/misc/polyline-playground/
[](https://demo.woosmap.com/misc/polyline-playground/ "Open in new tab")

## Precision

Standard polyline encoding uses 5 decimal places (1e5), giving ~1.1 meter accuracy. Some systems use 6 decimal places (1e6) for ~11 cm accuracy. Ensure encoder and decoder use matching precision.

## Related Resources

- [Distance API](/products/distance-api/overview/)
- [Draw Shapes](/products/map-api/guides/draw-shapes/)
