---
title: "Creating your tour"
url: "https://audioguidekit.org/docs/content/creating-guide"
description: "Complete guide to structuring your tour JSON files"
lang: "en"
updated: "2026-09-19T16:42:38.209Z"
---

# Creating your tour

[Docs](https://audioguidekit.org/docs) / Content / Creating your tour

# Creating your tour

Complete guide to structuring your tour JSON files

This guide walks through every field in your tour JSON files. By the end, you'll have a complete, working tour.

Bundling **more than one tour** in a single deployment? Put each tour in its own subfolder and add an app-level `app.json` to theme the selection screen. See [Multiple tours](https://audioguidekit.org/docs/content/multi-tour).

## Tour file structure

AudioGuideKit uses two types of files:

1.  **`metadata.json`** - Shared settings across all languages
2.  **Language files** (`en.json`, `es.json`, etc.) - Translated content

### Why two file types?

Settings like theme and offline mode should be consistent across languages. Content like titles and descriptions need translation. Splitting them keeps your files DRY (Don't Repeat Yourself).

## The metadata file

Create `src/data/tour/metadata.json`:

```
{
  "id": "barcelona",
  "offlineMode": "optional",
  "themeId": "default-light",
  "transcriptAvailable": true,
  "collectFeedback": true,
  "image": "https://images.unsplash.com/photo-barcelona..."
}
```

### Metadata fields

| Field | Required | Description |
| --- | --- | --- |
| `id` | Yes | Unique identifier for your tour (lowercase, hyphens okay) |
| `offlineMode` | No | `"optional"`, `"online-only"`, or `"offline-only"` |
| `themeId` | No | Theme name: `"default-light"`, `"default-dark"`, or your custom theme |
| `transitionAudio` | No | URL to audio played between stops |
| `transcriptAvailable` | No | Show transcription toggle when `true` |
| `collectFeedback` | No | Show rating button when `true` |
| `showLanguageLabel` | No | Show language name next to flag (default: `true`) |
| `hapticsEnabled` | No | Enable haptic feedback on stop taps — Android uses the Vibration API, iOS triggers the Taptic Engine (default: `true`) |
| `image` | No | Default tour cover image URL |
| `mapView` | No | Show an interactive map tab when `true` |
| `listView` | No | Show the stop list tab (default: `true`); set `false` with `mapView: true` for a map-only tour |
| `mapProvider` | No | Tile provider: `"openfreemap"` (default), `"openstreetmap"`, `"carto"`, `"mapbox"`, `"jawg"`, `"maptiler"` |
| `mapStyle` | No | MapLibre style.json URL — overrides `mapProvider` entirely for a fully custom vector basemap |
| `mapStyleId` | No | Provider-specific style ID (each provider has a sensible default) |
| `mapCenter` | No | Fixed starting map center: `{ "lat": 51.5, "lng": -0.1 }` |
| `mapZoom` | No | Fixed starting zoom level (0–23); defaults to fitting all stops |
| `mapMarker` | No | Default marker style: `"number"` (default), `"image"` (stop photo), or `"empty"` |
| `mapMarkerIcon` | No | URL to a custom marker image used for all stops; overrides `mapMarker` |
| `mapMarkerColors` | No | Per-tour marker background colors by state — `{ "active": "#...", "upcoming": "#...", "completed": "#...", "cluster": "#..." }`; falls back to the theme |
| `mapCluster` | No | Cluster nearby markers — `{ "disableClusteringAtZoom": 16 }` |
| `mapRoute` | No | Draw a route line between stops: `true` for straight lines, or `{ "geoJSON": "./route.geojson" }` for street-accurate paths; also takes per-tour `completedColor`, `upcomingColor`, `weight`, `opacity`, `dashArray` overrides |
| `mapLocateButton` | No | Show the locate-me button on the map (default: `true`) |

Start with just `id` and add other settings as needed. Every field except `id` has sensible defaults.

Map fields are covered in detail — providers, API keys, route lines, and theming — in the [Map view](https://audioguidekit.org/docs/content/map) guide.

## The language file

Create `src/data/tour/en.json` for English content:

```
{
  "id": "barcelona",
  "language": "en",
  "title": "Unlimited Barcelona",
  "description": "Discover the rich history and hidden gems of Barcelona's Gothic Quarter on this self-guided walking tour.",
  "totalDuration": "45 mins",
  "totalStops": 5,
  "image": "https://images.unsplash.com/photo-barcelona...",
  "stops": [
    {
      "id": "1",
      "type": "audio",
      "title": "Welcome to Barcelona",
      "duration": "3 min audio",
      "image": "https://images.unsplash.com/photo-welcome...",
      "audioFile": "https://your-storage.com/audio/01-welcome.mp3"
    }
  ]
}
```

### Language file fields

| Field | Required | Description |
| --- | --- | --- |
| `id` | Yes | Must match `metadata.json` |
| `language` | Yes | ISO language code (`"en"`, `"es"`, `"de"`, etc.) |
| `title` | Yes | Tour title (displayed on start screen) |
| `description` | Yes | Tour description (1-2 engaging sentences) |
| `totalDuration` | Yes | Human-readable duration (`"45 mins"`) |
| `totalStops` | Yes | Number of stops in the tour |
| `image` | No | Tour cover image (overrides metadata) |
| `stops` | Yes | Array of stop objects |

The `language` field determines the language, not the filename. You could name your file `english.json` and it would still work if `"language": "en"` is set. (But please don't—use `en.json` for sanity.)

## Stop objects

Each item in the `stops` array represents one tour stop:

```
{
  "id": "1",
  "type": "audio",
  "title": "Welcome to Barcelona",
  "duration": "3 min audio",
  "image": "https://images.unsplash.com/photo-xxx",
  "audioFile": "https://your-storage.com/audio/01-welcome.mp3",
  "transcription": "Welcome to Barcelona! Today we'll explore..."
}
```

### Stop fields

| Field | Required | Description |
| --- | --- | --- |
| `id` | Yes | Unique within the tour (`"1"`, `"2"`, etc.) |
| `type` | Yes | Stop type (see [Stop types](https://audioguidekit.org/docs/content/stop-types)) |
| `title` | Yes | Stop title |
| `duration` | Yes | Human-readable duration (`"3 min audio"`) |
| `image` | Yes | Stop image URL |
| `audioFile` | For audio | Audio file URL (MP3 or M4A) |
| `transcription` | No | Text transcription of the audio |
| `location` | No | GPS coordinates for the map pin: `{ "lat": 51.5007, "lng": -0.1246 }` — audio stops only |
| `mapMarkerIcon` | No | Custom marker image URL for this stop only (overrides the tour-level `mapMarkerIcon` and any `mapMarker` mode) |

Stop IDs must be unique within a tour and consistent across all language files. If English stop `"3"` is about the cathedral, Spanish stop `"3"` must also be about the cathedral.

## Complete example: London tour

Let's build a real tour from scratch.

### Step 1: Create metadata.json

```
{
  "id": "london-highlights",
  "offlineMode": "optional",
  "themeId": "default-light",
  "transcriptAvailable": true,
  "collectFeedback": true,
  "image": "https://images.unsplash.com/photo-1513635269975-59663e0ac1ad?w=1000",
  "mapView": true,
  "mapRoute": true
}
```

### Step 2: Create en.json

```
{
  "id": "london-highlights",
  "language": "en",
  "title": "London Highlights",
  "description": "Discover London's most iconic landmarks on this walking tour through Westminster and the South Bank.",
  "totalDuration": "60 mins",
  "totalStops": 4,
  "stops": [
    {
      "id": "1",
      "type": "audio",
      "title": "Big Ben & Parliament",
      "duration": "8 min audio",
      "image": "https://images.unsplash.com/photo-1529655683826-aba9b3e77383?w=800",
      "audioFile": "https://your-storage.com/london/01-big-ben.mp3",
      "transcription": "Welcome to Westminster! Standing before you is the Elizabeth Tower, home to Big Ben...",
      "location": { "lat": 51.5007, "lng": -0.1246 }
    },
    {
      "id": "2",
      "type": "audio",
      "title": "Westminster Abbey",
      "duration": "10 min audio",
      "image": "https://images.unsplash.com/photo-1520986606214-8b456906c813?w=800",
      "audioFile": "https://your-storage.com/london/02-abbey.mp3",
      "location": { "lat": 51.4994, "lng": -0.1273 }
    },
    {
      "id": "3",
      "type": "audio",
      "title": "London Eye",
      "duration": "6 min audio",
      "image": "https://images.unsplash.com/photo-1567157577867-05ccb1388e66?w=800",
      "audioFile": "https://your-storage.com/london/03-eye.mp3",
      "location": { "lat": 51.5033, "lng": -0.1195 }
    },
    {
      "id": "4",
      "type": "audio",
      "title": "Tower Bridge",
      "duration": "7 min audio",
      "image": "https://images.unsplash.com/photo-1461949814715-0e9ad3b9e75a?w=800",
      "audioFile": "https://your-storage.com/london/04-bridge.mp3",
      "location": { "lat": 51.5055, "lng": -0.0754 }
    }
  ]
}
```

### Step 3: Save to src/data/tour/

Place your files in the `src/data/tour/` directory:

```
src/data/tour/
├── metadata.json
└── en.json
```

### Step 4: Test

```
bun run dev
```

Open [http://localhost:3000](http://localhost:3000/) and your London tour should appear!

## Adding another language

To add Spanish, create `src/data/tour/es.json`:

```
{
  "id": "london-highlights",
  "language": "es",
  "title": "Lo Mejor de Londres",
  "description": "Descubre los monumentos más icónicos de Londres en este recorrido a pie por Westminster y South Bank.",
  "totalDuration": "60 mins",
  "totalStops": 4,
  "stops": [
    {
      "id": "1",
      "type": "audio",
      "title": "Big Ben y el Parlamento",
      "duration": "8 min audio",
      "image": "https://images.unsplash.com/photo-1529655683826-aba9b3e77383?w=800",
      "audioFile": "https://your-storage.com/london/es/01-big-ben.mp3"
    }
  ]
}
```

Notice the audio file points to a Spanish version. You need separate audio recordings for each language (unless you want all languages to hear the same audio, which... don't do that).
