# Route Replay agent instructions

Docs version 4.1.0, scene schema v1. Endpoints: https://routereplay.video/api/v1. Schema: https://routereplay.video/schemas/scene-v1.json.

## Workflow

Route Replay turns a travel itinerary (flights, and any train, bus, car, or ferry legs between them) into an animated journey on a 3D Earth. You (the agent) research and clarify the itinerary with the creator, then submit a small JSON scene spec over HTTPS. Route Replay validates it, stores a private draft, and shows it in a live browser preview. You do the authoring; the page only plays, shares, and exports.

Every successful response includes `next`: a short list of suggested next steps. Follow it unless the creator asked for something else.

You need to be able to make HTTP requests with custom headers and JSON bodies (for example with `curl` or a fetch tool). Reading URLs alone is not enough. Send a descriptive `User-Agent` such as `my-agent/1.0`; the hosting network rejects some library defaults (for example Python's `Python-urllib`) with a plain-text `error code: 1010`. If you cannot make authorized POST and PUT requests, tell the creator plainly instead of pretending to create the journey.

### 1. Gather the itinerary

- Collect each flight in order: departure airport, arrival airport, and local departure and arrival times with dates.
- Use 3-letter IATA airport codes (`ORD`, not `KORD` or the city code `CHI`).
- Find the aircraft type for every flight; the scene draws it. Give its 4-character ICAO type designator, such as `B38M` (Boeing 737 MAX 8) or `A21N` (Airbus A321neo), not the 3-character IATA code many booking sites show (`7M8`, `32Q`). For a past flight, flight-history sites list the type that flew; for an upcoming one, use the airline's schedule or the creator's booking, and tell the creator that airlines sometimes swap aircraft. If the type isn't in the supported list (Reference section), choose the closest listed type and say so.
- Travel on the ground or water between flights (a train, bus, car, or ferry) is a leg too, with `mode` in place of `aircraft`, so the journey stays connected. For its `from` and `to`, use the IATA code of the airport nearest each station or terminal (Wellington's ferry terminal is `WLG`). Split a multi-day trip at its overnight stops: the night there shows, and the route is traced through the place the creator stopped rather than the fastest way. When you save, Route Replay traces each such leg along the railway, road, or ferry line; the scene draws a train, coach, car, or ferry moving along that route.
- Write every time with the airport's local UTC offset at that moment, including daylight saving time: `2031-07-05T10:00:00-05:00` in Chicago in July, `-06:00` in January.
- Clocks can change during a trip, even overnight on a flight. Check each timestamp's offset separately. If you have no time-zone database, `GET https://routereplay.video/api/v1/airports/{IATA}?local=2031-03-30T06:40` returns the airport, its IANA zone, and the exact offset (or both offsets, or none) for that local time.
- Flights over the date line often arrive on a different calendar day. Check that arrival is after departure in UTC.
- Ask the creator only about material ambiguity: a missing or unclear time or date, a city with several airports, or a gap between flights that suggests a missing leg (a flight, or travel on the ground). Do not invent times. Where the creator has a booking, prefer its scheduled times.
- Leave out passenger names, booking references, ticket numbers, seat numbers, prices, and sources. The scene contains only what is needed to draw the journey.

### 2. Build the spec

Start from the example in the Reference section of https://routereplay.video/agent-docs and the field descriptions in https://routereplay.video/schemas/scene-v1.json. The example sets several optional fields only to show their shape. Use stable lowercase leg ids such as `ord-sfo`. Omit optional presentation fields unless the creator asked for something specific; defaults adapt when legs change. A short, generic `title` (such as "Boston to Madeira") is recommended; it names the page and shared links, and is never drawn in the scene. Scenes have no frame shape: the player fills any screen, and viewers pick 16:9, 1:1, or 9:16 when they export a video.

Sensible choices:

- The camera is not configurable: it looks straight down at the aircraft, north up, close in at airports and pulling back toward the middle of each flight (furthest on the trip's longest leg). Time runs on through the start and end holds, from 20 minutes before departure to 20 minutes after arrival.
- Long connections are animated in a short stop; set `presentation.stopHolds` to give a connection more or less time, or `0` to cut straight to the next departure.
- Pacing: `normalized.legs[].flightSeconds` shows how long each flight is on screen. Flight time is the total duration minus all holds, shared between legs by weight. Default weights grow with distance and average 1; a leg you don't list in `legWeights` keeps its default. Raising one leg's weight alone takes time from the others, and raising `durationSeconds` alone slows every leg. To slow just one leg without changing the others, add the extra seconds to `durationSeconds`, then set that leg's weight to its current `normalized.legs[].weight` × new seconds ÷ current `flightSeconds`, and list every other leg in `legWeights` at its current `normalized` weight. Example: a leg with weight 1.39 showing 7 s should show 14 s: add 7 to `durationSeconds` and set its weight to 1.39 × 14 ÷ 7 = 2.78. `durationSeconds` may be fractional. Once it is set, the length no longer adapts when legs change, so adjust it yourself if you later add or remove legs. Dry-run with `/api/v1/validate` to see the resulting `flightSeconds` before saving.
- If `durationSeconds` is omitted, the length is the start, end, and stop holds plus 6 seconds per leg, capped at 120. It changes when you add legs or holds.

If you are unsure whether a spec is valid, `POST https://routereplay.video/api/v1/validate` checks it without saving anything.

### 3. Create the draft

```
POST https://routereplay.video/api/v1/scenes
Content-Type: application/json
Idempotency-Key: <new random UUID>

<scene spec JSON>
```

The `201` response contains `id`, `revision`, `previewUrl`, and `credentials.edit` / `credentials.owner`. Credentials are shown only once. Capture the whole response before printing or redacting anything, and keep the credentials in this conversation's working state. If you lose them within 24 hours, repeating the identical request with the same `Idempotency-Key` returns the original response, credentials included.

- Give the creator `previewUrl`. Opening it shows the journey (on desktop or phone) and refreshes automatically when you revise it. Its credential, after the `#`, allows editing, so the creator should share it only with people who may edit.
- Keep `credentials.owner` private. It is needed to publish, delete, or rotate the edit credential. Give it to the creator in your private conversation and suggest they keep it somewhere safe, such as a password manager, so they can manage the journey after this conversation ends; there are no accounts and it cannot be recovered.
- Never put either credential in a public place. If you must keep credentials between sessions, store them only where the creator approves, never in a repository or anything shared.
- If the request fails with a network error, retry with the same `Idempotency-Key` and the same body; you will not create a duplicate.
- The `#k=` part of `previewUrl` is the edit credential. The page moves it into a private browser session and removes it from the address bar. For a link that can only watch, publish (step 7).

### 4. Repair validation errors

A `422 validation_failed` response lists `issues`, each with a JSON Pointer `path`, a `code`, a `message`, and often a `hint` with a concrete fix. Nothing is saved. Apply the fixes and resubmit. If an issue reflects a real ambiguity, such as an unknown airport or a time that does not exist, ask the creator rather than guessing. Stop and explain after a few failed attempts.

### 5. Check your work

Passing validation does not prove the journey looks right.

- **Warnings.** Successful validate, create, and replace responses include `warnings[]`: likely mistakes that were still accepted, such as an average speed no airliner flies (often a wrong date) or a multi-day stay that flashes past. Each has `path`, `code`, `message`, and `hint`; the Reference section lists the codes. Raise material ones with the creator in plain words, for example "The SFO–ORD flight comes out at 28 hours. Did it land on the 7th?" Don't change the creator's itinerary just to silence a warning, and don't repeat one they have confirmed.
- **Storyboard.** After creating or revising, `GET https://routereplay.video/api/v1/scenes/{id}/storyboard` with the credential. Its keyframes describe what the animation shows at evenly spaced moments (`?frames=` from 2 to 24, default 8) or at moments you choose (`?at=7.2,12`): the phase, leg and progress, a plain summary, the UTC and local times being shown, whether the aircraft is in daylight, the airport labels on screen, and where the camera is centred and how far it sees. `onScreenSeconds` lists how long each leg and stop lasts. Compare it with what the creator asked for: that a slowed leg gained seconds, or that an overnight flight crosses the dark side.
- **Picture.** If you can view images, `https://routereplay.video/api/v1/scenes/{id}/storyboard.svg` sketches the routes, airports, and numbered keyframe markers on a plain map, with night shading at `?night=<seconds>` (default 0).
- **Before saving.** `POST https://routereplay.video/api/v1/validate?storyboard=8` adds a storyboard to a dry run.

### 6. Revise

When the creator asks for a change ("slow down the Pacific leg", "make it vertical", "the second flight left at 9:40"). If they point at the preview ("slow down this part"), see "What the creator is looking at" below:

1. `GET https://routereplay.video/api/v1/scenes/{id}` with `Authorization: Bearer <edit or owner credential>`.
2. Change the returned `spec` (not `normalized`), keeping leg ids stable.
3. `PUT https://routereplay.video/api/v1/scenes/{id}` with body `{"expectedRevision": <revision you read>, "spec": <changed spec>}`.

A `409 revision_conflict` means the draft changed since you read it (perhaps the creator used another agent). The response includes the current spec. Reapply your intended change to it and retry with the current revision; do not blindly overwrite. An open preview shows each new revision immediately. Check the response's `warnings` and the storyboard (step 5) before telling the creator it's done.

To undo, list `GET /api/v1/scenes/{id}/revisions`, fetch an earlier revision, and PUT its `spec` as a new revision.

### What the creator is looking at

While the creator has the preview open, reading the draft with your credential (`GET https://routereplay.video/api/v1/scenes/{id}`) also returns:

- `viewer.open`: whether a preview is open. Once the creator pauses or moves the playhead, `viewer.paused` and `viewer.at` describe the moment they are looking at, in the same form as a storyboard keyframe (`t`, `phase`, `legId`, `legProgress`, `summary`, local times). While it plays, `at` is an estimate.
- `activity`: whether the preview currently shows that you are working.

When the creator says "this part", "here", or "now", read the draft and use `viewer.at`. Say what you assumed ("I'll slow down the Pacific crossing, where you paused"). If no preview is open or it is playing, ask which part they mean. A paused position stays accurate however long ago it was reported (`reportedSecondsAgo`), because the preview reports again whenever the creator moves. `viewer.revision` appears only while the preview is still showing an older revision, typically for a second after you save.

**Showing a moment.** `POST https://routereplay.video/api/v1/scenes/{id}/viewer` with `{"seek": <seconds>}` pauses open previews at that moment; storyboard keyframes give the times. Move the creator's view only when they ask ("show me the layover"), or once at the end of a change to bring it into view. Never move it while you work.

**Showing that you are working.** Before work that will take you more than about 10 seconds in all, such as researching flights or a read–check–save sequence, `POST https://routereplay.video/api/v1/scenes/{id}/activity` with `{"state": "working", "message": "Checking your connection in San Francisco"}`. The message is plain text, up to 80 characters. Open previews show "Your agent is working: …" until you send `{"state": "idle"}`, or for 3 minutes unless you send it again.

Viewer state is never stored or published. It exists only while a preview is open.

### 7. Share

Publish only when the creator asks to share:

```
POST https://routereplay.video/api/v1/scenes/{id}/publications
Authorization: Bearer <owner credential>
Content-Type: application/json
Idempotency-Key: <new random UUID>

{"revision": <the revision the creator approved>}
```

Give the creator the returned `watchUrl`. Anyone can watch it without an account or credentials. It is an immutable snapshot: later edits do not change it, and publishing again creates a new link. Published data contains the journey and presentation only.

### 8. Delete

When the creator asks, `DELETE https://routereplay.video/api/v1/scenes/{id}` with the owner credential removes the draft, its revisions, and all its watch links. Explain that this cannot be undone.

### Browser tools (optional)

When the creator has the preview open in a browser that supports WebMCP, the page offers tools: `get_scene`, `set_scene`, `seek_scene`, and (with owner access) `publish_scene`. They use the same validation and revisions as the HTTP API. Use `seek_scene` to inspect a specific moment. The HTTP API works without them.

### Video export

The page has an Export button. On browsers that support it, the creator can save a 720p MP4 locally. Export runs on their device, may take longer than the clip's length, and is not required for sharing.

## Reference

### Example spec (synthetic)

This example sets optional presentation fields to show their shape. Only `schemaVersion` and `legs` are required.

```json
{
  "schemaVersion": 1,
  "title": "Chicago to Auckland (synthetic example)",
  "legs": [
    {
      "id": "ord-sfo",
      "from": "ORD",
      "to": "SFO",
      "departure": "2031-01-05T10:00:00-06:00",
      "arrival": "2031-01-05T12:45:00-08:00",
      "aircraft": "B739"
    },
    {
      "id": "sfo-akl",
      "from": "SFO",
      "to": "AKL",
      "departure": "2031-01-05T21:30:00-08:00",
      "arrival": "2031-01-07T07:15:00+13:00",
      "aircraft": "B789"
    }
  ],
  "presentation": {
    "durationSeconds": 20,
    "stopHolds": {
      "ord-sfo": 2
    }
  }
}
```

### Endpoints

| Method and path | Purpose | Credential |
| --- | --- | --- |
| `GET /api/v1/airports/{IATA}?local=YYYY-MM-DDTHH:MM` | Airport name, coordinates, IANA zone; with `local`, the valid offset(s) for that local time | None |
| `POST /api/v1/validate` | Check a spec without saving; `?storyboard=n` adds keyframes | None |
| `POST /api/v1/scenes` | Validate and create a private draft | None (rate-limited) |
| `GET /api/v1/scenes/{id}` | Read spec, normalized record, revision, capabilities, publications, and (while a preview is open) `viewer` and `activity` | Edit or owner |
| `PUT /api/v1/scenes/{id}` | Replace the spec: `{"expectedRevision", "spec"}` | Edit or owner |
| `GET /api/v1/scenes/{id}/revisions` | List retained revisions (last 50) | Edit or owner |
| `GET /api/v1/scenes/{id}/revisions/{n}` | Read one revision | Edit or owner |
| `POST /api/v1/scenes/{id}/publications` | Publish a revision as an immutable snapshot: `{"revision"}` | Owner |
| `GET /api/v1/scenes/{id}/publications` | List this draft's watch links | Edit or owner |
| `POST /api/v1/scenes/{id}/viewer` | `{"seek": seconds}`: pause open previews at that moment | Edit or owner |
| `POST /api/v1/scenes/{id}/activity` | `{"state": "working", "message"}` or `{"state": "idle"}`: the preview's "Your agent is working" line, lapsing after 3 minutes | Edit or owner |
| `GET /api/v1/scenes/{id}/storyboard` | Keyframes (`?frames=2..24` or `?at=seconds,...`) and screen time per leg and stop | Edit or owner |
| `GET /api/v1/scenes/{id}/storyboard.svg` | Map sketch of the storyboard; `?night=seconds` places the day/night line | Edit or owner |
| `POST /api/v1/scenes/{id}/credentials/edit` | Replace the edit credential; old one and its browser sessions stop working | Owner |
| `DELETE /api/v1/scenes/{id}` | Delete the draft and all its publications | Owner |
| `GET /api/v1/publications/{id}` | Read a published snapshot: `scene` holds its normalized record (there is no `spec`) | None |
| `GET /api/v1/publications/{id}/storyboard` (and `.svg`) | Storyboard of a published snapshot | None |

Send credentials as `Authorization: Bearer <credential>`. Successful responses include `next`, the suggested next steps. Responses include `capabilities` so you can see what the current credential allows. Ordinary reads never return credentials. `GET /api/v1/scenes/{id}` supports `If-None-Match` with its `ETag`.

### Spec rules

- `schemaVersion` is `1`. Unknown fields are errors.
- 1–12 legs. Each leg: `id`, `from`, `to`, `departure`, `arrival`, and exactly one of `aircraft` (a flight) or `mode` (a leg on the ground or water).
- `aircraft` is an ICAO type designator. Supported: `BCS1` Airbus A220-100, `BCS3` Airbus A220-300, `A318` Airbus A318, `A319` Airbus A319, `A320` Airbus A320, `A321` Airbus A321, `A19N` Airbus A319neo, `A20N` Airbus A320neo, `A21N` Airbus A321neo, `B736` Boeing 737-600, `B737` Boeing 737-700, `B738` Boeing 737-800, `B739` Boeing 737-900ER, `B37M` Boeing 737 MAX 7, `B38M` Boeing 737 MAX 8, `B39M` Boeing 737 MAX 9, `B3XM` Boeing 737 MAX 10, `B752` Boeing 757-200, `B753` Boeing 757-300, `B762` Boeing 767-200ER, `B763` Boeing 767-300ER, `B764` Boeing 767-400ER, `B772` Boeing 777-200ER, `B77L` Boeing 777-200LR / 777F, `B773` Boeing 777-300, `B77W` Boeing 777-300ER, `B778` Boeing 777-8, `B779` Boeing 777-9, `B788` Boeing 787-8, `B789` Boeing 787-9, `B78X` Boeing 787-10, `A332` Airbus A330-200, `A333` Airbus A330-300, `A338` Airbus A330-800, `A339` Airbus A330-900, `A359` Airbus A350-900, `A35K` Airbus A350-1000, `B744` Boeing 747-400, `B748` Boeing 747-8, `A388` Airbus A380-800, `E170` Embraer 170, `E75L` Embraer 175 (long wing), `E75S` Embraer 175 (short wing), `E190` Embraer 190, `E195` Embraer 195, `E290` Embraer 190-E2, `E295` Embraer 195-E2, `CRJ2` Bombardier CRJ200, `CRJ7` Bombardier CRJ700, `CRJ9` Bombardier CRJ900, `CRJX` Bombardier CRJ1000, `AT43` ATR 42-300/-320, `AT45` ATR 42-500, `AT46` ATR 42-600, `AT72` ATR 72-200/-210, `AT75` ATR 72-500, `AT76` ATR 72-600, `DH8A` De Havilland Canada Dash 8-100, `DH8B` De Havilland Canada Dash 8-200, `DH8C` De Havilland Canada Dash 8-300, `DH8D` De Havilland Canada Dash 8-400. A connection between legs flown by different types dissolves from one aircraft to the next while the aircraft waits.
- `mode` is one of `train`, `bus`, `car`, `ferry`. Each mode is drawn as its own vehicle moving along the ground: a short train, a coach, a car, or a ferry with a wake. At a connection the aircraft dissolves into it, and one mode dissolves into the next (two legs with the same mode keep the same vehicle). When the journey is saved (create or replace, not `/validate`), the leg is traced along OpenStreetMap's railways for `train`, roads for `bus` and `car`, and ferry lines for `ferry`, from the airport nearest one station to the airport nearest the other, and `normalized.legs[].path` holds the route. A later save keeps it while the leg's mode and airports stay the same. If no route is found, the leg is drawn as a straight line with a `route_not_found` warning. The mode names the leg in the route summary and storyboards. `from` and `to` are the IATA codes of the airports nearest the stations or terminals (a few kilometres apart is invisible at the scene's scale). Choose the closest mode for others: a tram or metro is `train`, a coach is `bus`, any boat is `ferry`.
- Legs are connected (each departs where the previous arrived) and do not overlap in time. Repeated airports are fine.
- Timestamps are ISO 8601 with the airport's local offset at that instant. `Z` is accepted only where the local offset is zero. Times are converted to UTC by the service.
- Flight time per leg: 10 minutes to 30 hours. Surface legs: 10 minutes to 7 days. Whole journey: at most 366 days.
- `presentation.durationSeconds`: 4–120. After start, stop, and end holds are subtracted, each flight needs at least 1 s.
- `presentation.legWeights` values 0.1–10. Unlisted surface legs default to at least 0.5, so a short crossing stays on screen beside long flights. `stopHolds` values 0–20 s keyed by the arriving leg's id; start and end holds 0–10 s.
- `title` (optional): up to 80 characters. It names the page and shared links, and is never drawn in the scene.
- `environment.weather`: `clouds` (default) draws cloud cover from NOAA's GFS weather model at the journey's times: the model's analysis for past times and its forecast for upcoming ones. They are model clouds, not satellite photos. Each save pins the latest model run, so save again closer to an upcoming trip for a fresher forecast. Model data covers 22 March 2021 to 16 days ahead; outside that, no clouds are drawn. `omitted` draws no clouds. `assets.style`: `standard`.
- Request bodies are limited to 64 KiB.

The service returns `normalized`: resolved airports (name, coordinates, IANA time zone), UTC times, distances, per-leg presentation seconds, defaults, a seed, and pinned renderer, asset, and airport-data versions. Read it to confirm the service understood the itinerary. Never send `normalized` back; edit `spec`.

### Warnings

Warnings never block saving. Each has `path` (where a fix would go in the spec), `code`, `message`, and `hint`.

| Code | When | Usually means |
| --- | --- | --- |
| `implausible_speed` | Average speed (great-circle distance ÷ block time) over 1,050 km/h, or under 250 km/h on a flight longer than 3 hours. Surface legs: over 350 km/h, or under 5 km/h on a leg longer than 12 hours | A wrong date, time, or airport |
| `long_block_time` | A flight longer than 19.5 hours (validation allows up to 30); never raised for surface legs | Arrival on the wrong day, or a stop that should be its own leg |
| `short_screen_time` | A flight on screen for less than 2 s | Too fast to follow |
| `compressed_connection` | A stop runs faster than 24 real hours per second on screen | Day and night flash past; lengthen the stop, or set it to 0 to cut |
| `far_future_or_past` | The journey starts more than 2 years from today | A typo in the year |
| `route_not_found` | A train, bus, car, or ferry leg has no matching railway, road, or ferry line in OpenStreetMap between its airports, so it is drawn straight | A wrong mode or airport; or a line OpenStreetMap lacks, which needs no fix |
| `route_unavailable` | The route lookup service didn't answer when the journey was saved; the leg is drawn straight for now | Nothing to fix; save again later to retry |
| `no_cloud_data` | Clouds are on, but part of the journey is before 22 March 2021 or more than 16 days after the save (not raised with `far_future_or_past`) | Nothing to fix; that part is drawn without clouds |

### Errors

Every error is JSON: `{"error": {"code", "message", "hint"?, ...}}`.

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `invalid_json`, `invalid_body`, `expected_revision_required`, `revision_required`, `invalid_idempotency_key`, `invalid_query` | Malformed request |
| 401 | `credential_required`, `session_expired` | Missing or expired credential |
| 403 | `owner_required`, `csrf_rejected` | Credential cannot do this |
| 404 | `not_found`, `publication_not_found`, `revision_not_found` | Unknown id, or credential does not match |
| 409 | `revision_conflict` | Draft changed; body has `currentRevision`, `spec`, `normalized` |
| 409 | `request_in_progress` | Same Idempotency-Key still running; retry shortly |
| 410 | `publication_deleted` | Owner deleted the journey |
| 413 | `payload_too_large` | Body over the size limit |
| 415 | `unsupported_media_type` | Use `Content-Type: application/json` |
| 422 | `validation_failed` | `issues[]` with `path`, `code`, `message`, `hint` |
| 422 | `idempotency_key_reused` | Same key, different body |
| 429 | `rate_limited` | Wait `retryAfterSeconds` (also in `Retry-After`) |
| 501 | `live_unavailable` | This server has no live channel; viewer and activity features are off |
| 403 (plain text `error code: 1010`) | — | Blocked by the hosting network's browser-signature check before reaching Route Replay. Set a descriptive `User-Agent` header and retry |

Validation issue codes include `unknown_field`, `required`, `type`, `unsupported_version`, `unsupported_preset`, `unsupported_aircraft`, `unsupported_mode`, `conflicting_fields`, `pattern`, `out_of_range`, `timestamp_format`, `invalid_date`, `offset_mismatch`, `unknown_airport`, `same_airport`, `antipodal_route`, `arrival_not_after_departure`, `flight_duration`, `disconnected_legs`, `overlapping_legs`, `duplicate_leg_id`, `unknown_leg_reference`, `hold_on_final_leg`, `journey_too_long`, and `duration_budget`.

### Limits and retention

- Creation is rate-limited per client and globally; writes are rate-limited per draft. Back off on `429`.
- Idempotency keys are remembered for 24 hours, scoped to the operation (and the draft, for publishing).
- Drafts are deleted after 180 days without changes. Published watch links stay until the owner deletes the draft.
- There are no accounts. Whoever holds the owner credential controls the draft. If it is lost, the draft cannot be published or deleted, and Route Replay cannot recover it.

### Privacy

Specs must not contain personal data beyond the journey itself. Route Replay stores the spec and its derived record, never your conversation or the creator's documents. Credentials are stored only as hashes. When a journey with train, bus, car, or ferry legs is saved, Route Replay's server sends the coordinates of each such leg's two airports, and whether to follow railways, roads, or ferry lines, to the routing services that trace it: BRouter (brouter.de) for trains, and OSRM at routing.openstreetmap.de (run by FOSSGIS) for buses, cars, and ferries. Nothing else from the journey goes with them: no times, title, other legs, or credentials. Routes are cached and shared between journeys, so a leg already traced for anyone isn't sent again. Video export runs entirely in the viewer's browser and uploads nothing; the bundled Remotion renderer reports only the site's origin and whether a render succeeded to Remotion's license service. Pages load Cloudflare Web Analytics, which counts page views and measures load times without cookies. It reports each page's address without its query or fragment, so the credential in a private link is never sent.
