Documentation
Everything about setting up and running Snappier Server. New here? The setup guide is the quickest start, and the setup wizard does most of the work.
Setup Details
Every step in a little more detail — most people only need the first two, because the setup wizard does the rest.
Every step in a little more detail. The command line has no window or icon — you run it in a terminal, and the setup wizard in your browser does the rest.
1 Install the app
Download it for macOS (13 or later, Apple Silicon or Intel) or Windows (10 or later, x64 or ARM64) and install it. Everything it needs is inside, FFmpeg (the video engine) included. The downloads page helps you pick the right file.
2 Open it
Snappier Server has no window of its own. It runs in the background, with an icon you use to control it:
- macOS: in the menu bar, top right. There is no Dock icon.
- Windows: in the system tray, bottom right — click the ^ arrow if you can't see it.
Click the icon for everything: start and stop the server, the dashboard, Preferences, the setup wizard, the server log. The server listens on port 8000 unless you change it in Preferences.
3 The setup wizard
The first time you open the app, the setup wizard opens in your browser, already signed in. It asks what you want to watch, then asks for each thing it needs one at a time — your IPTV provider (or just paste the playlist link your provider sent), Plex, Emby or Jellyfin, a catalog source (lists of films and series for the app to browse) and its free TMDB key (for posters and details). Every login is tested before you move on, and nothing is saved until the end. It finishes by creating a login for the Snappier IPTV app and showing you the details to type in.
- Click the Snappier Server icon and choose Set Up Snappier Server….
- Greyed out, or a message says the server is not running? Choose Start Server first. If that fails, a notification says why — usually another program is using port
8000; pick another port in Preferences. - It opens by itself only on a new install: once you have added a provider, media server or catalog — or chosen Don't show this again — open it from the menu instead. Use Snappier Server only for recordings? It may still open by itself after an update; close it, or choose Don't show this again — nothing was reset.
You can run it again any time to add something else or connect another device: it only ever adds, and never removes what you have.
4 Connect the Snappier IPTV app
On your Apple TV, iPhone or iPad, the app connects in up to two steps, set up in different places in the app. Everyone does the first; the second is only for watching through the server.
- In Snappier IPTV, open Settings → Snappier Server and switch on Enable Snappier Server. (On iPhone and iPad the rows are called Server Address and Server Port.)
- For Address for Server, use the server address from the wizard's last step without the
http://and the port —http://192.168.1.20:8000becomes192.168.1.20. Port for Server is8000. - For API Token, press Show on the wizard's last screen (it is also in Snappier Server's Preferences → Security). Then tap Test Server Connection — it checks that the server can be reached, not the token.
- This lets the app schedule recordings and downloads, and it is what the server checks before it gives the app its playlist. Do it on every Apple TV, iPhone and iPad you use; cloud sync can stay on.
- In Snappier IPTV, add a playlist and choose the type Xtream Codes — the playlist type for servers like this one.
- Type in the server address, username and password from the wizard's last step, exactly as shown. They are a login the wizard made for the app — not your provider's.
- Another device later? Run the wizard again and choose Nothing new — just connect another TV or device.
1 Download it, and install FFmpeg
Download the command-line version for your system — Windows, macOS or Linux, x64 or ARM64 — and unzip it. It is a single program with Node.js built in, so the only other thing it needs is FFmpeg, the video engine it records with. FFmpeg is not included, so install it first (version 4 or later):
- Linux: from your package manager —
sudo apt install ffmpeg(Debian, Ubuntu, Raspberry Pi OS),sudo dnf install ffmpeg(Fedora, RHEL) orsudo pacman -S ffmpeg(Arch). - macOS:
brew install ffmpeg, with Homebrew. No Homebrew yet?/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"installs it. - Windows: get a build from the FFmpeg download page and add the folder holding
ffmpeg.exeandffprobe.exeto yourPATH.
The server looks for ffmpeg and ffprobe on the PATH. On a Mac or PC with a screen, the desktop app is simpler — FFmpeg comes with it.
2 Run it
Leaving it running on a server with no screen? Skip to Run it as a service now and come back for the wizard: the wizard's settings and token belong to the user the server runs as.
Open a terminal in the folder you unzipped it to, and run it:
- Linux and macOS:
./snappier-server-cli-v…-linux-x64(or-linux-arm64,-macos-arm64,-macos-x64). If it says permission denied, runchmod +x snappier-server-cli-*first. The macOS version is signed and notarised by Apple. - Windows (PowerShell):
.\snappier-server-cli-v…-win-x64.exe(or-win-arm64.exe).
It starts the server on port 8000 and prints the addresses other devices can reach it on. The first time, while nothing is set up, it prints the setup wizard address instead, and the command that shows your API token. It keeps running until you press Ctrl+C, and records only while it runs.
- Settings, the API token, logs, recordings, films and series all live in
~/SnappierServer/in your home folder.--configpoints it at a different settings file;--recordings,--movies,--seriesand--logs-foldermove the folders. - Port
8000taken? Use--port(or thePORTenvironment variable) — the command line reads its port only from there, never from the settings file. - Every option is in Advanced Configuration, or run it with
--help.--check-configchecks your settings without starting the server.
3 The setup wizard
Open the /setup address it printed — for example http://192.168.1.20:8000/setup — from a phone or computer on the same network. The machine running the server doesn't need a screen.
First it asks for your API token, the password that protects the dashboard and your settings. To see it, run the program again with --show-token (plus the same --config, if you use one): it prints the token and exits, without starting a second server. The token is also api_token in ~/SnappierServer/config.json.
Then it asks what you want to watch, then asks for each thing it needs one at a time — your IPTV provider (or just paste the playlist link your provider sent), Plex, Emby or Jellyfin, a catalog source and its free TMDB key. Every login is tested before you move on, and nothing is saved until the end. It finishes by creating a login for the Snappier IPTV app and showing you the details to type in.
- The wizard's address is printed only while nothing is set up; after that the dashboard's is. The wizard is still there — put
/setupon the end of the same address. - While nothing is set up, the dashboard also shows a banner with Open the setup wizard.
- You can run it any time to add something else or connect another device: it only ever adds, and never removes what you have.
4 Connect the Snappier IPTV app
On your Apple TV, iPhone or iPad, the app connects in up to two steps, set up in different places in the app. Everyone does the first; the second is only for watching through the server.
- In Snappier IPTV, open Settings → Snappier Server and switch on Enable Snappier Server. (On iPhone and iPad the rows are called Server Address and Server Port.)
- For Address for Server, use the server's address without the
http://and the port —http://192.168.1.20:8000becomes192.168.1.20. Port for Server is8000, or the number you gave--port. - For API Token, use the token
--show-tokenprints. Then tap Test Server Connection — it checks that the server can be reached, not the token. - This lets the app schedule recordings and downloads, and it is what the server checks before it gives the app its playlist. Do it on every Apple TV, iPhone and iPad you use; cloud sync can stay on.
- In Snappier IPTV, add a playlist and choose the type Xtream Codes — the playlist type for servers like this one.
- Type in the server address, username and password from the wizard's last step, exactly as shown. They are a login the wizard made for the app — not your provider's.
- Another device later? Run the wizard again and choose Nothing new — just connect another TV or device.
5 Keep it running
Recordings only happen while the server is running. On a machine that stays on, have it start with the machine, rather than from a terminal you might close:
- Linux: run it as a systemd service, below.
- Docker or Home Assistant: use one of the community packages.
If something goes wrong, Troubleshooting covers the common problems, and --support-log writes a support log you can send us.
6 Run it as a service (Linux)
A service starts with the machine and keeps running after you log out. Replace YOUR_USERNAME with the user it should run as: its settings, API token and recordings live in that user's ~/SnappierServer/.
8000. For a dedicated user, give it a home folder: sudo useradd -r -m -d /var/lib/snappier snappier.
The zip holds two files: the program, and wireproxy, the WireGuard helper the VPN setting uses, which has to sit next to it. (Comskip is built into the program.) Downloading over SSH? In the downloads, copy the Linux .zip's link, then curl -LO it and unzip it (sudo apt install unzip if you need to).
sudo mkdir -p /opt/snappier /etc/snappier
sudo cp snappier-server-cli-v…-linux-x64 /opt/snappier/snappier-server-cli
sudo cp wireproxy /opt/snappier/
sudo chmod +x /opt/snappier/snappier-server-cli /opt/snappier/wireproxy
sudo tee /etc/systemd/system/snappier-server.service << 'EOF'
[Unit]
Description=Snappier Server
After=network.target
[Service]
Type=simple
User=YOUR_USERNAME
WorkingDirectory=/opt/snappier
ExecStart=/opt/snappier/snappier-server-cli
EnvironmentFile=-/etc/snappier/env
Restart=on-failure
RestartSec=5
StartLimitBurst=5
StartLimitIntervalSec=60
StandardOutput=journal
StandardError=journal
# Hardening
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
# Optional: a different port
echo 'PORT=8000' | sudo tee -a /etc/snappier/env
Set everything else in the dashboard, so there is one place to look.
Set the folders in the dashboard's Settings → Folders, or in /etc/snappier/env: echo 'RECORDINGS_FOLDER=/mnt/nas/tv' | sudo tee -a /etc/snappier/env (-a adds to the file instead of replacing it), and the same for MOVIES_FOLDER and SERIES_FOLDER. For folders, a command-line flag beats the environment, which beats the dashboard. Make sure the service's user can write there, and for a network share add RequiresMountsFor=/mnt/nas under [Unit], so the service waits for it.
sudo systemctl daemon-reload
sudo systemctl enable --now snappier-server
journalctl -u snappier-server -f # the first time, it prints the setup wizard's address
sudo -u YOUR_USERNAME -H /opt/snappier/snappier-server-cli --show-token
Run it as the service's user, as shown. Run as yourself or as root, it reads a different ~/SnappierServer/ and prints a token the server won't accept. It prints the token and exits, without touching the running server.
Copy the new program over /opt/snappier/snappier-server-cli, keeping that name, and the new wireproxy beside it, then sudo systemctl restart snappier-server. Settings, the token and recordings stay where they are. It never replaces itself: the update check only tells you a new version is out, in the log and on the dashboard.
7 Firewall and access from outside
- Firewall: allow port
8000from your home network, for examplesudo ufw allow from 192.168.0.0/16 to any port 8000 proto tcp— adjust it to your network. - A fixed address: the app stores the server's address, so give the machine a fixed one — a DHCP reservation on your router.
- Don't forward port
8000on your router. For access away from home, use a VPN, or put the server behind HTTPS — see HTTPS / TLS.
Environment Variables & CLI Arguments
PORT— Listening port (default:8000)HOST— Bind address (default:0.0.0.0)TRUST_PROXY— Trust the reverse proxy'sX-Forwarded-*headers:truefor the nearest hop, a number for that many hops, or an Express subnet spec such as172.16.0.0/12. Overridestrust_proxyinconfig.json. Off by default so forged headers can't spoof a directly-exposed instancePUBLIC_BASE_URL— Force the advertised origin, e.g.https://snappier.example.com, for setups where forwarded headers can't be trusted. Overridespublic_base_urlinconfig.jsonENABLE_REMUX— Convert.tsto.mkvafter recording (default:false)ENABLE_COMSKIP— Run Comskip on finished recordings to write a sidecar.edlwith commercial-break markers (default:false)COMSKIP_PATH— Override path to an externalcomskipbinary (e.g./usr/local/bin/comskip). Useful when the bundled binary is missing or you've built a newer version. Falls back to the bundled binary if the override isn't usableCOMSKIP_INI— Override path to acomskip.inituning file. Takes precedence over<config-dir>/comskip.iniand the bundled iniRECORDINGS_FOLDER— Live TV recording output path (default:~/SnappierServer/Recordings)MOVIES_FOLDER— Movie download output path (default:~/SnappierServer/Movies)SERIES_FOLDER— TV series download output path (default:~/SnappierServer/TVSeries)PVR_FOLDER— PVR data path (default:~/SnappierServer/PVR)HLS_FOLDER— HLS transcoding temp directory (default:~/SnappierServer/hls)EPG_FOLDER— EPG cache data path (default:~/SnappierServer/epg)LOGS_FOLDER— Log file directory (default:~/SnappierServer/logs/)- Upgrading from an earlier release? Your data folder is never moved — recordings, watch progress and favourites in
~/SnappierServercarry over untouched. DOWNLOAD_SPEED_LIMIT_MBS— Max curl download speed in MB/s, so a large download doesn't saturate your own connection (default:0= unlimited)MAX_CURL_RETRIES— Max retry attempts for curl downloads (default:5)USE_CURL_TO_DOWNLOAD— Force curl for all downloads instead of FFmpeg (default:false)ENABLE_EPG— Enable EPG support (default:false)EPG_URL— Single EPG XML URL (deprecated — useEPG_URLSinstead). If both are set,EPG_URLStakes precedenceEPG_URLS— Multiple EPG sources as JSON array (takes precedence overEPG_URL)EPG_REFRESH_INTERVAL— Refresh interval in hours (default:24)LOG_ROTATE_DAYS— Log rotation interval in days (default:3)LOG_ROTATE_SIZE_MB— Max log file size before rotation in MB (default:10)KEEP_ALIVE_TIMEOUT— HTTP keep-alive timeout in ms (default:65000)HEADERS_TIMEOUT— HTTP headers timeout in ms (default:66000)HLS_USE_HW— Enable hardware acceleration for HLS transcoding (default:false). Picks the encoder for your hardware automatically: VideoToolbox on macOS; on Linux, NVENC when/dev/nvidia0exists, VAAPI when a DRM render node exists (AMD/Intel GPUs), and software encoding otherwiseHLS_VIDEO_ENCODER— Override the video encoder for HLS (e.g.h264_videotoolbox,h264_vaapi,h264_nvenc). If unset, useslibx264or the hardware encoder whenHLS_USE_HWis enabledHLS_VAAPI_DEVICE— DRM render node used by the VAAPI encoders (default:/dev/dri/renderD128). Only needed on multi-GPU systems where the default node is the wrong card
Hardware Encoding on Linux (VAAPI)
New in v1.7.0-8: VAAPI hardware encoding on AMD and Intel GPUs works correctly now. Previously, setting HLS_VIDEO_ENCODER=h264_vaapi killed FFmpeg at startup (“Impossible to convert between the formats”) and every stream silently fell back to software encoding at very high CPU usage. The transcode pipeline now opens the DRM render node, uploads frames to the GPU (format=nv12,hwupload, P010 for 10-bit HEVC), and downscales UHD content on the GPU with scale_vaapi.
HLS_VIDEO_ENCODER at all — just set HLS_USE_HW=true and the server detects NVENC, VAAPI, or software automatically. If hardware encoding fails at runtime, it still falls back to libx264.# AMD / Intel GPU — auto-detects VAAPI
export HLS_USE_HW=true
# Or pin the encoder and render node explicitly
export HLS_VIDEO_ENCODER=h264_vaapi
export HLS_VAAPI_DEVICE=/dev/dri/renderD128
Your user needs access to the render node — on most distros that means membership of the render (or video) group: sudo usermod -aG render $USER, then log out and back in.
Setting Variables
# macOS / Linux
export PORT=9000
export ENABLE_REMUX=true
export ENABLE_EPG=true
export EPG_URL="http://example.com/epg.xml"
./snappier-server-cli
# Windows (PowerShell)
$env:PORT = "9000"
$env:ENABLE_REMUX = "true"
.\snappier-server-cli.exe
# Windows (cmd)
set PORT=9000
set ENABLE_REMUX=true
snappier-server-cli.exe
To persist, add to ~/.bashrc, ~/.zshrc, or the systemd service file.
All arguments override environment variables. Run --help for the full list.
./snappier-server-cli --help
Server
--port 8080 # Override listening port
--host 127.0.0.1 # Bind address (default: 0.0.0.0)
--enable-remux # Convert .ts to .mkv after recording
--enable-comskip # Run Comskip on finished recordings (writes sidecar .edl)
--comskip-path /usr/local/bin/comskip # Use an external comskip binary instead of the bundled one
--comskip-ini /etc/snappier/comskip.ini # Use a custom comskip.ini for detection tuning
--speed-limit 50 # Download speed limit in MB/s
Config Check
Validates config.json and exits without starting the server. It is completely offline — nothing is fetched, nothing is written — so it is safe to run while a server is already up, and safe to point at a config you are still editing.
./snappier-server-cli --check-config # checks ~/SnappierServer/config.json
./snappier-server-cli --check-config --config /etc/snappier/config.json # or any other file
Findings come in three severities:
- ERROR — the server will misbehave. Invalid JSON (which the server refuses to start on, leaving the file untouched); unknown or misspelled keys, with a "did you mean…?" suggestion; wrong types — including quoted booleans, where
"false"counts as true; URLs that aren't fullhttp(s)://addresses; a partly filled-in IPTV provider (host but no credentials); acomskip_pathorcomskip_inithat doesn't exist; and a TMDB value that is actually the long API Read Access Token instead of the 32-character API Key. A config file the check cannot reach at all is an error too — typically one behind a directory the user running the check cannot open, as when the CLI runs as a different user from the one owning the mount. That is reported as a permission problem rather than as a missing file, because the file may well be there. The server itself refuses to start on either of these, printing one line that names the file and the problem. - warning — legal but probably not what you meant. World-readable file permissions on a file full of credentials; EPG enabled with no sources; a TMDB key with an unusual format.
- note — nothing to fix. Keys like
portthat the desktop app honours but the CLI takes from its command-line flags or environment variables instead; folder paths, which every install honours but only reads at startup, so a change to one applies on the next restart; no EPG source marked for the TV Guide; a config file that doesn't exist yet (the server creates one on first run).
Exit code is 0 when there are no errors (warnings and notes don't fail the check) and 1 otherwise, so a deploy script or systemd unit can refuse to (re)start on a broken config:
./snappier-server-cli --check-config && sudo systemctl restart snappier-server
Support Log
Writes a support log to send when you ask for help, and exits without starting the server — so it works when the server itself will not start. It is written into your logs folder, which is printed when it finishes. It honours --config and --logs-folder like the server does.
./snappier-server-cli --support-log # the last 6 hours
./snappier-server-cli --support-log 1 # the last hour (1, 6 or 24)
Setup Wizard & API Token
On a fresh install the server prints the setup wizard’s address when it starts — open it from a phone or computer on the same network. It asks for your API token, which the server never prints; show it with --show-token, which prints the token and exits without starting the server. It honours --config. In a container, run it with docker exec.
./snappier-server-cli --show-token
docker exec <container> <path to snappier-server-cli> --show-token # in a container
Config & Data Paths
--config /etc/snappier/config.json # Custom config file (default: ~/SnappierServer/config.json)
--pvr-folder /mnt/data/pvr
--epg-folder /mnt/data/epg
--logs-folder /var/log/snappier
--recordings ~/Recordings
--movies ~/Movies
--series ~/TVShows
Logging
--log-rotate-days 7 # Rotate every N days (default: 3)
--log-rotate-size 20M # Rotate at N MB (default: 10)
EPG
# Single source
--enable-epg --epg-url "http://example.com/epg.xml" --epg-interval 12
# Multiple sources (JSON)
--enable-epg --epg-urls '[
{"url":"http://primary.com/epg.xml","name":"Primary","priority":1,"enabled":true},
{"url":"http://backup.com/epg.xml","name":"Backup","priority":2,"enabled":true}
]'
Full Example
./snappier-server-cli \
--config /path/to/config.json \
--port 8080 \
--enable-epg \
--epg-url "http://provider.com/epg.xml" \
--epg-interval 24 \
--enable-remux \
--recordings ~/Recordings \
--movies ~/Movies \
--series ~/TVShows \
--logs-folder /var/log/snappier \
--log-rotate-days 7 \
--log-rotate-size 20M \
--epg-folder /mnt/data/epg \
--pvr-folder /mnt/data/pvr
Reference
One guide per part of Snappier Server, in the order most people set things up. A few words you'll meet: EPG is the TV guide; Xtream Codes is the kind of playlist the app uses to talk to this server; PVR rules record programmes automatically; a catalog source is a list of films and series for the app to browse; and to remux is to repackage a recording into a more widely playable file without changing the picture.
Snappier Server ships with a built-in browser-based dashboard. It runs on the same port as the API and requires no extra install — just point a browser at:
http://YOUR-SERVER-IP:8000/dashboard
The dashboard is where everything beyond the Preferences window is set up — providers, guides, catalogs, playlists — and where recordings are managed. Choose Dashboard from the menu-bar or tray icon and it opens in your browser, already signed in.The dashboard is how you manage a command-line server — open http://YOUR-IP:8000/dashboard from any browser on your network. It works on phones, tablets and desktops, and supports both light and dark themes (toggle in the top nav).
Authentication
Opened from the menu-bar or tray icon, the dashboard signs you in by itself. Opened any other way — from a phone, another computer, or a bookmark — it asks for the API token (in Preferences → Security).On first load you'll be prompted for the API token — print it with --show-token, or find it in ~/SnappierServer/config.json. With Remember this device ticked (the default) the token is stored in localStorage so you only enter it once per browser; untick it to keep the token for the current session only. To rotate it, use Settings → Auth → Regenerate.
Overview Cards
The home screen shows a live grid of count cards, each opening a detail modal:
- Scheduled Programs: upcoming one-shot and PVR recordings with start/stop times. Cancel from here.
- Recordings: completed live-TV recordings, organised into a browsable folder library (see Recordings Library below), where they can be browsed and deleted.
- Streaming Devices: active HLS sessions (transcoding) and remux sessions, plus connected client info.
- Movies / TV Series: downloaded VOD content with metadata and posters, and a delete action.
- PVR Rules: active series/one-time rules and the next match found in the EPG.
- Reminders: programme reminders and their fire times.
- System stats: CPU, memory, and per-folder disk usage updated live over SSE.
Recordings Library
Recordings are grouped into a folder library rather than one long list, so a large back catalogue stays browsable. Click Recordings on the home screen, then drill down:
- Programme folders. One folder per programme name, each showing its total size and a badge with the number of recordings it holds. A programme currently being recorded shows a REC badge instead and sorts to the front; otherwise the most recently recorded programme comes first.
- The recordings. Opening a programme lists all of its recordings newest first, each with channel, date, size, and a Delete button. The list is broken up by month headings that stay pinned as you scroll, so a daily show is still easy to read without a second folder to open.
Use the breadcrumb button at the top to go back to the folders. The search box filters at whatever level you're on, and it matches filenames and channel names as well as programme names — so searching for a file still surfaces the folder it lives in.
TV Guide (EPG Grid)
An interactive XMLTV-driven grid view. Browse channels by category, jump to "Now", scroll forward/back in time, and long-press / right-click any programme cell for actions: Record once, Create PVR rule, or Set reminder. Setup:
- Dashboard → Settings → EPG → add or edit a source.
- Tick Use for TV Guide (Xtream Codes). If your EPG URL is a standard Xtream
xmltv.phpURL, the hint below the tickbox turns green and reads "Xtream credentials auto-detected from URL" — you don't need to enter anything else. If it doesn't parse, fill in the host, username, and password fields that appear. - Click Save in the source editor, then Save again on the main Settings screen. Both are required — see the warning below.
- Click TV Guide in the top nav.
When the toggle is set correctly the guide's first dropdown shows your source name and a second dropdown appears beside it listing your provider's categories, opening on the first category rather than every channel at once. Categories whose channels have no programme data are hidden automatically.
Settings Modal
Tabbed configuration UI — everything writes to config.json and most options apply without a restart. The port is in the app's Preferences, where it takes effect as soon as it is saved, and in the Server tab below.The port is not set here: the command line takes it from --port or PORT.
- Server: port and log rotation (the desktop app uses these; the command line takes both from its flags or environment instead, so they have no effect there); toggles for Remux, Commercial Skipping (Comskip), and the alternative download engine; download speed limit.
- Folders: per-purpose paths for Recordings, Movies, TV Series, PVR data, Logs, and EPG cache, with a folder browser.
- EPG: enable/disable EPG, manage multiple XMLTV sources with priorities, set refresh interval, mark a source for TV Guide use, and an Xtream URL helper.
- Your IPTV provider: address and credentials, and whether to publish live TV, films and series — see Your IPTV Provider. Also Play through this server, and Send provider traffic through a VPN or proxy — see VPN or Proxy.
- Catalog Sources: the sources, the catalogues each one publishes, and how fast and deep they are read — see Your Catalog Sources.
- Playlist Login: published playlist credentials and which sources each login sees — see Multiple playlists.
- Auth: view, copy, and regenerate the API token.
Live Updates (SSE)
The dashboard subscribes to the server's Server-Sent Events stream, so you don't need to refresh. Job progress, recording starts/stops, remux completion, Comskip status, EPG refresh, PVR scans, and reminder fires all update the UI in real time. If the connection drops the dashboard reconnects automatically.
Mobile / Tablet
The layout collapses to a stacked card view on narrow screens; modals become full-screen sheets. The TV Guide grid is touch-scrollable with momentum.
Headless Servers
On a NAS or a server with no screen, the dashboard is your only management UI. Everything is here except the port and log rotation, which the command line takes from its flags or environment (see Configuration).
Snappier Server can publish your own IPTV subscription into the same playlist as everything else, so a device needs only one playlist rather than several. Live TV, films and TV series each have their own switch — enable any combination.
Setting it up
- Open Settings in the web dashboard and find Your IPTV provider.
- Enter your provider's address, username and password — the same details you would normally type into a player. Address is host and port only, with no username, password or path.
- Tick Live TV, Movies and/or TV Series.
- Click Save. The catalog rebuilds straight away.
https:// if your provider supports it. Many redirect plain http to https, which adds a pointless round trip to every single play.
Live TV and the guide
Channels arrive with your provider's own categories and ordering. The TV guide is your provider's XMLTV, passed through untouched — channel IDs are preserved exactly as they send them, which is what makes programmes line up with channels without any mapping on your part.
Catch-up is passed through where your provider offers it: channels are published with the provider's own archive flags, the archive programme table comes from the provider, and playing an archived programme routes through this server, which re-credentials the request onto the provider's timeshift service. Channels without archive on the provider's side are published without one, so the catch-up UI never appears where it cannot work.
Films and series
Film details — plot, cast, runtime, artwork — are fetched from your provider the moment you open a title, not stored up front. A provider catalogue can run to tens of thousands of films, and holding full details for every one would bloat the catalog for the sake of titles nobody opens. Episode lists work the same way: fetched when you open a show.
Your provider's own naming is kept exactly as they write it, so nothing is renamed or reformatted on the way through.
Playing when the server is off
By default, live TV and films are handed to the player as direct provider URLs, so once the playlist is imported they keep playing whether or not this server is running — the server is only needed to browse and refresh. Series and catch-up are the exceptions: episode lists and archive playback go through the server, so those need it running. With Play through this server or a VPN or proxy switched on, everything plays through the server, so it has to be running to watch anything.
Play through this server
A switch under Settings → IPTV Provider in the web dashboard (xtream_stream_mode in config.json). Off, the default, the player is sent straight to your provider. On, live TV, catch-up, films and episodes stream through this server instead, and so do the pictures: channel logos, film and series posters, episode stills and the icons in the TV guide. Your providers see this server's internet address rather than each device's. Useful when this computer is on a VPN, or for providers whose links only work from the address that asked for them. It uses this server's bandwidth.
- Refresh the playlist in the app on each device after switching it. The app keeps the addresses it was given at import, so until then it can go on playing straight from the provider.
- Anything the app looks up for itself somewhere other than your provider, such as film details from TMDB, still goes from each device.
- It changes who carries the video, not who is allowed to watch it.
Load pictures through this server
The switch below it sends only the pictures through this server: channel logos, film and series posters, episode stills and the icons in the TV guide. The video still goes straight to your provider. Your devices then no longer look up or contact the provider's image hosts, whose names often say what they are. Every picture travels twice, from the provider to this server and on to the device, and when you watch away from home that second leg uses this computer's upload, so it is off unless you switch it on. A picture that has not changed is checked with a short request instead of being sent again. It is always on while Play through this server is. Refresh the playlist and the TV guide in the app after changing it.
Settings reference
iptv_host— Provider address, host and port onlyiptv_username/iptv_password— Your subscription credentialsiptv_publish_live— Publish live channels and the guide (default:false)iptv_publish_movies— Publish films (default:false)iptv_publish_series— Publish TV series (default:false)iptv_max_titles— Cap on films taken from the provider,0for no limit (default:0)
More than one provider
To publish several provider subscriptions in the same playlist, add providers under Settings → IPTV Provider in the web dashboard, or set an iptv_providers list in config.json (the server reloads the file on save):
"iptv_providers": [
{ "host": "http://one.example.com:8080", "username": "u1", "password": "p1",
"category_prefix": "P1: " },
{ "host": "http://two.example.com:8080", "username": "u2", "password": "p2",
"category_prefix": "P2: ", "publish_live": false, "max_titles": 500 }
]
- When
iptv_providersis set (non-empty), the legacy single-provider keys are ignored entirely — one source of truth at a time. - Each entry takes its own
publish_live/publish_movies/publish_series(defaulttruehere, unlike the legacy keys) andmax_titles. - Set a short
category_prefixper provider — it is what keeps "Sports" from one provider apart from "Sports" from another. Without prefixes, same-named categories pool into one shelf. - Every provider keeps its own ID space, so favourites and watch progress survive adding or removing another provider. The TV guide at
xmltv.phpstreams the first live-publishing provider's guide; add the others' XMLTV under EPG sources. --check-configvalidates the list — run it after editing.
Signed stream URLs
Set stream_auth: "signed" to put an expiring signature on the media URLs this server issues itself — recordings, downloads and the HLS proxy. A copied link to one of those stops working once it expires. The default is "off" because signed URLs can break some downstream caching setups.
It does not reach catalog playback, under either stream mode. Those requests are authorised by the playlist username and password they already carry, and there is no URL of ours to sign: on "redirect" the link handed to the player is your provider's own, and on "proxy" the bytes come through this server but the request is still authorised by those same credentials. To cut off a leaked catalog link, rotate that playlist login — each one can be changed on its own without disturbing the others.
Multiple playlists
Sources can also be split across separate published playlists, each with its own login and its own view of the catalog — one per family member or device. Manage them under Settings → Playlist Login in the web dashboard, or add a playlists list to config.json:
"iptv_providers": [
{ "host": "http://one.example.com:8080", "username": "u1", "password": "p1",
"category_prefix": "P1: ", "id": "p1" },
{ "host": "http://two.example.com:8080", "username": "u2", "password": "p2",
"category_prefix": "P2: ", "id": "p2" }
],
"playlists": [
{ "username": "livingroom", "password": "…" },
{ "username": "kids", "password": "…", "sources": ["p2"] }
]
- Each entry is one set of login credentials for the apps.
sourceslists which provider/instanceids that login sees — omit it to see everything. - Give provider and instance entries an explicit short
"id"when using playlists, sosourcesreferences stay readable. - Only the playlists listed can log in. On configs from older releases that still carry an auto-generated
xtream_username/xtream_password, that legacy login works only until the first playlist is defined — add an entry with those credentials if existing devices should keep their login. - A title has the same stream ID in every playlist, and the app scopes favourites and watch progress per playlist name — so each login keeps its own, and nothing is lost by splitting.
- Filtering is enforced, not cosmetic: a scoped login cannot list, fetch details for, or play another source's titles.
--check-configvalidates the list, including that everysourcesreference matches a configured id.
Troubleshooting
- A film won't play but others do. Individual titles are often dead on the provider's side. The log shows where it redirected; try two or three other titles before suspecting the setup.
- Nothing appears after enabling a switch. The catalog rebuilds on save, but the app keeps its own copy — refresh the playlist once the log shows
Catalog refreshed. - The provider stopped responding. The refresh is abandoned and your existing catalog is kept, rather than being replaced by an empty one.
EPG (Electronic Programme Guide) provides programme listings for scheduling recordings and browsing the TV guide. Snappier Server reads any feed in XMLTV format — an open standard for TV listings — so any URL that returns XMLTV data works. Common sources:
- Your IPTV provider — look for "XMLTV URL", "EPG URL", or "TV Guide URL" in your provider's welcome email, customer portal, or app setup instructions. If you can't find it, contact your provider.
- Public feeds — many broadcasters and FAST (free, ad-supported) channel services publish XMLTV guides, and community projects aggregate free-to-air listings for most countries.
EPG URL Format
If your provider uses Xtream Codes (a common IPTV management system), construct the EPG URL from your provider's server details (not your Snappier Server server):
http://your-provider-server:port/xmltv.php?username=USERNAME&password=PASSWORD
Setting it up
- Open the web dashboard (Dashboard in the menu-bar or tray icon) and go to Settings → EPG.
- Tick Enable EPG and set the refresh interval (24 hours is plenty).
- Under EPG Sources, choose + Add Source: paste the URL, name the source and set its priority (1 = highest). With no sources yet, the Setup Wizard button there walks you through it.
- Press Save on the main Settings screen.
Use for TV Guide (Xtream Codes)
Programme listings alone are enough to schedule recordings and create PVR rules. The Use for TV Guide (Xtream Codes) tickbox on a source does something extra: it fetches the live stream URLs and the channel category list from your provider's Xtream API. Without it the TV Guide has no categories to filter by, so it lists every channel at once and the category dropdown stays hidden.
Tick it on any source whose EPG URL is a standard Xtream xmltv.php URL — the host, username, and password are read straight from that URL, so there is nothing extra to type. For a non-Xtream EPG URL, tick it and fill in the host, username, and password fields that appear.
config.json until you see the "Settings saved!" toast.
Once saved, the server fetches the category data immediately — no restart needed. To confirm it worked, check that the source has the flag set:
curl -H "X-API-Token: YOUR_TOKEN" http://localhost:8000/config | grep -o '"tvGuide":[^,}]*'
and look for a line like [Xtream] Total: 1234 channel URLs, 56 categories, … in the server log. If you instead see [Xtream] No EPG source is marked "Use for TV Guide", the flag didn't save.
From the command line
Instead of the dashboard, sources can be given when the server starts:
# Single source
./snappier-server-cli --enable-epg \
--epg-url "http://iptv.example.com:8080/xmltv.php?username=user&password=pass"
# Multiple sources
./snappier-server-cli --enable-epg --epg-urls '[
{"url":"http://primary.com/epg.xml","name":"Primary","priority":1,"enabled":true},
{"url":"http://backup.com/epg.xml","name":"Backup","priority":2,"enabled":true}
]'
Verify
curl -H "X-API-Token: YOUR_TOKEN" http://localhost:8000/epg/status # Source info & update times
curl -H "X-API-Token: YOUR_TOKEN" http://localhost:8000/epg/channels # Detected channels
curl -H "X-API-Token: YOUR_TOKEN" -X POST http://localhost:8000/epg/refresh # Force refresh
Troubleshooting
- No data: Verify URL returns XML in a browser. Check EPG is enabled. Wait for initial download.
- Stale data:
POST /epg/refreshor reduce refresh interval. - URL not working: Verify credentials. Try standard Xtream format. Contact your provider.
- TV Guide shows every channel with no category dropdown: no source has Use for TV Guide (Xtream Codes) ticked, or the change was never saved on the main Settings screen. See above.
The films and TV already on your own media server, published into the same playlist as everything else. Playback comes straight from that machine — nothing to resolve, nothing to wait for, and no stream to find.
Plex, Emby and Jellyfin are all supported, several of each, mixed freely in one playlist.
Adding Plex
- Open the dashboard, go to Settings → Media Server and press Add Plex.
- A four-character code appears. On your phone or computer, go to plex.tv/link and enter it.
- Tick the servers you want, then the libraries within them, and press Add selected. It saves and loads them for you — there is no rebuild to press.
There is no address to find and no token to dig out of a settings page. If a server is not on your account, or this machine can only reach it by an address the account does not advertise, Add Plex manually takes an address and token directly and tests both before saving.
Adding Emby or Jellyfin
- Press Add Emby or Add Jellyfin.
- Enter the address including its port — the whole address as you would type it into a browser, such as
192.168.1.10:8096. No port is assumed for either; Plex is the exception, where leaving the port off uses the standard 32400. - Enter your username and password, press Connect & load libraries, tick what to publish, and save.
Your password is never stored. It is sent once, to your own server, and exchanged for an access token — only that is kept, and you can revoke it from your media server's own dashboard without changing your password. Emby and Jellyfin share an API, which is why they are set up identically.
Choosing what gets published
Each server lists its libraries with a switch each, grouped into Films and TV. A large account can carry twenty or more — separate 4K, foreign-language, kids and sports libraries — and you almost certainly do not want all of them in one catalog. Changes save themselves and reload the catalog on their own. Reload Catalog re-reads your media servers only; your catalog sources and IPTV providers are left exactly as they are.
Large libraries
Films and series are published up front, but episodes and film details load only when you open something. A library of tens of thousands of titles costs nothing for the titles nobody watches, so a big account stays usable rather than producing a catalog too large to import.
Switching one off, and disconnecting
Each server has an Enabled switch. Turned off, its titles leave the catalog and the machine is not contacted at all — useful for one that sleeps. Prefer it to Remove for anything temporary: removing discards the entry's identity, which is what your favourites and watch progress point at, so re-adding the same server later issues fresh ids.
Disconnect forgets every linked server and this install's account identity in one step. It cannot revoke access at your media account — that needs the account-wide sign-in, which is never stored — so remove the device in your account's own settings if you want that too.
Your account sign-in is never stored
The token that linking produces is used once, to list the servers on your account, and then discarded. Only each individual server's own access token is kept. Adding another server later means linking again, which takes four characters.
Playing directly is off by default. Turned on, the app streams from your media server without passing through Snappier Server — faster, and it keeps working while this server is busy. The access token travels inside the playback address to do that, so it is stored on every device that imports the playlist. Left off, playback is proxied through Snappier Server instead.
A catalog source is a separate service you run or subscribe to that lists films and series — the kind you would normally install in a player by pasting its install address. Snappier Server reads the catalogues it offers and publishes each one as a category in the same playlist as everything else. You can add several; each keeps its own catalogue selection and category prefix, and a title offered by two sources appears once.
Setting it up
- In your catalog source, copy the install address you would normally paste into a player. There is no username or password — your whole configuration is inside that address.
- Open Settings in the web dashboard and find Catalog Sources. Press + Add Instance, paste the address, optionally give it a name and a category prefix, and save.
- Press the instance's Catalogs button, then tick the catalogues you want under Catalogs to publish. Each becomes a category in the app. The small cap box beside a ticked catalogue limits how deep that one goes.
- If any of them are series, add a free TMDB key under TMDB in the dashboard — without it, series open with no episodes.
- Press Rebuild Catalog Now. The first full pass is the slow one; a large selection fills in over a few runs, growing as it goes.
At least one source has to play
Some catalog sources only list titles and cannot play them. That is fine alongside one that can: when you open a title, the other source in the same playlist is asked for it. On its own, nothing from a list-only source plays.
Reading the badges
Once the server has read a source, its entry in the dashboard shows what it found. Hover over any badge for the full explanation.
- 5 of 27 catalogs — how many catalogues you ticked, out of how many it offers. auto means none are ticked, so only its watchlist catalogues (if it has any) are published.
- stream — it plays its own titles.
- stream · another source — it only lists titles, and every playlist that includes it has another source to play them through. That source is asked, not promised: a title it has nothing for still will not play.
- no stream — it only lists titles, and at least one playlist that includes it has nothing to play them through. Add a source that plays to that playlist, or take this one out of it.
- in no playlist — no playlist login includes it, so no app sees its titles.
- subtitles / meta — it offers subtitles, or title details. If no subtitles appear for a title, check for the subtitles badge first.
The line under each address lists everything the source declares and how many films and series it currently lists. If it says the source declares catalogues but offers none, it needs setting up at its own site first — then paste the new install address it gives you. A catalogue shown in amber as no longer offered by this instance has been dropped by the source; it fails every rebuild while ticked, so untick it.
Settings reference
All but the last sit under Catalog Sources in the dashboard. --check-config checks them if you would rather edit config.json.
catalog_max_titles_per_catalog— Maximum titles per catalog;0for no limit. The cap box overrides it per catalogue.catalog_max_pages— Maximum pages per catalog; a coarser cap in pages,0for the whole catalogue.catalog_run_budget_seconds— Crawl budget per run. Each run stops cleanly after this long and carries on a minute later where it left off;0for one uninterrupted pass.catalog_topup_interval_minutes— New-arrivals check: how often each catalogue's first page is re-checked between full crawls;0turns it off.catalog_min_request_interval_ms— Minimum gap between requests. Raise it if the log shows "Rate limited"; a source on your own machine or network needs no gap.catalog_request_timeout_seconds— Request timeout. Raise it if the log shows "Timed out".xtream_refresh_interval_minutes— Catalog refresh interval: how often the catalog is rebuilt;0leaves only the manual button.catalog_concurrency—config.jsononly: requests in flight at once per source (default4, at most8).
Every setting is explained in full on the server's own /help page.
PVR (Personal Video Recorder) creates rules that automatically schedule recordings when matching programmes appear in your EPG data. Like a DVR — set it once and the server records every matching episode.
Requirements
- EPG must be enabled and working
- Server should be running 24/7 for automatic scheduling
Rule Types
- Series: Records all future matching episodes continuously. Best for TV series and daily shows.
- One-time: Records only the next match, then auto-disables. Best for special events or one-off recordings.
How to Create Rules
- Snappier IPTV app: Long-press any programme in the EPG grid for recording options. Manage rules in the Server section.
- Web Dashboard: Click PVR Rules in the top nav (or the PVR Rules card on the home screen) to create and manage rules.
How It Works
The server scans EPG data for matching programmes after each EPG refresh, on startup (2-second delay), or when you trigger a manual scan. Matched programmes are automatically scheduled for recording. You can exclude specific episodes you don't want.
Data Storage
PVR data is stored in the PVR_FOLDER (default: ~/SnappierServer/PVR/):
pvr_rules.json— Recording rulespvr_exclusions.json— Excluded episodes- Recordings saved as
.ts(or.mkvwith remuxing enabled)
Snappier Server bundles Comskip to detect commercial breaks in finished recordings. It is non-destructive — the original recording is untouched. Comskip writes a sidecar .edl file (Edit Decision List) next to the recording, and players that understand EDL (Kodi, MythTV, NextPVR, Jellyfin with the appropriate plugin) will skip those segments automatically on playback.
Enabling
- Web Dashboard: Settings → Server → Enable Commercial Skipping (Comskip).
- Preferences: Tick Enable Commercial Skipping.
- Environment:
ENABLE_COMSKIP=true - Command line:
--enable-comskip
How It Works
When a live TV recording finishes (and remuxing completes if enabled), Comskip runs against the finished file. On completion the sidecar files are written next to the recording:
recording.edl— commercial-break time ranges (used by players)recording.txt,recording.log,recording.logo.txt— diagnostic output (safe to delete)
Detection runs in the background — the recording is immediately playable, and EDL data appears once Comskip finishes. The recording's metadata (and dashboard listing) shows a comskip status of running, done, none, or failed. Live progress is also broadcast over the SSE event stream as comskipStarted / comskipDone / comskipFailed.
Platform Support
- macOS: Bundled for Apple Silicon and Intel Macs, and works on macOS 13 or later. It is built from source with everything it needs inside it, so it depends on nothing else being installed.
- Windows: Bundled
comskip.exe(x86 build; runs on x64 Windows, and on ARM64 Windows under emulation). - Linux: Bundled binaries for both
x86_64andaarch64(ARM64). They use shared libraries from your system — FFmpeg 4.x (x86_64) or 5.x (ARM64) and argtable2 — so on a distribution with a different FFmpeg they do not start, and commercial detection fails (the recording itself is unaffected). To rebuild from source:apt install autoconf automake pkg-config build-essential libargtable2-dev libavformat-dev libswscale-dev, then./autogen.sh && ./configure --disable-gui && make, and pointcomskip_pathat the result (see below).
Tuning
Comskip's detection behaviour is controlled by comskip.ini, shipped alongside the binary. The bundled config produces standard EDL output; for fine-tuning (logo detection, channel-specific aspect ratios, sensitivity) consult the upstream sample ini.
Overriding the bundled binary or ini
You can point Snappier Server at an external comskip binary (e.g. a system-installed build) or a custom comskip.ini. Resolution order, highest precedence first:
- Config file:
comskip_path/comskip_iniinconfig.json(also accepts camelCasecomskipPath/comskipIni). Picked up live when the config is saved — no restart needed. - Environment:
COMSKIP_PATH/COMSKIP_INI. - Command line:
--comskip-path <path>/--comskip-ini <path>. - Config-dir ini fallback: If no ini override is set, a
comskip.iniplaced next to yourconfig.jsonis used in preference to the bundled one. - Bundled: The platform/arch-appropriate binary and ini shipped with Snappier Server.
If an override path is unreadable or non-executable, Snappier Server logs a warning and falls back to the next candidate. Example config.json snippet:
{
"enable_comskip": true,
"comskip_path": "/usr/local/bin/comskip",
"comskip_ini": "/etc/snappier/comskip.ini"
}
Caveats
- Commercial detection is heuristic — expect occasional false positives or misses, especially on channels without clear ad breaks.
- Sidecar files are deleted automatically when you delete the recording from the dashboard.
- Detection runtime is roughly 5–15× faster than realtime depending on hardware.
Snappier Server can send everything it fetches from the internet — channel lists, streams, catch-up, guides, artwork, update checks — through a VPN or proxy you choose, so your providers see its address rather than this computer's. Your devices are covered too, because they then get everything from the provider, pictures included, by way of the server. Only the server uses it: nothing else on this computer goes through the VPN, no VPN app or admin rights are needed, and your devices need no setup at all.
Setting it up
- Open Settings → IPTV Provider in the web dashboard and switch on Send provider traffic through a VPN or proxy.
- Choose the type: WireGuard, SOCKS5 proxy or HTTP proxy.
- For WireGuard, paste the WireGuard config file from your VPN service's website, or press Choose file…. For a proxy, enter its address, port and, if it has one, its login.
- Press Test connection to try it before saving, then Save.
- Refresh the playlist in the app on each device, because playback now goes through this server.
Which VPN services work
- WireGuard config file: Proton VPN, Mullvad, Surfshark, IVPN, AirVPN, IPVanish and Windscribe let you download one for "manual setup" from their website.
- SOCKS5 proxy: NordVPN (in a few countries) and PIA offer one with your account. Their address, port and login are on the service's website.
- OpenVPN only: ExpressVPN and CyberGhost cannot be used this way. Run their app on this computer instead and switch on Play through this server, which sends provider traffic through the VPN for every device.
How WireGuard runs
The server runs WireGuard itself, for itself alone, using a small helper program (wireproxy, ISC licence). It comes with the macOS and Linux builds. On Windows it is downloaded from snappierserver.app (about 11 MB) the first time you switch WireGuard on, and checked against a fingerprint built into the app before it is used. That one download goes over the computer's normal connection, because the VPN cannot start without it. The server keeps an eye on the connection and reconnects on its own if it drops or goes quiet. The dashboard shows whether it is connected and when the VPN server last answered.
While it is switched on
- Play through this server is on too, and cannot be turned off: without it, devices would play straight from the provider from their own address, around the VPN.
- If the VPN or proxy stops working, playback stops rather than going out without it. The same applies when it is switched on with a setting that cannot be used. Nothing is ever sent around it. If it stays down for more than 30 seconds, the dashboard shows a red banner, and the desktop app shows a notification and a warning in its menu bar or tray menu, until it is working again.
- Your media servers (Plex, Emby, Jellyfin) and anything else on your own network are reached directly, since a remote VPN could not reach them.
- All the video passes through the VPN or proxy, so its speed is what your devices get.
- Channel logos, film and series posters, episode stills and the icons in the TV guide load through the server too, over the same connection as everything else, even where the provider's own address for them is plain
http://. Anything the app looks up for itself somewhere other than your provider, such as film details from TMDB, still goes from each device. - The WireGuard config holds your VPN key, and a proxy password is a password: both are stored like your other passwords, never shown again, and kept out of logs and support logs.
Settings reference
outbound_proxy_enabled— Switch it on or off (default:false)outbound_proxy_type—"wireguard","socks5"or"http"outbound_wireguard_config— The WireGuard config file's textoutbound_proxy_host/outbound_proxy_port— A proxy's address and port. The address only, with nosocks5://and no portoutbound_proxy_username/outbound_proxy_password— A proxy's own login, if it has one. It is not your IPTV login.
--check-config checks all of these, including whether a WireGuard config is complete.
Troubleshooting
- "The VPN server has not answered." The config may be out of date or revoked; many services replace keys from time to time. Download a fresh config. A network that blocks outgoing UDP also blocks WireGuard.
- "The proxy refused the username or password." Use the proxy's own login from the VPN service's website, which is often different from your account login.
- Windows: "the WireGuard helper could not be downloaded". Check this computer's internet connection; it is tried again every minute. If your antivirus removed the helper, allow it and switch WireGuard off and on again.
- Streams buffer. Pick a VPN server closer to you. Everything passes through the VPN, so its speed is the limit.
The server auto-detects SSL certificates on startup and switches to HTTPS. The port stays the same (default 8000) — only the protocol changes. No certs = standard HTTP.
Certificate Paths
- Command-line version:
./certs/, relative to the folder it runs in —/opt/snappier/certs/when it runs as the service. The files must be readable by the user it runs as: after copying them,sudo chown YOUR_USERNAME: /opt/snappier/certs/*.pem. After a certificate is renewed, copy the new files in andsudo systemctl restart snappier-server. - Desktop app:
certs/in its settings folder —- Windows:
%APPDATA%\snappierServer\certs\ - macOS:
~/Library/Application Support/snappierServer/certs/
- Windows:
Required: privkey.pem and fullchain.pem
Let's Encrypt
sudo certbot certonly --standalone -d yourdomain.com
mkdir -p ./certs
sudo cp /etc/letsencrypt/live/yourdomain.com/privkey.pem ./certs/
sudo cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem ./certs/
sudo chown $USER:$USER ./certs/*.pem
Reverse Proxy (Caddy)
# Caddyfile
yourdomain.com {
reverse_proxy localhost:8000
}
caddy run
Caddy handles certificates, renewal, and HTTP-to-HTTPS redirect automatically.
Behind any reverse proxy (Caddy, Traefik, nginx), also turn on Behind a reverse proxy on the dashboard's Server tab — or set "trust_proxy": true in config.json / TRUST_PROXY=true in the environment. Without it the Xtream handshake advertises the internal listener (http on port 8000), players build stream URLs against an address that isn't reachable from outside, and you get the confusing failure where login works but playback doesn't. Leave it off when clients connect directly — trusting X-Forwarded-* headers from arbitrary clients would let them spoof their origin. If the proxy's headers can't be trusted or aren't sent, set a Public base URL (public_base_url) instead to force the advertised address outright.
Self-Signed (dev only)
mkdir -p ./certs
openssl req -x509 -newkey rsa:4096 \
-keyout ./certs/privkey.pem \
-out ./certs/fullchain.pem \
-days 365 -nodes -subj "/CN=localhost"
Verify
# Check server logs:
# HTTPS: "SSL certificates found in ./certs - starting HTTPS server"
# HTTP: "No SSL certificates found - starting HTTP server"
Certificate Reload
Certificates are read on startup only. After updating or renewing certificates, restart the server for changes to take effect.
App Connection
Enable the HTTPS/SSL toggle in Snappier IPTV settings. For self-signed certs, visit https://SERVER-IP:8000 in mobile Safari/Chrome first to accept the certificate.
The common problems, and where the answer is. If none of these fits, send a log and describe what you see.
The Snappier IPTV app can't reach the server
- Is the server running? Click the Snappier Server icon: if Start Server is available, it is stopped — choose it.Check the process is still running, and look at the end of its output for an error.
- Same network? The Apple TV, iPhone or iPad must be on the same home network as the computer (or reach it over a VPN).
- Firewall. Allow Snappier Server through the computer's firewall, on port
8000or whichever you chose. - Has the computer's address changed? Routers can hand out a new one. Run the setup wizard again and choose Nothing new — just connect another TV or device to see the current address.The server prints its current addresses when it starts. Update it in the app's playlist and in Settings → Snappier Server.
- HTTPS. If the server uses HTTPS, switch on Use HTTPS/SSL in the app's Settings → Snappier Server as well. See HTTPS / TLS.
The app says "Snappier Server Not Linked" or "Link Snappier Server?"
The app has not been linked to this server yet, so recordings and playlist updates cannot go through. Link it in the app's Settings → Snappier Server with the server's address, port and API token — see Connect the Snappier IPTV app.print the token with --show-token.
The setup wizard didn't open
It only opens by itself while nothing is set up. Open it from the Snappier Server icon: Set Up Snappier Server… — more in The setup wizard.The command line never opens a browser: it prints the wizard's address when it starts. Open http://YOUR-IP:8000/setup from any phone or computer on your network; it asks for the API token, which --show-token prints.
Port 8000 is already in use
Another program has the port, so the server cannot start. A notification says so: choose another port in Preferences, then Start Server.It stops with EADDRINUSE: run it with --port 9000, or set PORT. Use the new port in the app too.
The server won't start at all
A message titled Snappier Server could not start gives the reason — most often a settings file it cannot read. The icon stays, so you can still Save Support Log.It prints one line saying why — for a settings file it cannot use, [config] Refusing to start: and the reason. Run --check-config for a full report of what is wrong with config.json.
Recordings fail, or "ffmpeg could not be run"
The command line uses the FFmpeg installed on the computer. Install the full FFmpeg package — ffprobe comes with it — and restart the server. See Linux Installation for the commands.
Commercials are not detected
Check it is switched on, and see Commercial Skipping for how each platform's Comskip works — on Linux it needs particular FFmpeg libraries.
- Config location:
config.jsonin the app's settings folder —~/Library/Application Support/snappierServer/on macOS,%APPDATA%\snappierServer\on Windows. Preferences → Uninstall shows the exact one. - Config location:
~/SnappierServer/config.json, or wherever--configpoints. - The binary: a standalone executable with Node.js bundled in. No Node.js runtime needed — download and run. FFmpeg is still required.
- FFmpeg: bundled with the app.install it yourself; the command line never bundles it.
- Recording format:
.ts(MPEG Transport Stream). Enable remuxing to convert to.mkvfor better compatibility with media players like Plex and VLC. - Default storage:
~/SnappierServer/(recordings, movies, series, PVR data). Change the folders in Preferences or the dashboardin the dashboard, or with environment variables or arguments. Upgrades from an earlier release keep using an existing~/SnappierServer/folder. - Port conflicts: If port
8000is already in use, the server cannot start. The app says so in a notification: choose another port in Preferences, then Start Server from the menu-bar or tray icon.It stops with anEADDRINUSEerror; run it with--port 9000orPORT=9000. - Firewall: Allow traffic on the configured port for cross-device access.
- VPN: The server and client must be able to reach each other over the network (same LAN, or routable via VPN).
Updating
Install the new version over the old one — run the Windows installer, or drag the new app into Applications on a Mac.Replace the binary with the new version — it never replaces itself; the update check only tells you one is out. Your configuration, API token and recordings are stored separately and persist across updates.
Where the catalog is stored
Everything the server hands the app as a playlist — your IPTV provider, Catalog Sources and media servers merged together — is built in the background and saved to ~/SnappierServer/Xtream/, in the home folder of the account running the server. This location is fixed for both the desktop app and the CLI; the folder overrides above do not move it.
catalog.json— the catalog itself. Playlist requests are answered from this file, so a refresh in the app never waits on your providers.id-map.json— keeps each title's ID the same from one rebuild to the next, which is what keeps your favourites attached to the right titles.adopted-items.json— titles you found through search and then played, kept so they stay in the catalog.crawl-state.json— how far the server has got through each Catalog Source.guides/— cached programme guides.
Keep catalog.json private. Its stream addresses include your IPTV provider's username and password, which is why only your own account can read it. Don't attach it to a bug report or share it, and don't edit it by hand — the server rewrites it on every refresh. Your Catalog Sources settings are not in this folder; they are in the config file (see Config location above).
Uninstalling
Quit the app before deleting anything. Stopping the server from the tray is not enough: the app keeps running with your settings held in memory and writes them straight back, so a settings folder deleted while it is open simply reappears a moment later — which looks like the deletion silently failed. Choose Quit from the tray menu, delete, then check the folder has stayed gone.
The Preferences window has an Uninstall tab that lists the exact folders this install is using, with a copy button for each. Prefer it to the paths below, which are only the defaults — they move if you override them with environment variables or command-line arguments.
- Windows: Settings → Apps → Installed apps → snappierServer → Uninstall (for 2.0 or earlier, delete the extracted folder). Remove
%APPDATA%\snappierServerto clear settings. - macOS: Drag the app from Applications to Trash. Remove
~/Library/Application Support/snappierServerto clear settings. - Stop the server, delete the binary, and remove
~/SnappierServerto clear its settings and data. A copy of the retired Linux desktop app (AppImage) kept its settings in~/.config/snappierServer.
Recordings, downloads, and the file that keeps your favourites and watch progress matched up all live in ~/SnappierServer/, which is not removed along with the settings above — the same folder as the settings, so deleting it takes everything at once. Delete that folder only if you want all of it gone for good — it is what your favourites, watch progress and hidden items are keyed against, and losing it orphans every one of them.
If you reinstall, three things will have changed, and each one breaks something that was working before:
- A new API token. The dashboard and the app both have to be given it again; a browser that had the old one saved is refused until you re-enter it. Find it in Preferences under Security.Print it with
--show-token. - Your playlist logins are gone. They live in the settings, so every device's playlist fails to log in. Recreate them in the web dashboard (Settings → Playlist Login) and update each device.
- Possibly a different address. If your router hands this machine a new address, the one saved in the app points at nothing. Check it against the address shown on the server's own screens.
Desktop App vs CLI
They are the same server — the desktop app runs the command-line version inside it. The app adds the menu-bar or tray icon with start and stop, the Preferences, Server Logs and Settings Help windows, folder pickers, a warning before quitting stops a recording, and opening the dashboard already signed in. Both pick up changes to config.json without a restart; the command line takes its port and log rotation from flags or the environment rather than the file.
Find Your IP
# Windows
ipconfig # Look for "IPv4 Address"
# macOS
ipconfig getifaddr en0 # Or check System Settings > Network
# Linux
hostname -I # Or: ip a
When you ask for help, a support log is the most useful thing you can send. It is a copy of the server's recent log with the personal details taken out, so it shows what went wrong without showing who you are or what you watch. New in 2.0.1.
From the dashboard
- Open the dashboard, then Settings → Server → Logging.
- Under Support log, choose Last hour, Last 6 hours or Last 24 hours — pick the one that covers when the problem happened.
- The whole file is shown before anything is saved. Read it, then press Save file.
When the server will not start
The dashboard needs a running server, so there is another way in that does not:
- Desktop app: click the Snappier Server icon in the menu bar (macOS) or system tray (Windows) and choose Save Support Log. The icon now stays there even when the server cannot start, for exactly this reason.
- Command line: run
./snappier-server-cli --support-log. It writes the file into your logs folder, prints where, and exits without starting the server. In a container, that is the logs folder you already mount. See CLI Arguments for the options.
What is in it
- Kept: when things happened, what the server was doing, and how each attempt turned out — plus your server version and a short summary of your settings, such as how many sources you have.
- Replaced with placeholders: film, series, programme and channel names, your provider's and media server's addresses, IP addresses, device details, usernames and email addresses. They read as
title#1,source#2,device#1and so on. The same thing keeps the same placeholder throughout one file, so a pattern like "title#3 failed three times" still shows; what each placeholder stands for is never written down anywhere. - Never included: passwords, tokens and your settings file itself.
- A reference code, such as
K7Q2-9XMD, at the top of the file. Quote it when you send the file.
Using the desktop app, and just updating? Install the update over the old one and you're done: your settings, API token and recordings are kept, and nothing changes in the Snappier IPTV app. The rest of this section is for people who edit config.json by hand, run the command line, or kept server logs from before 2.0.
2.0.0 is a large release. Your existing config.json keeps working untouched — but several things the 1.6.0 documentation told you are no longer true, and a few setups need attention.
If you manage the config file or keep old logs
- Check your config before starting the server. New in 2.0.0:
--check-configreadsconfig.json, reports errors, warnings and notes, and exits without starting anything. A warning means "legal, but probably not what you meant" and still exits 0. - Rotate your API token — only if you ran a build before 1.7.0-12 and still have its logs, or sent one to anyone. Those builds could write the token into
server.log, and rotated log files from that period may still be on disk. Otherwise, leave it. Regenerate it in Preferences or the dashboard, then update it in the Snappier IPTV app and anywhere else you use it. - Consider rotating your provider passwords too. Outbound stream URLs carried them in the clear until 1.7.0-18, and a config reload printed the whole configuration until 1.7.0-23. If you keep old logs, or have ever sent one to support, treat those passwords as exposed.
What the 1.6.0 documentation told you that has changed
- "All endpoints require this token, except the dashboard." The dashboard now requires signing in. "Remember this device" keeps you signed in for 30 days, refreshed each time you use it; leave it unticked and the session ends with the browser.
- Passing the token as
?token=. Deprecated since 1.7.0-20 and removed in 2.1.0. Move scripts to theX-API-Tokenheader orAuthorization: Bearer. For/events, request a single-use ticket fromPOST /events/ticketinstead. - Connecting the app with your IP, port
8000and the API token. Still correct, and still the way to do it — under Settings → Snappier Server in the app.
Behind a reverse proxy, set two keys before you test playback
Xtream clients build every stream URL from the address this server reports. Behind a proxy that has to describe the proxy's public face rather than the internal listener — otherwise signing in succeeds and playback fails against an unreachable host and port, which looks like a broken catalog rather than a configuration problem. Set trust_proxy, and public_base_url where the proxy publishes a different address.
Linux and the command line: FFmpeg is yours to provide
The macOS and Windows desktop app uses its bundled FFmpeg. The command-line version — the only one on Linux, and an option on macOS and Windows — uses whatever FFmpeg is installed, which on Linux is what the distribution provides and not something this project chooses. The startup log now names the build and version it found, and says so when that version is older than the 4.x minimum it is tested against.
Install the full FFmpeg package rather than the ffmpeg binary alone — ffprobe comes with it. Without ffprobe, stream details are read from FFmpeg instead and a Dolby Vision file is reported as plain HDR. Playback decisions are unaffected.
Windows
- The 32-bit download is gone. The build stopped producing one at 1.7.0-23. The x64 build needs a 64-bit system.
- Forward-slash media paths work again. A path such as
k:/SnappierServer/Moviesused to report 0 bytes free and fill the log with errors. Fixed in 1.7.0-20 — if you rewrote your paths with backslashes to work around it, you no longer need to.
Updates are stricter
An update manifest carrying no signature is now refused rather than used and marked unverified. If you mirror or proxy the update feed and anything strips or rewrites it, update checks will stop finding releases. A failed check now reports the reason on /update-status and in the dashboard, instead of looking identical to "up to date".
If you monitor /health
degraded means something narrower now. Through 1.7.0-21 warnings flipped it, so a server its own validator passed could report degraded permanently. From 1.7.0-22 it means configuration errors and environment faults only; warnings and notes are reported alongside without moving status. Counts are public; the texts behind them need the API token.
Your existing config keys are safe
The single-provider keys — iptv_host, iptv_username, iptv_password and the single catalog-source setting — are folded into a one-entry list automatically, keeping the identity each source already had. Set the list form and the legacy keys are ignored entirely rather than merged, so there is exactly one source of truth at a time.
Two keys from older builds, require_snappier_client and snappier_client_agents, are removed from config.json on startup. Nothing is lost — they had stopped doing anything.
New keys you may want
playlists— Multiple published playlists, each a filtered view of the catalog with its own login. Setting this retires the generatedxtream_username/xtream_passwordpair; anything still using that pair must move to a playlist entry, and adding one with the same credentials keeps it working.iptv_providers, and the catalog sources list — The list forms, for several providers and catalog sources published together. Both have fields in the dashboard, under IPTV Provider and Catalog Sources.stream_auth— An expiring signature on this server's own media URLs. See Signed stream URLs for what it does and does not reach.trust_proxy/public_base_url— Reverse proxy support. On a proxied install these are usually not optional.xtream_stream_mode—"redirect"(default) hands catalog streams straight to your provider;"proxy"carries them through this server, for CDNs that reject the redirect or bind links to the resolving IP. It is the Play through this server switch in the dashboard, and is forced on while a VPN or proxy is.xtream_art_through_server—trueloads channel logos, posters and TV guide icons through this server even while the video goes straight to your provider (default:false). It is the Load pictures through this server switch, and is always on while Play through this server is.outbound_proxy_enabledand the otheroutbound_proxy_*keys — Send everything this server fetches from the internet through a WireGuard VPN, or a SOCKS5 or HTTP proxy. See VPN or Proxy.tmdb_api_key— Affects one thing only: the catalog published through a Playlist Login to the Snappier IPTV app. TV series there, from a catalog source, need this key — without it they appear in the app but open with no episodes and nothing to play. Films are unaffected, and so are series from a media server or an IPTV provider, which arrive with their own episode lists. The key is free from themoviedb.org and goes under TMDB in the dashboard, which now spells out how to get one.plex_servers— Your own media servers — Plex, Emby and Jellyfin — published into the same catalog as everything else. Set them up under Media Server; each entry carries akindsaying which product it is. The key keeps its original name so that existing entries, and the playlists scoped to them, are untouched.- Crawl depth and politeness — maximum pages, the minimum gap between requests, the request timeout, the per-run time budget and the top-up interval. All five sit under Catalog Sources in the dashboard; concurrency is set in
config.jsononly.--check-confignames the keys if you would rather editconfig.json. Worth reviewing if a source rate-limits you.
Once it is running
The setup wizard at /setup is the fastest route through the new multi-source setup, and the dashboard now manages providers, catalog sources, media servers and playlists as lists — most of what used to be hand-edited in config.json has a screen. Previous releases stay downloadable, so a rollback is available if you need one.
Snappier Server is distributed with the third-party software below. Each is licensed to you by its own authors under its own terms, not under the Snappier Server licence. The full notices are in THIRD_PARTY_LICENSES.txt, which ships inside every download and is also published here.
- FFmpeg — the video processing engine, bundled with the macOS and Windows desktop app as a separate executable (not with the command-line version, where you install it yourself). GNU GPL v3 or later. You may use, copy, modify and redistribute it under that licence, independently of ours.
- Comskip — commercial-break detection, bundled with all builds as a separate executable. GNU GPL v2 or later, on the same footing. The macOS build has parts of FFmpeg (LGPL v2.1 or later) and argtable2 (LGPL v2 or later) built into it.
- Tauri (the macOS and Windows desktop app) — MIT or Apache License 2.0, with the Rust libraries it uses, each under its own permissive licence and listed in THIRD_PARTY_LICENSES_RUST.txt, which ships inside the app and is also published here. On Windows it uses Microsoft Edge WebView2, which is part of Windows and not distributed with Snappier Server.
- Node.js (the CLI, which is also the server inside the macOS and Windows app) — MIT Licence, along with the MIT/BSD-licensed npm packages listed in the notices file.
- wireproxy — connects to your WireGuard VPN when you set one up, bundled with the macOS and Linux builds as a separate executable and downloaded by Windows the first time it is needed. ISC Licence.
Source code for the GPL components
FFmpeg and Comskip are free software, and you are entitled to their source. We build FFmpeg ourselves, for Windows and macOS, from the unmodified release published at ffmpeg.org — the version each binary reports from ffmpeg -version — with only the parts Snappier Server uses switched on. Comskip comes from github.com/erikkaashoek/Comskip; for macOS we build it ourselves, with one small change that lets it build against current FFmpeg. The scripts and that change are part of the corresponding source. For three years from the date you received a copy, we will also send you the complete corresponding source on request to support@snappieriptv.app, for no more than the cost of the distribution — tell us the Snappier Server version and platform you hold. See THIRD_PARTY_LICENSES.txt for the exact versions in this release.
Licence
Snappier Server is supplied free of charge under the Snappier Server End User Licence Agreement, which ships inside every download as LICENSE.txt. Downloading or installing it means you accept those terms. In short: use it on as many of your own machines as you like, including inside a business for its own needs; don't redistribute it, charge for it, or build it into a product or service you offer to other people. Snappier Server is free to download and use. It is the companion server for the Snappier IPTV app and works only with that app, not with other IPTV players, so an active Snappier IPTV subscription is what makes it useful. A copy you hold stays licensed to you for as long as you comply with the terms.
Acceptable use
- Snappier Server supplies no content of any kind. It ships with no playlists, no credentials and no sources.
- You are responsible for holding a lawful subscription or licence for every source you configure, and for compliance with copyright law in your jurisdiction.
- Use with sources you are not authorised to access is prohibited by these terms.
- The software may not be used as a backend for third-party commercial products.
- Redistribution of the binary is not permitted — link people to snappierserver.app instead. This applies to Snappier Server itself; the GPL-licensed programs bundled with it stay redistributable under their own terms, as set out above.
Rightsholder contact
If you hold rights in content and believe this software is being used in breach of them, write to support@snappieriptv.app. We respond to properly formed notices and act on them.
Privacy
The only request Snappier Server makes to us is an update check to snappierserver.app, which asks for a signed release manifest and sends nothing about you, your configuration or your usage. Every other request it makes goes to the sources you configure yourself — your provider, EPG and metadata services — and nowhere else. The dashboard itself makes one more request, from your browser rather than the server: it asks api.ipify.org for the public IP address of the device you are viewing it on, to show in its Connection card. The dashboard API token is held in your browser's localStorage; configuration, recordings and logs live on your own machine. There is no telemetry, no analytics and no account.
API Token
A unique API token is generated on first launch. It is the password for the dashboard and for linking the Snappier IPTV app. Find it in Preferences → Security, where Copy puts it on the clipboard. You don't need it for the dashboard on this computer: Dashboard in the menu-bar or tray icon opens it already signed in — the token is only asked for when you open the dashboard from another device.Run the server with --show-token to print it, or find api_token in config.json. Endpoints require this token unless they are listed below.
/dashboard— the sign-in shell only. The management page itself,/dashboard/app, needs the token like anything else./helpand/getting-started— documentation and the first-run walkthrough. Gating the page that tells you where to find the token would be a locked door with the key inside./,/favicon.icoand/build/— the page shell and its static assets./health— reports liveness, counts of configuration issues and warnings, and this server's name and version. Never the issue texts themselves, and never a configuration value.- The streaming paths — media players cannot send headers. The two exceptions are
/hls/proxy/signand/media/sign, which hand out playable URLs and so must present the token; setstream_auth: "signed"to require an expiring signature on the streaming paths themselves. /eventsauthenticates itself: aBearerheader is preferred, or request a single-use ticket fromPOST /events/ticket.- The Xtream surface —
player_api.php,get.php,xmltv.phpand the stream paths — authenticates with a published playlist's username and password instead of the token.
# Header (recommended)
curl -H "X-API-Token: YOUR_TOKEN" http://localhost:8000/config
# Query parameter (compatibility only - see note below)
curl http://localhost:8000/config?token=YOUR_TOKEN
The query-parameter form is deprecated as of 1.7.0-20 and is removed in 2.1.0. Prefer the header: URLs are written to proxy access logs, browser history and referrer headers, so a token placed in one ends up in all of them.
To regenerate the token, use the Dashboard Settings or POST /auth/regenerate.