---
title: "Map view"
url: "https://audioguidekit.org/docs/content/map"
description: "Show an interactive map alongside your tour stops"
lang: "en"
updated: "2026-09-19T16:42:38.209Z"
---

# Map view

[Docs](https://audioguidekit.org/docs) / Content / Map view

# Map view

Show an interactive map alongside your tour stops

AudioGuideKit can show an interactive map tab on the tour screen. Visitors switch between the stop list and the map with a single tap — stops appear as numbered markers, and a route line can guide them between each one.

The map is completely optional. Without a single setting change everything works exactly as before.

## Enabling the map

Add `mapView: true` to your `metadata.json`:

```
{
  "mapView": true
}
```

The tour will open in map view by default. Without this setting the map tab stays hidden. No `mapProvider` needed — it defaults to keyless vector tiles (see [Tile providers](https://audioguidekit.org/docs/content/map#tile-providers) below).

## View modes

A tour screen has two views — **map** and **list** — controlled by two independent flags:

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `mapView` | boolean | `false` | Enable the map view |
| `listView` | boolean | `true` | Enable the list view |

The header shows a map/list toggle **only when both are enabled**. With a single view enabled there's no toggle — the tour opens directly into that view.

| `mapView` | `listView` | Result |
| --- | --- | --- |
| `true` | `true` (or omitted) | **Both** — toggle shown, opens on the map |
| `true` | `false` | **Map only** — no toggle |
| `false` (or omitted) | `true` (or omitted) | **List only** — no toggle (the default) |
| `false` | `false` | Falls back to the list |

Because `listView` defaults to `true`, existing tours are unaffected: omit it to keep the list, set `mapView: true` to add the map alongside it, or set `listView: false` (with `mapView: true`) for a map-only tour.

On a map-only tour (`listView: false`) the offline placeholder's **View list** button is hidden automatically — there's no list to fall back to.

## Adding coordinates to stops

Only audio stops appear on the map. Add a `location` field to each stop you want to pin:

```
{
  "id": "1",
  "type": "audio",
  "title": "Plaça Catalunya",
  "location": { "lat": 41.3851, "lng": 2.1734 }
}
```

Stops without a `location` are silently skipped — no marker is rendered, no errors.

All map fields (`mapView`, `mapProvider`, `location`, `mapMarkerIcon`, etc.) are listed with descriptions in the [Creating your tour](https://audioguidekit.org/docs/content/creating-guide) reference — alongside every other `metadata.json` and stop field.

## Tile providers

AudioGuideKit supports six map tile providers, plus bringing your own custom vector style. OpenFreeMap (the default) and OpenStreetMap work out of the box with no account or API key. The others need a key set as an environment variable.

| Provider | Key needed? | `mapProvider` value | Tiles |
| --- | --- | --- | --- |
| [OpenFreeMap](https://openfreemap.org/) | No | `"openfreemap"` (default) | Vector |
| [OpenStreetMap](https://www.openstreetmap.org/) | No | `"openstreetmap"` | Raster |
| [MapTiler](https://www.maptiler.com/) | Yes | `"maptiler"` | Raster |
| [Mapbox](https://www.mapbox.com/) | Yes | `"mapbox"` | Raster |
| [CARTO](https://carto.com/) | Yes | `"carto"` | Raster |
| [Jawg Maps](https://www.jawg.io/) | Yes | `"jawg"` | Raster |

### OpenFreeMap (default)

No setup needed, no account, no usage quota. Renders vector tiles via MapLibre GL, so the map stays crisp at every zoom level.

```
{
  "mapProvider": "openfreemap"
}
```

Or simply omit `mapProvider` — this is the default. Switch between the official styles with `mapStyleId`:

| Style | `mapStyleId` |
| --- | --- |
| Bright (default) | `bright` |
| Liberty | `liberty` |
| Positron (light) | `positron` |
| Fiord | `fiord` |
| Dark | `dark` |

```
{
  "mapProvider": "openfreemap",
  "mapStyleId": "dark"
}
```

### OpenStreetMap

No setup needed. Free for typical usage. Raster tiles.

```
{
  "mapProvider": "openstreetmap"
}
```

### MapTiler, Mapbox, CARTO, and Jawg

These four require an API key. Copy `.env` to `.env.local` and add the key(s) you need:

```
VITE_MAPTILER_API_KEY=your-maptiler-key
VITE_MAPBOX_API_KEY=pk.eyJ1...
VITE_CARTO_API_KEY=your-carto-key
VITE_JAWG_API_KEY=your-jawg-token
```

Never put API keys in `metadata.json`. Use `.env.local` — it's gitignored and kept off your public repo.

Then set the provider:

```
{
  "mapProvider": "maptiler",
  "mapStyleId": "outdoor-v4"
}
```

Each provider has a default style that works great out of the box. Use `mapStyleId` to pick a different one.

-   **[MapTiler](https://www.maptiler.com/)** default: `outdoor-v4`. Any MapTiler map ID works.
-   **[Mapbox](https://www.mapbox.com/)** default: `mapbox/outdoors-v12`. Custom Mapbox Studio styles use `"yourname/cl9abc1234def"` format.
-   **[CARTO](https://carto.com/)** — get a key at [carto.com/basemaps/apikey](https://carto.com/basemaps/apikey). CARTO retired its free tier—without a key, `mapProvider: "carto"` silently falls back to OpenStreetMap. Default style: `rastertiles/voyager`.
-   **[Jawg Maps](https://www.jawg.io/)** built-in styles: `jawg-streets`, `jawg-terrain`, `jawg-sunny`, `jawg-lagoon`, `jawg-dark`, `jawg-light`. Default: `jawg-terrain`.

### Bring your own vector style

`mapStyle` takes any MapLibre style.json URL and overrides `mapProvider` entirely — the map renders exactly that vector style, with no tile server of your own to run:

```
{
  "mapStyle": "https://your-storage.com/my-style.json"
}
```

Use this for a fully custom look, or to point at a provider not built in (any MapLibre-compatible style host works). Attribution comes from the style's own sources, so nothing else needs to be configured alongside it.

## Customizing the map view

### Starting position

By default the map fits all stops into view automatically. Use `mapCenter` and `mapZoom` to set a fixed starting position instead:

```
{
  "mapCenter": { "lat": 41.3851, "lng": 2.1734 },
  "mapZoom": 13
}
```

| Combination | Behaviour |
| --- | --- |
| Neither set | Fits all stops in view |
| `mapCenter` only | Centers there at zoom 13 |
| `mapCenter` + `mapZoom` | Centers there at the given zoom |
| `mapZoom` only | Fits all stops, then overrides the zoom level |

### Marker styles

By default each audio stop is a small circle showing its **stop number**, switching to a **checkmark** once completed. The `mapMarker` field sets the default style for the whole tour:

```
{
  "mapMarker": "image"
}
```

| Mode | Marker | Notes |
| --- | --- | --- |
| `"number"` (default) | Numbered circle; checkmark when completed | The original behaviour |
| `"image"` | The stop's own photo, cropped into the circle | See below |
| `"empty"` | Plain circle; checkmark still shown when completed | Like `number` with the number hidden |

#### Image markers

With `mapMarker: "image"`, each marker shows that stop's `image` — the same photo used in the list — cropped into a 32 × 32 px circle. State is conveyed with a colored ring instead of a number:

| State | Appearance |
| --- | --- |
| Active (current stop) | Photo with a ring in `mapMarkers.active.outlineColor` |
| Completed | Photo with a ring in `mapMarkers.completed.backgroundColor` |
| Neither | Photo, no ring |
| Stop has no `image` | Empty circle — never a broken image |

In the default themes the active and completed ring colors are both green (`#459825`), so they look identical until you give them distinct values in your theme.

### Marker colors

Marker background colors normally come from the theme, shared across every tour. Use `mapMarkerColors` to override them for a single tour instead — handy when a tour's basemap or branding needs different marker colors without a whole new theme:

```
{
  "mapMarkerColors": {
    "active": "#F97316",
    "upcoming": "#94A3B8",
    "completed": "#22C55E",
    "cluster": "#64748B"
  }
}
```

Any state you omit falls back to the theme's own `mapMarkers` colors. Number and checkmark colors stay with the theme (white in both built-in themes) — pick backgrounds dark enough for white text to stay readable, or give the tour its own `themeId` for a deeper restyle.

### Custom marker icons

Custom icons replace the circle entirely with your own image — no circle, ring, number, or checkmark. Set one for the whole tour with `mapMarkerIcon` in `metadata.json`:

```
{
  "mapMarkerIcon": "https://api.iconify.design/ph/map-pin-duotone.svg"
}
```

Or override a single stop's marker in the language file:

```
{
  "id": "3",
  "type": "audio",
  "mapMarkerIcon": "https://api.iconify.design/ph/map-pin-plus-bold.svg"
}
```

Icons are displayed at 32 × 32 px (`object-fit: contain`) inside a 44 × 44 px tap target.

#### Precedence

For each stop the marker is chosen in this order — first match wins:

1.  **`mapMarkerIcon`** on the stop — stop-level custom icon
2.  **`mapMarkerIcon`** in `metadata.json` — tour-level custom icon
3.  **`mapMarker`** mode — `image` / `number` / `empty`

Cluster icons are always unaffected.

### Marker clustering

When stops are close together, AudioGuideKit can group them into cluster bubbles that expand as visitors zoom in:

```
{
  "mapCluster": {
    "disableClusteringAtZoom": 16,
    "spiderfyOnMaxZoom": true
  }
}
```

| Field | Default | Description |
| --- | --- | --- |
| `disableClusteringAtZoom` | — | Zoom level where clustering stops |
| `spiderfyOnMaxZoom` | `true` | Fan out overlapping markers at max zoom |

## Route line

An optional polyline connects stops in sequence. It splits into two visual segments: solid for visited stops, dashed for stops still ahead — a progress indicator along the route.

The line only appears at street-level zoom (configurable via `minZoom`) and hides on overview zoom, keeping the map uncluttered.

### Straight-line route

```
{
  "mapRoute": true
}
```

Draws straight lines between stop coordinates. Good for most situations.

### Street-accurate route with GeoJSON

For tours where visitors walk along real streets, provide a GeoJSON file that follows the actual path:

```
{
  "mapRoute": {
    "geoJSON": "./route.geojson"
  }
}
```

Place the file next to `metadata.json`:

```
src/data/tour/
  my-tour/
    metadata.json
    route.geojson
    en.json
```

GeoJSON coordinates use `[longitude, latitude]` order — the reverse of the `{ lat, lng }` objects used elsewhere. This is the GeoJSON standard, not a quirk.

**Generating the file:** Export a GPX track from Komoot, Google Maps, Strava, or any walking app, then convert it to GeoJSON at [geojson.io](https://geojson.io/).

### Route configuration

| Field | Default | Description |
| --- | --- | --- |
| `geoJSON` | — | Relative path to a GeoJSON file |
| `minZoom` | `13` | Hide the line below this zoom level |
| `completedColor` | theme default | Color of visited segments |
| `upcomingColor` | theme default | Color of unvisited, dashed segments |
| `weight` | theme default | Line width in px |
| `opacity` | theme default | Opacity (0–1) of the completed line; upcoming renders at 75% of it |
| `dashArray` | theme default | SVG dash pattern for upcoming segments |

Route colors and line styling normally come from `mapMarkers.route` in your theme — see [Theming](https://audioguidekit.org/branding/reference) for the full reference. The fields above override the theme for a single tour, useful when a tour's basemap needs a different route color than the rest of your deployment:

```
{
  "mapRoute": {
    "geoJSON": "./route.geojson",
    "completedColor": "#F97316",
    "weight": 4
  }
}
```

## All metadata.json map fields

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `mapView` | boolean | `false` | Show the map tab |
| `listView` | boolean | `true` | Show the list tab |
| `mapProvider` | string | `"openfreemap"` | Tile provider |
| `mapStyle` | string (URL) | — | MapLibre style.json URL; overrides `mapProvider` entirely |
| `mapStyleId` | string | — | Provider-specific style ID |
| `mapCenter` | `{ lat, lng }` | — | Fixed starting center |
| `mapZoom` | number | — | Fixed starting zoom (0–23) |
| `mapMarker` | `"number"` | `"image"` | `"empty"` | `"number"` | Default marker style for the tour |
| `mapMarkerIcon` | string | — | Custom icon URL for all markers; overrides `mapMarker` |
| `mapMarkerColors` | object | — | Per-tour marker background colors by state; falls back to the theme |
| `mapCluster` | object | — | Clustering behaviour |
| `mapRoute` | boolean | object | `false` | Route polyline with progress and per-tour color/weight/style overrides |
| `mapLocateButton` | boolean | `true` | Show the locate-me button |

## Offline behaviour

Map tiles require an internet connection. When the device is offline, the map is replaced with an "unavailable offline" message and a **View list** button.

Stop data, GPS coordinates, and audio files remain fully accessible offline — visitors can still navigate through the stop list.

We're working on full offline support for maps (cached tiles) in a future release.
