Tourwright
Turn a script into a narrated product tour video: real browser, captions, voice, MP4.
Install
Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).
tourwrightclaude mcp add tourwright -e 'TOURWRIGHT_API_URL=<TOURWRIGHT_API_URL>' -e 'TOURWRIGHT_API_TOKEN=<your tourwright_api_token>' -- npx -y tourwright@2.1.0 mcp
{
"mcpServers": {
"tourwright": {
"command": "npx",
"args": [
"-y",
"tourwright@2.1.0",
"mcp"
],
"env": {
"TOURWRIGHT_API_URL": "<TOURWRIGHT_API_URL>",
"TOURWRIGHT_API_TOKEN": "<your tourwright_api_token>"
}
}
}
}
Environment variables
TOURWRIGHT_API_URLSend jobs to a Tourwright API instead of rendering on this machineTOURWRIGHT_API_TOKENsecret Token for TOURWRIGHT_API_URL
Documentation
From the project's README on GitHub, refreshed weekly. Links open on GitHub.
Scripted, narrated product tours. Write what should happen on screen and what should be said; Tourwright
films a real browser (or builds slides), guides the eye to each element, synthesizes the voice, and delivers
an .mp4 with captions, chapters, subtitles and a thumbnail. Built for people and AI agents, on any server, from a laptop to a cluster.
Made by Tourwright from examples/app.yaml, with nobody at the keyboard. ▶ Watch it with sound (52 s)
# tour.yaml
title: Your first invoice
voice: lessac
baseUrl: https://app.example.com
steps:
- goto: /invoices/new
- title: { text: Your first invoice, subtitle: Step by step }
- say: Pick the <b>customer</b> first.
- click: { role: combobox, name: Customer }
- say: Then save. That's it.
- click: { role: button, name: Save }
tourwright render tour.yaml # → videos/tour.mp4 (+ .srt .vtt .jpg .json)
Why Tourwright
Screen recorders (Loom) and click-through demo tools (Arcade, Supademo, Scribe) need a person to record, and every redesign means recording again. Tourwright videos are code:
| Screen recorder | Demo SaaS | Tourwright | |
|---|---|---|---|
| Re-record after a UI change | by hand | by hand | tourwright render |
| Knows when a video went stale | no | no | tourwright check in CI names the broken step and the fix |
| Narration | your voice, retakes | none or extra | text-to-speech in many voices, offline or online |
| Same tour for 50 customers or languages | 50 recordings | 50 demos | one script with {{variables}} |
| Personal data on screen | edit it out | edit it out | mask replaces it with invented data |
| Lives in | a vendor's cloud | a vendor's cloud | your git repo, your servers; MIT |
| AI agents can make one | no | no | MCP server and a Claude Code plugin |
What you get
- Browser walkthroughs: real Chromium, a smooth animated cursor, click ripples, highlights, spotlights, callout bubbles, camera zoom, drag and drop, blurred personal data, title cards and captions in your colors and logo.
- Guided focus: the tour an app shows the first time you open it. Everything dims but the element, a
ring marks it, a bubble with a
2/4badge explains it and the camera pushes in, right on the word the voice is saying. - Narrated slides: title cards, images (with slow pan/zoom), HTML, crossfades. No website needed.
- Voices, your choice: Pocket TTS (offline, open, natural:
tourwright install --pocket), Piper (offline, open source, light), Microsoft Edge neural voices, any OpenAI-compatible TTS server (OpenAI, Kokoro, LocalAI…), or your own command. Every sentence is cached: re-rendering never re-synthesizes. - A cast, and how each line is said: several voices per video, speed, pitch and volume per line on any
engine, exact pauses (
[[1s]]), a pronunciation dictionary, sound presets (warm, radio, podcast…), click, typing and other sound effects, music with fades. - Scripts that scale with you: variables (
{{name}}, also from the CLI or the API), reusable blocks, repeats, conditions and steps that may fail. One script, many videos. - Plugins: new actions, TTS engines and voices as small modules (docs/PLUGINS.md).
- Tight edits, automatically: page loads, slow waits and voice synthesis are cut out; narration never overlaps; background music ducks under the voice.
- Deliverables: H.264/AAC
.mp4with soft subtitles and chapters,.srt,.vtt, thumbnail and a JSON manifest (duration, chapters, captions) for automation. - Four ways in: CLI, HTTP API with job queue and webhooks, MCP server for AI agents, Node library.
- Scales out: stateless API replicas, any number of workers on any number of servers, Redis/BullMQ queue, S3-compatible storage. Or a single process with a folder, on a Raspberry Pi.
Install
Docker (recommended)
docker run --rm -v "$PWD:/work" -w /work ghcr.io/cxmiloxx/tourwright render examples/slides.yaml --out videos/
A full service (API + 2 workers + Redis):
cp .env.example .env # set TOURWRIGHT_API_TOKENS
docker compose up -d --build
docker compose up -d --scale worker=6
From npm (quickest to try)
Node.js 22+, on Linux, macOS or Windows:
npm install -g tourwright
tourwright install # ffmpeg, Piper + voices, edge-tts, Chromium (no root)
tourwright install --plan # only show what it would use from this PC and what it would download
tourwright config set quality fullhd # your own defaults: quality, voice, fps… (tourwright config lists them)
tourwright record https://app.example.com --out tour.yaml # do the tour by hand: it writes the script
tourwright guide tour.yaml --open # the same tour as a step-by-step guide with screenshots (HTML, PDF, Markdown)
tourwright narrate tour.yaml --write # your AI (Claude, OpenAI, Ollama) rewrites the narration from the screens
tourwright check videos/*.yaml # which videos broke after a deploy, at which step, and the fix
tourwright fix tour.yaml --write # puts the new targets in the script
tourwright render tour.yaml --step 7 # film one step with its voice, without the whole video
tourwright install --pocket # + Pocket TTS: natural offline voices (about 1 GB)
tourwright clean # what each part takes on disk; removes downloads and leftovers
tourwright doctor # what works on this machine
Without installing anything globally: npx tourwright <command>. With pnpm: pnpm add -g tourwright
(on 2.0.0, add --no-optional).
The Redis queue and Claude for narrate are optional: install bullmq ioredis or @anthropic-ai/sdk next to
Tourwright when you use them (npm install -g bullmq ioredis). The Docker image already has them.
Without Docker (Linux, macOS, Windows)
Node.js 22+. tourwright install puts ffmpeg, Piper, voices, edge-tts and Chromium in TOURWRIGHT_HOME, with no
root or admin rights; what the system already has is kept.
git clone https://github.com/CXmiloxx/tourwright && cd tourwright
./scripts/install.sh # Linux / macOS (Windows: powershell -ExecutionPolicy Bypass -File scripts\install.ps1)
node bin/tourwright.js doctor # what works on this machine
npm link # optional: the `tourwright` command
Each piece is looked for on the PC first and only downloaded when it is missing:
| Linux (x64, arm64) | macOS (Intel, Apple Silicon) | Windows 10/11 (x64, ARM) | |
|---|---|---|---|
| Chromium | Chrome, Edge or Chromium (apt, dnf, pacman, Raspberry Pi OS), else downloaded | Chrome, Edge or Chromium, else downloaded | Chrome or Edge, else downloaded |
| ffmpeg | PATH, Homebrew, Nix, else downloaded | Homebrew, MacPorts, Nix, else brew install ffmpeg | PATH, winget, scoop, Chocolatey, C:fmpeg, else downloaded |
| Piper (offline voices) | PATH, pip, pipx, conda, else downloaded | PATH, pip, pipx, conda, else piper-tts | PATH, pip, pipx, conda, else downloaded |
| Piper voices | Hugging Face cache, TOURWRIGHT_PIPER_VOICE_DIRS, else downloaded | same | same |
| edge-tts (Microsoft voices) | PATH, pip, pipx, conda, else installed | same | same |
| Python (for edge-tts, Pocket, Whisper) | the system's 3.10–3.13, else 3.12 is downloaded | same | same (not the Microsoft Store stub) |
| Capture | screen with Xvfb (sharpest), else screencast | screencast | screencast |
Also reused: a Chromium left by another Playwright or Puppeteer version, and CHROME_PATH, CHROME_BIN or
PUPPETEER_EXECUTABLE_PATH. Snap and Flatpak browsers are skipped (their sandbox blocks Playwright).
TOURWRIGHT_SYSTEM_BROWSER=0 always uses Playwright's own Chromium. tourwright doctor shows what was found.
Nothing is installed on the system: what is downloaded lives in one folder (TOURWRIGHT_HOME), and the Python
packages run in a virtual environment, so yours is never changed. To uninstall, delete that folder.
Xvfb (apt install xvfb, Linux only) gives the sharpest capture; without it Tourwright records headless
(screencast), which works everywhere Chromium runs. Clients of the HTTP API or MCP can be on any system.
Use it
From a site to a video, without writing selectors by hand:
tourwright explore https://app.example.com/login --draft app.yaml # asks for the login, writes the script
tourwright render app.yaml --dry-run # checks every step in seconds
tourwright render app.yaml --open # the video, in ./videos/app/
The draft goes through every section of the site with narration taken from its pages; edit it in your words.
Credentials are asked for once, never shown and never written in the script (tourwright secret list;
tourwright forget deletes them).
tourwright init video.yaml # an example script
tourwright validate video.yaml
tourwright render video.yaml --dry-run # runs every step fast: tests selectors, no voice/video
tourwright render video.yaml --quality fullhd --voice salome --out out/
tourwright voices # voices available here
tourwright install-voice en_GB-alba-medium # any voice from huggingface.co/rhasspy/piper-voices
tourwright say "Hello there" --voice lessac --out hello.wav
The script format, every action and the voices: docs/SCRIPTS.md.
JSON Schema for editors and agents: schema/script.schema.json.
HTTP API
TOURWRIGHT_API_TOKENS=secret tourwright serve --worker --port 4700
curl -X POST localhost:4700/v1/jobs -H 'authorization: Bearer secret' -H 'content-type: application/json' \
-d '{"script": {"type": "slides", "slides": [{"title": "Hello", "say": "Hello from the API."}]}}'
curl localhost:4700/v1/jobs/<id> -H 'authorization: Bearer secret' # → status, result, download links
Endpoints, assets, webhooks: docs/API.md.
AI agents (MCP)
Claude Code, as a plugin (the MCP server plus a skill that writes, checks and renders the script):
/plugin marketplace add CXmiloxx/tourwright
/plugin install tourwright@tourwright
Any other MCP client (Claude Desktop, Cursor, VS Code…):
{ "mcpServers": { "tourwright": { "command": "tourwright", "args": ["mcp"] } } }
Tools: tourwright_guide, tourwright_voices, tourwright_validate, tourwright_render, tourwright_job (and
tourwright_render_file with TOURWRIGHT_MCP_ALLOW_FILES=true). Point it at a remote API with TOURWRIGHT_API_URL
and TOURWRIGHT_API_TOKEN. Details: docs/AGENTS.md.
GitHub Action
Re-render your tours on every release, or fail the build when a deploy broke one:
- uses: CXmiloxx/tourwright@v2
with:
scripts: videos/*.yaml
command: check # or render: the videos become a workflow artifact
env:
TOURWRIGHT_SECRET_APP_PASSWORD: ${{ secrets.APP_PASSWORD }}
Inputs: scripts, command, out, voice, quality, voices, version, upload (action.yml).
Node library
import { loadFile, render } from 'tourwright'
const result = await render(await loadFile('tour.yaml'), { out: 'videos/', quality: 'hd' })
console.log(result.paths.video, result.duration, result.chapters)
Scaling
| Size | Setup |
|---|---|
| One machine | tourwright serve --worker — local folder queue, files on disk |
| One big machine | docker compose up --scale worker=N — Redis queue, shared volume |
| Many machines | API replicas behind a load balancer, workers anywhere, same Redis + S3 bucket |
| Kubernetes | deploy/kubernetes/tourwright.yaml, workers autoscaled |
Each worker renders TOURWRIGHT_CONCURRENCY videos at a time (one Chromium + ffmpeg each: plan ~1–2 CPU and
~1 GB RAM per video at 720p). Workers run at low CPU and disk priority so a shared server stays responsive.
More: docs/DEPLOYMENT.md · configuration: docs/CONFIGURATION.md.
Security
API jobs run in a sandbox: data-only scripts (no JavaScript), files limited to the job's assets, optional host allowlist and private-network blocking, secrets off by default, per-token job isolation, signed download links. Read SECURITY.md before exposing the API to untrusted clients.
License
MIT. Piper voices have their own licenses (see each voice's model card); Edge voices are a Microsoft online service, check its terms for your use.
Frequently asked questions
What is Tourwright?
Turn a script into a narrated product tour video: real browser, captions, voice, MP4.
How do I install Tourwright?
It runs on your machine. In Claude Code: claude mcp add tourwright -e 'TOURWRIGHT_API_URL=<TOURWRIGHT_API_URL>' -e 'TOURWRIGHT_API_TOKEN=<your tourwright_api_token>' -- npx -y tourwright@2.1.0 mcp. For other clients, paste the JSON configuration from this page into their MCP settings.
Does Tourwright need an API key?
Yes. It expects TOURWRIGHT_API_TOKEN, which you set in its configuration.
Is Tourwright open source?
Yes. Its code is on GitHub under the MIT license.
Who maintains Tourwright?
It is published by CXmiloxx. AI.tn lists it but does not maintain or endorse it.
From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.