Self-hosted light show viewer control server. A drop-in alternative to Remote Falcon for hobbyists who want to run their own infrastructure without relying on a cloud service.
ShowPilot pairs with a Falcon Player (FPP) plugin to let your visitors:
- 🎵 Vote for sequences (Voting mode), queue them up (Jukebox mode), or tap-race for the next song (Race mode)
- 📱 Listen to your show audio on their phone via a built-in web player, kept in sync with the show — no app required
- 🎄 See what's playing now and what's coming up next on a customizable viewer page
You get an admin with a live dashboard, a tablet show-remote mode (Cockpit), stats, queue management, sequence configuration, a viewer-page designer, theming, backups, in-app updates, and multi-user authentication.
Migrating from Remote Falcon? ShowPilot's viewer page renderer is fully compatible with Remote Falcon templates. All the standard placeholders (
{PLAYLISTS},{NOW_PLAYING},{JUKEBOX_QUEUE},{NEXT_PLAYLIST},{QUEUE_DEPTH},{LOCATION_CODE}, etc.) and mode containers ({playlist-voting-dynamic-container},{jukebox-dynamic-container},{after-hours-message},{location-code-dynamic-container}) work identically. Paste your existing Remote Falcon viewer HTML into ShowPilot's editor and it just works — no template rewrite needed. If something doesn't render quite right out of the box (older RF templates sometimes lack a few of the toast hooks or the after-hours setup ShowPilot expects), drop your HTML into the RF Template Converter — it adds the missing pieces, flags layout traps, and gives you back a paste-ready ShowPilot template.
- Voting, Jukebox & Race modes — let viewers vote for the next sequence, queue songs to play in order, or race to tap their pick to a target first. Optional tiebreak round when a vote ends tied
- Listen-on-Phone audio player — your show audio, served by ShowPilot and kept in sync with FPP. Phones continuously correct toward FPP's playback position with inaudible speed nudges, and song changes reach them in real time. No native app, no extra service, no Icecast setup. Works on iOS Safari, Android Chrome, and desktop browsers
- Alternate-language audio — optional extra audio tracks per sequence (for example a translated version) that listeners can choose in the player
- Larger player on phones (optional) — a two-row player on phones with the full song title and bigger, spread-out controls, turned on in the admin
- Sync debug tools — under Settings → Debug (off by default): a microphone "Measure sync" button that reports how far the show speakers are from a phone, and a sync probe that checks the relay against FPP directly
- Listener audio timing — phones can't see Bluetooth or car-stereo delay, so listeners can shift the sound earlier or later from a small timing button in the player until it lines up with the lights (big "music is late / early" buttons, a fine slider and presets). Saved on that phone only; you can turn the button off, and set the slider's range, in the admin. A collapsible Audio Sync Help block for the viewer page, and a tip inside the timing sheet, explain how to use it
- Mobile-first viewer page — designed for cold winter hands tapping with gloves. Large hit targets, high-contrast cards, marquee-scrolling long titles, optional page-wide effects (snow, leaves, fireworks, hearts, stars, bats, confetti, petals, embers, bubbles, rain), optional themed player decorations (Christmas, Halloween, Easter, St. Patrick's, Independence Day, Valentine's, Hanukkah, Thanksgiving, generic snow)
- Cover art support — automatic MusicBrainz/iTunes cover lookup per sequence with admin override, displayed inline on song cards
- Now Playing + Up Next — real-time updates pushed via Socket.io, plus polled fallback for slower connections
- Song progress bar (optional) — a slim bar with time left, on top of the Listen-on-Phone player in its theme color (or across the top of the page). Templates can also place
{NOW_PLAYING_PROGRESS}or the{NOW_PLAYING_TIMER}countdown anywhere - Song categories — group sequences under headings on the viewer page, and switch whole categories on or off
- Viewer page translation (optional) — visitors can read the viewer page in their own language
- Three editing modes — pick what fits your comfort level:
- Settings mode: form-based editor for show name, colors, fonts, hours, social links, FM frequency. No HTML knowledge required
- Blocks mode: drag-and-drop sections onto a canvas — 13 block types covering Hero, Text, Divider, Show Hours, Now Playing, Up Next, Queue, Voting Instructions, Jukebox Instructions, Song List, Location Code, Social Links, and Custom HTML. Reorder by dragging or with arrow buttons
- Code mode: full Monaco editor for hand-written HTML. Standard Remote Falcon placeholders supported
- Live preview iframe — see your changes update next to the editor as you type, before committing
- Drafts — edits save as drafts automatically (debounced 500ms). Visitors keep seeing the live page until you click Save Changes
- Multiple templates — create as many templates as you want and switch active ones with one click. Build separate looks for different seasons or events
- Default template included — fresh installs get a working mobile-friendly template seeded automatically; customize from there
- GPS audio gate (optional) — restrict audio playback to listeners physically present at your show. Tapping the 🎧 button forces a fresh GPS check (cached location won't bypass it). Re-checks every 5 minutes during playback to catch listeners who walked away
- Refresh-to-recover latch — once the gate trips, audio stays blocked until the page is refreshed. Prevents auto-resume when admin toggles control modes
- External audio access — set your public base URL (your domain) so listeners on cellular can stream the audio without VPN, or let ShowPilot set up a Cloudflare Tunnel for you under Settings → Public Access. Local listeners still use the direct path for best performance
- Address-to-coordinates lookup — type any address ("1234 Main St, Branson MO"), click Find Coordinates, lat/lng auto-fill. Powered by OpenStreetMap Nominatim
- Detect-my-location button — uses browser GPS to set show coordinates if you're at the venue
- Visual map preview — embedded OpenStreetMap shows exactly where your coordinates point, scales to your radius. Verify your config without leaving admin
- Companion FPP plugin (ShowPilot Blackbox, FPP 10+) — install it from FPP's Plugin Manager, point it at your ShowPilot server URL, and it stays connected. It handles sequence sync, playing-status reporting, viewer request handoff to FPP, and the precise playback position phones sync their audio to
- Song cooldowns — keep a song from being requested again for a while after it plays; optionally also skip cooled-down songs in FPP's normal playlist rotation (the plugin skips ahead without editing your playlists)
- Sequence sync — sequences imported from FPP into the admin, where you can reorder, rename for display, set artists, hide individual sequences, and toggle votable/jukeboxable per sequence
- Mid-track resume — when a viewer-requested song interrupts the original, resuming the original picks up at the correct elapsed position (not the start)
- PSA injection — auto-inject PSAs (sponsor messages, holiday greetings) every N interactions
- Real-time plugin status — admin header shows whether FPP plugin is connected and last sync time, updated live via Socket.io
- Redesigned admin — every section and settings page in a collapsible sidebar, a live dashboard with an On Air panel, and a slide-out menu on phones and tablets. Each admin can switch back to the classic layout anytime
- Cockpit (tablet mode) — a big-button show remote for a tablet at the booth that you lay out yourself: drag in the tiles you want (viewer control, modes, reset/purge, safeguard switches, song categories, page effect and template, status readouts, the now-playing countdown, live vote/queue and song lists), resize and reorder them. Each admin's layout is saved to their account
- Multi-user authentication — username + password, bcrypt hashed, JWT session cookies. Per-user "remember me" (30-day cookie or session-only). Force-password-change flag for new accounts
- User management — add/edit/disable/delete users. Self-protection: can't disable yourself, can't delete the last user
- Themes — Stage·Dark and Stage·Light core themes for the admin UI, plus seasonal variants (Christmas, Halloween, Easter, St. Patrick's, Independence Day, Valentine's) you can switch between
- Sequence snapshots — save your current playlist configuration (display names, artists, sort order, visibility) as a named snapshot. Restore later when switching seasons. Non-destructive: preserves play history, vote stats, queue state
- Live stats dashboard — votes per round, jukebox queue depth, plays per sequence, last-played times, viewer count, plus visitor charts over time
- Viewer QR code — ready-to-print QR code for your viewer page
- Backup & restore — download a full backup from Settings → Backup & Restore and restore it on the same or a new install (including on a fresh install before first sign-in)
- In-app updates — check for and apply new versions from Settings → Updates. When a newer beta exists, a separate beta channel installs it for debugging — not stable, and not for general use
- IP blocking — block individual IPs or CIDR ranges. Useful when one user gets too enthusiastic with the request button
- Per-sequence visibility/votability/jukeboxability — fine-grained control over what shows up where
- Auto-fill song info — looks up sequence titles online to populate display name + artist automatically (no more "JinglePopXmas2019_v3.fseq" shown to viewers)
- GPS proximity check — separate from the audio gate; restricts who can vote/queue based on their physical location
- Configurable request limits — per-viewer cap on jukebox requests per session (1-20)
- No cloud dependency — runs on a Pi, a NAS, a VM, anywhere with Node.js
- SQLite database — single file, easy backup, no separate database server
- Open source — MIT-licensed, hackable, no vendor lock-in
- No telemetry — your data stays on your hardware
The viewer page uses browser geolocation APIs for the GPS audio gate and GPS proximity check. Browsers refuse to expose location data on insecure (http://) origins — this is a hardcoded security restriction, not something ShowPilot controls.
If you plan to use any location-based feature, you must serve ShowPilot over HTTPS. Options:
- Nginx Proxy Manager (easiest) with a Let's Encrypt cert — point it at ShowPilot on port 3100
- Caddy with automatic HTTPS — single-line reverse proxy config
- Cloudflare Tunnel — free TLS without opening ports
- Standalone reverse proxy (Nginx/Apache) with your own cert
Localhost (http://localhost:3100 or http://127.0.0.1:3100) is also exempt from this restriction, so local development works without HTTPS. But anything visitors hit needs a cert.
If you don't use any location features, plain HTTP is fine.
- Features
- Requirements
- Install on Linux (Debian/Ubuntu/Raspberry Pi OS)
- Install on Linux (RHEL/Fedora/Rocky/Alma)
- Install on macOS
- Install on Windows
- Install with Docker
- First-run setup
- Install the FPP plugin
- Configuration reference
- Running as a service
- Updating
- Backups
- Troubleshooting
| Component | Minimum | Recommended |
|---|---|---|
| Node.js | 18.x | 20.x or 22.x LTS |
| RAM | 256 MB | 512 MB+ |
| Disk | 100 MB for app + your data | 1 GB+ if storing many cover art images |
| OS | any modern Linux, macOS 11+, Windows 10+ | Linux for production |
| FPP | 10.0+ on a separate device (Pi, BeagleBone, etc.) — required by the ShowPilot plugin | latest stable |
Network: ShowPilot listens on TCP port 3100 by default. The FPP plugin needs to reach this port. Visitors hit the same port (or whatever you front it with).
These instructions cover Debian 11+, Ubuntu 22.04+, Raspberry Pi OS Bookworm+. The exact same commands work on a Raspberry Pi 4/5 if you want to colocate ShowPilot with FPP on a single Pi (4GB+ RAM recommended).
The Node.js version in your distro repos is usually too old. Use the official NodeSource installer:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs build-essentialVerify:
node --version # should print v20.x.x or higher
npm --version# Pick a location. /opt is conventional for self-hosted apps.
sudo mkdir -p /opt/showpilot
sudo chown $USER:$USER /opt/showpilot
cd /opt/showpilot
# Download the latest release (the main branch always holds the latest release)
wget https://github.com/ShowPilotFPP/ShowPilot/archive/refs/heads/main.tar.gz
tar -xzf showpilot.tar.gz --strip-components=1
rm showpilot.tar.gz
# Or clone via git if you prefer:
# git clone https://github.com/ShowPilotFPP/ShowPilot.git .
# Install Node dependencies
npm install --omit=devShowPilot works out of the box with no configuration — secrets are auto-generated on first run and persisted to data/secrets.json. If you want to tweak ports, paths, or other settings:
cp config.example.js config.js
nano config.jsThe most useful setting to think about is trustProxy:
- Direct exposure (port forward, no proxy): keep
trustProxy: false(the default) - Behind a reverse proxy (Nginx Proxy Manager, Caddy, Cloudflare Tunnel, etc.): set
trustProxy: 1
For environments where you'd rather inject secrets at runtime (Kubernetes, Docker secrets, etc.), set the SHOWPILOT_JWT_SECRET and SHOWPILOT_SHOW_TOKEN environment variables — they take precedence over both config.js and auto-generation.
npm startOn the very first run, you'll see a one-time announcement with your auto-generated show token — that's the value you'll paste into the FPP plugin config. You can also retrieve it anytime in the admin UI under Settings → Plugin → Show Token.
You should see ShowPilot listening on http://0.0.0.0:3100. Open http://<your-server-ip>:3100/admin in a browser.
Default login: admin / admin — you'll be forced to change the password on first login.
For production, see Running as a service below to keep ShowPilot running on boot.
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo dnf install -y nodejs gcc-c++ makeVerify:
node --version
npm --versionsudo mkdir -p /opt/showpilot
sudo chown $USER:$USER /opt/showpilot
cd /opt/showpilot
curl -L https://github.com/ShowPilotFPP/ShowPilot/archive/refs/heads/main.tar.gz \
-o showpilot.tar.gz
tar -xzf showpilot.tar.gz --strip-components=1
rm showpilot.tar.gz
npm install --omit=devSame as Debian/Ubuntu (sections 3 and 4 above).
If firewalld is enabled, you'll need to open port 3100:
sudo firewall-cmd --permanent --add-port=3100/tcp
sudo firewall-cmd --reloadUseful for development and testing on a Mac mini or laptop. Production typically runs on a Pi or VPS, but macOS works fine.
The easiest path is Homebrew:
brew install node@20Or download the official installer from nodejs.org.
mkdir -p ~/showpilot
cd ~/showpilot
curl -L https://github.com/ShowPilotFPP/ShowPilot/archive/refs/heads/main.tar.gz \
-o showpilot.tar.gz
tar -xzf showpilot.tar.gz --strip-components=1
rm showpilot.tar.gz
npm install --omit=devnpm startSecrets auto-generate on first run. Optional: copy config.example.js to config.js if you want to customize ports, paths, or trustProxy.
Open http://localhost:3100/admin. Default login admin / admin.
To run as a background service, use launchd — see Running as a service below.
Tested on Windows 10 and 11.
Download the LTS installer from nodejs.org and run it. Accept defaults — make sure "Automatically install the necessary tools" is checked (it installs build tools needed by better-sqlite3).
Open PowerShell and verify:
node --version
npm --versionPick a folder (e.g. C:\ShowPilot):
New-Item -ItemType Directory -Force -Path C:\ShowPilot
Set-Location C:\ShowPilot
# Download the latest release
Invoke-WebRequest -Uri https://github.com/ShowPilotFPP/ShowPilot/archive/refs/heads/main.tar.gz -OutFile showpilot.tar.gz
# Extract (Windows 10 1803+ has tar built in)
tar -xzf showpilot.tar.gz --strip-components=1
Remove-Item showpilot.tar.gz
npm install --omit=devnpm startSecrets auto-generate on first run. Optional: Copy-Item config.example.js config.js if you want to customize ports, paths, or trustProxy.
Open http://localhost:3100/admin. Default login admin / admin.
If Windows Firewall prompts you, allow the Node.js process to communicate. To run as a Windows service, use NSSM — see Running as a service.
Multi-architecture images (amd64 + arm64) are published to GitHub Container Registry. Pull, configure, run — no build step required.
Image: ghcr.io/showpilotfpp/showpilot:latest
Tags: browse all available tags
# Make a working directory
mkdir showpilot && cd showpilot
# Pull the image (this is what `docker compose up` will do automatically,
# but pulling explicitly first lets you confirm connectivity to GHCR)
docker pull ghcr.io/showpilotfpp/showpilot:latest
# Set up data directory (config.js is OPTIONAL — see below)
mkdir showpilot-data
# Download the compose file
curl -O https://raw.githubusercontent.com/ShowPilotFPP/ShowPilot/main/docker-compose.yml.example
mv docker-compose.yml.example docker-compose.yml
# Edit if you need to change the port mapping
nano docker-compose.yml
# Start it
docker compose up -d
# Watch the logs as it boots — your auto-generated show token will be
# printed here on first run (you'll need it to configure the FPP plugin).
docker compose logs -fThen open http://<your-host>:3100/admin and continue with First-run setup.
Optional: customize config. ShowPilot works out of the box with default settings + auto-generated secrets. If you want to change ports, paths, or trustProxy:
mkdir showpilot-config
curl -O https://raw.githubusercontent.com/ShowPilotFPP/ShowPilot/main/config.example.js
mv config.example.js showpilot-config/config.js
nano showpilot-config/config.js
# Then uncomment the config volume in docker-compose.ymlFor Docker secrets / Kubernetes environments, you can inject SHOWPILOT_JWT_SECRET and SHOWPILOT_SHOW_TOKEN as environment variables and skip both config.js and the auto-generated secrets file entirely.
Notes for Docker users:
- The container runs as a non-root
nodeuser (UID 1000). If you bind-mount the data directory, make sure your host directory is writable by UID 1000 —chown -R 1000:1000 showpilot-dataif needed. - The data volume holds the SQLite database (
showpilot.db) and cover-art uploads (covers/). Back this up regularly. - For HTTPS, put the container behind your existing reverse proxy (Nginx Proxy Manager, Traefik, Caddy). HTTPS termination at the proxy is the supported pattern — no built-in TLS in the container.
- Updating:
docker compose pull && docker compose up -d. Schema migrations run automatically on container start. - Pin to a specific version by editing
image:indocker-compose.ymlfrom:latestto a specific tag like:0.18.5. See available tags at ghcr.io/ShowPilotFPP/ShowPilot. - Testing a beta (debugging only): beta builds are unstable test versions — don't use them unless you know what you're doing. Download a backup first (Settings → Backup & Restore), then change
image:toghcr.io/showpilotfpp/showpilot:betaand rundocker compose pull && docker compose up -d. Watchtower keeps a:betacontainer on the latest beta. To return, change the tag back to:latestand pull again; your data volume carries over. - Want to build the image yourself instead of pulling? See the alternative
build:block indocker-compose.yml.example.
- Open
http://<your-server-ip>:3100/admin - Log in with
admin/admin - Change the default password (you'll be prompted)
- Go to Plugin tab → copy the Show Token (you'll paste this into FPP)
- Optionally go to Users tab and add accounts for anyone else who needs admin access
- Go to Settings tab → review jukebox/voting safeguards and configure External Audio Access if you want listeners outside your network to be able to hear the show
- Configure your viewer page on the Viewer Page tab (use the default ShowPilot template or import the example template provided)
The FPP plugin (ShowPilot Blackbox) reports playback to ShowPilot, hands off requested sequences to FPP, and provides the precise playback position that keeps phone audio in sync. It requires FPP 10.0 or newer.
- In the FPP web UI, go to Content Setup → Plugin Manager
- Paste this into the plugin URL box, click Get Plugin Info, then Install:
https://raw.githubusercontent.com/ShowPilotFPP/ShowPilot-plugin/main/pluginInfo.json - Open the plugin's settings from Content Setup → ShowPilot
- Fill in:
- Server URL:
http://<your-showpilot-server-ip>:3100(no trailing slash; use yourhttps://domain if the server is outside your home network) - Show Token: paste the token you copied from ShowPilot's Plugin tab
- Remote Playlist: the FPP playlist that contains your viewer-controllable sequences
- Interrupt schedule: enable if you want viewer picks to play immediately instead of after the current song
- Server URL:
- Click Sync Now — your sequences appear in ShowPilot's admin
- ShowPilot shows the plugin as connected (FPP status in the admin sidebar) within a few seconds
If it doesn't connect, check the plugin's log in the FPP UI under Status/Control → Logs (plugin-showpilot-plugin.log) or the plugin's Diagnostics tab. See the plugin README for details.
config.js (created from config.example.js):
| Key | Default | Notes |
|---|---|---|
port |
3100 |
TCP port to listen on |
host |
0.0.0.0 |
Bind address. Use 127.0.0.1 to restrict to localhost only |
dbPath |
./data/showpilot.db |
SQLite DB path. Created automatically. |
trustProxy |
false |
Set to 1 (or the number of proxy hops) when ShowPilot sits behind a reverse proxy / Cloudflare Tunnel, so visitor IPs are read correctly |
jwtSecret |
null |
Signs session cookies. Leave null to auto-generate a random secret on first run (saved in data/secrets.json), or set SHOWPILOT_JWT_SECRET |
sessionCookieName |
showpilot_session |
Browser cookie name |
sessionDurationHours |
720 (30 days) |
Default session length when "remember me" is off; remember-me always extends to 30d |
showToken |
null |
Shared secret between ShowPilot and the FPP plugin. Leave null to auto-generate (printed on first run and shown in the admin's Plugin tab), or set SHOWPILOT_SHOW_TOKEN |
viewer.activeWindowSeconds |
30 |
How recently a viewer must have heartbeat'd to count as "active" |
viewer.pollIntervalMs |
5000 |
Viewer page state poll fallback (when socket disconnects) |
viewer.maxJukeboxRequestsPerViewer |
1 |
Default request limit (the admin's Interaction Safeguards setting takes over once saved) |
viewer.maxVotesPerRound |
1 |
Default votes per viewer per round |
voting.resetAfterWinnerPlays |
true |
Start a new voting round after the winner plays |
demoMode |
false |
Public demo instance: resets itself every demoResetIntervalMinutes and shows demoCredentialsHint on the login page |
logLevel |
info |
debug / info / warn / error |
Most operational settings (jukebox depth, vote rules, viewer-page HTML, theme, snow effect, etc.) live in the admin panel UI, not in config.js.
Create /etc/systemd/system/showpilot.service:
[Unit]
Description=ShowPilot
After=network.target
[Service]
Type=simple
User=showpilot
WorkingDirectory=/opt/showpilot
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetNote:
Restart=alwaysis required (notRestart=on-failure). ShowPilot's in-app updater exits cleanly (code 0) after downloading an update so the new code is picked up on restart —on-failurewon't restart on a clean exit, leaving ShowPilot stopped after an update. If you have an existing install withRestart=on-failure, fix it with:sudo sed -i 's/Restart=on-failure/Restart=always/' /etc/systemd/system/showpilot.service sudo systemctl daemon-reload
Then:
# Create the service user
sudo useradd -r -s /bin/false -d /opt/showpilot showpilot
sudo chown -R showpilot:showpilot /opt/showpilot
sudo systemctl daemon-reload
sudo systemctl enable --now showpilot
sudo systemctl status showpilot
# View logs
sudo journalctl -u showpilot -fsudo npm install -g pm2
cd /opt/showpilot
pm2 start server.js --name showpilot
pm2 startup # follow the printed instructions
pm2 saveCreate ~/Library/LaunchAgents/com.showpilot.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.showpilot</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/node</string>
<string>/Users/YOURNAME/showpilot/server.js</string>
</array>
<key>WorkingDirectory</key>
<string>/Users/YOURNAME/showpilot</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/YOURNAME/showpilot/showpilot.log</string>
<key>StandardErrorPath</key>
<string>/Users/YOURNAME/showpilot/showpilot.log</string>
</dict>
</plist>Replace YOURNAME and the node path (find with which node). Then:
launchctl load ~/Library/LaunchAgents/com.showpilot.plistNSSM wraps any program as a Windows service.
# Download and extract NSSM, then:
.\nssm.exe install ShowPilotIn the GUI that opens:
- Path:
C:\Program Files\nodejs\node.exe - Startup directory:
C:\ShowPilot - Arguments:
server.js
Click Install service, then start it:
nssm start ShowPilot
# Or in services.msc, find "ShowPilot" and start itcd /opt/showpilot
sudo systemctl stop showpilot # or pm2 stop showpilot
# Backup first
cp -r data data.backup-$(date +%F)
# Get the new version
wget -O showpilot.tar.gz https://github.com/ShowPilotFPP/ShowPilot/archive/refs/heads/main.tar.gz
tar -xzf showpilot.tar.gz --strip-components=1
rm showpilot.tar.gz
npm install --omit=dev
sudo systemctl start showpilotDatabase migrations run automatically on startup. Your config and data are preserved.
cd /opt/showpilot
git pull
npm install --omit=dev
sudo systemctl restart showpilotThe whole application state lives in two places:
config.js— your secrets and bind configdata/directory — SQLite database, cover art images, viewer page templates
Back both up:
# Full backup
tar -czf showpilot-backup-$(date +%F).tar.gz config.js data/Restore is just extracting the backup back into the install directory.
To dump just the SQLite DB for inspection or migration:
sqlite3 data/showpilot.db .dump > showpilot.sql- Verify the
showTokeninconfig.jsexactly matches what you entered in the FPP plugin config - Check FPP can reach ShowPilot:
curl http://<showpilot-ip>:3100/api/plugin/state -H "remotetoken: YOUR_TOKEN" - Check the plugin log on FPP: web UI → Status/Control → Logs →
plugin-showpilot-plugin.log(or the plugin's Diagnostics tab) - Make sure FPP is 10.0 or newer — the plugin doesn't support older versions
- Restart the plugin listener via the FPP web UI
ShowPilot needs to be reachable from the public internet for off-network audio. Either:
- Set up a reverse proxy with a public domain, then enter that domain as the Public base URL in the admin settings
- Or use a Cloudflare Tunnel for a domain without exposing your home IP — ShowPilot can set one up for you under Settings → Public Access
Reset directly in the database:
cd /opt/showpilot
sqlite3 data/showpilot.db "DELETE FROM users WHERE username='admin';"
# Then restart ShowPilot. If no users are left, it re-seeds the default admin/admin user.If you have a working admin account, just use the Users tab → Reset PW for any other user.
Edit config.js, change port to something free (e.g. 3101), restart.
The service user (showpilot if following systemd setup) needs write access to data/ for SQLite:
sudo chown -R showpilot:showpilot /opt/showpilot/dataIn admin → Sequences, click Fetch Covers to re-pull all sequence covers (MusicBrainz / Cover Art Archive, then iTunes). If a specific cover is wrong, click on it directly to upload or replace.
# systemd
sudo journalctl -u showpilot -f --since "10 minutes ago"
# pm2
pm2 logs showpilotshowpilot/
├── server.js # Express app + Socket.io server
├── config.js # Your config (gitignored)
├── config.example.js # Template config
├── package.json
├── lib/
│ ├── db.js # SQLite schema, migrations, helpers
│ ├── viewer-renderer.js # Server-side template rendering for the viewer page
│ ├── cover-art.js # MusicBrainz / iTunes cover lookup, cache-busting
│ ├── audio-position-relay.js # FPP playback position relay for phone audio sync
│ ├── categories.js # Sequence categories
│ └── ...
├── routes/
│ ├── admin.js # /api/admin/* endpoints
│ ├── viewer.js # /api/* viewer endpoints + audio streaming
│ └── plugin.js # /api/plugin/* (FPP plugin talks here)
├── public/
│ ├── admin/ # Admin (index.html; ui-new.css/js = new layout; cockpit.html = tablet mode)
│ ├── viewer.html # Default viewer page template
│ └── rf-compat.js # Viewer-side audio player + visual effects
└── data/ # SQLite + cover art (gitignored)
MIT. Use it however you like — just don't blame me if your show breaks on Halloween night.
Issues and PRs welcome at https://github.com/ShowPilotFPP/ShowPilot
If you have ideas, find bugs, or want to share what your show looks like running on ShowPilot — please post in the xLights forum or open a GitHub issue.
Have fun, and Merry Christmas / Happy Halloween / etc! 🎄🎃🎆