Snappier Server
The companion server for the Snappier IPTV app — IPTV recording with EPG (Electronic Programme Guide), PVR (automatic recording rules), and scheduled downloads, served straight to the app.
Quick Start 3 steps
- 1 Download and install the app
- 2 Run it and copy the API token from the Preferences window
- 3 Open
http://YOUR-IP:8000/dashboardor connect via the Snappier IPTV app
What this is. Snappier Server is a personal video recorder for IPTV. It runs on hardware you own and records to storage you control.
What it is not. It supplies no content. It ships with no playlists, no credentials and no sources. Everything it plays or records comes from a service you configure, using credentials you hold.
Setup Details
More detail on each step of the setup process.
1 Install
Grab the desktop app (GUI with system tray icon — recommended for most users) or the CLI binary (for servers without a display). The desktop app bundles FFmpeg (the video processing engine) on macOS/Windows. On Linux, install FFmpeg separately.
2 Launch & Configure
Run the app. It starts a server on port 8000 and generates an API token (a password for connecting). Find the token in the Preferences window (desktop app) or as api_token in ~/SnappierServer/config.json (CLI).
3 Connect
In the Snappier IPTV app, go to Settings → Snappier Server and enter your server's IP address, port 8000, and the API token. Or open http://YOUR-IP:8000/dashboard in a browser. Do not include http:// in the app — just the IP and port.
How it works: Snappier Server runs in the background and processes recording/download requests. Once a job starts, the client app can be closed — the server works independently. Each active recording or download consumes one IPTV connection. In-progress recordings can be watched from the server without using an additional connection.
Desktop App
System-tray app with Preferences GUI, EPG configuration, and bundled FFmpeg (macOS/Windows).
minisign -Vm <file> -P RWTX5W4+F8l4vXGixpj7+eZtv1u4zxGZRdOMcxMzuQowFbYKm51XfcW0 (public key).
Windows
macOS
- Extract the
.ziparchive and run snappierServer.exe.ℹ SmartScreen: Windows may show a "Windows protected your PC" warning because the app is not yet signed with Microsoft. Before proceeding, verify your download against the SHA-256 hash published next to it on this page. Once the hash matches, click "More info" then "Run anyway". - The tray icon appears in the bottom-right taskbar. Click it to open Preferences and copy your API token.
- Optional: enable EPG in Preferences and add your EPG source URL.
- Connect via the Snappier IPTV app (Settings → Snappier Server) or open
http://YOUR-IP:8000/dashboard. Find your IP: open Command Prompt and typeipconfig— look for "IPv4 Address" (usually starts with 192.168).
- Open the
.dmgand drag Snappier Server to Applications. - Launch from Launchpad or Finder.
ℹ First launch: Snappier Server is signed with an Apple Developer ID certificate and notarised by Apple, so it opens normally — there is no Gatekeeper workaround to perform. macOS may still ask you to confirm the first time you open an app downloaded from the internet; click Open. If you want to check the download is intact, verify it against the SHA-256 hash published next to it on this page.
- The menu bar icon appears top-right. Click it to open Preferences and copy your API token.
- Optional: enable EPG and add your EPG source URL in Preferences.
- Connect via the app or
http://YOUR-IP:8000/dashboard. Find your IP: open Terminal and typeipconfig getifaddr en0, or go to System Settings → Network to see your IP address.
Prerequisites
# FFmpeg is required
sudo apt update && sudo apt install ffmpeg # Debian/Ubuntu
sudo dnf install ffmpeg # Fedora/RHEL
sudo pacman -S ffmpeg # Arch
dunst, xfce4-notifyd, etc.).
- Make executable and run:
chmod +x snappierServer-*.AppImage ./snappierServer-*.AppImage - Click the tray icon to open Preferences. Copy your API token.
- Optional: enable EPG and add your EPG source URL.
- Connect via the app or
http://YOUR-IP:8000/dashboard. Find your IP withhostname -I.
Command-Line Binary
Standalone executable with Node.js bundled in — no Node.js install needed (FFmpeg is still required). For headless servers, Docker, and automated deployments.
Windows
macOS
Run in a Docker container for headless deployments.
HA add-on with stable/beta channels. amd64 + aarch64.
These packages are community-maintained and are not built, signed or supported by this project. The SHA-256 hashes published on this page do not cover them.
Prerequisites
# Install FFmpeg
brew install ffmpeg # macOS (Homebrew)
sudo apt install ffmpeg # Debian/Ubuntu
sudo dnf install ffmpeg # Fedora/RHEL
sudo pacman -S ffmpeg # Arch
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Run
chmod +x snappier-server-cli-*
./snappier-server-cli-*
# Server starts on http://localhost:8000
systemd Service (Linux)
Replace YOUR_USERNAME and paths below. Config and recordings live in that user's home directory (~/SnappierServer/) by default — to store them elsewhere, set RECORDINGS_FOLDER etc. in the env file, or pass --config / --recordings.
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: create env file for configuration
sudo mkdir -p /etc/snappier
sudo tee /etc/snappier/env << 'EOF'
PORT=8000
ENABLE_EPG=true
# EPG_URL=http://provider.com/epg.xml
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now snappier-server
sudo systemctl status snappier-server
Previous releases
Older builds stay downloadable so a regression never strands you — roll back, report what broke, and update again when it is fixed. Every file ships with its SHA-256 and minisign signature; verify exactly as above.
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
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
API Token
A unique API token is generated on first launch. Find it in the Preferences window (desktop app), config.json (CLI), or Dashboard Settings. 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.
Setup Guides & Reference
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.
Do these three things first
- 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. Builds before 1.7.0-12 could write the token into
server.log, and rotated log files from that period are still on disk. 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: FFmpeg is yours to provide
Windows and macOS use the bundled FFmpeg. Linux uses whatever the distribution provides, which this project does not choose. 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 manifest sources list — The list forms, for several providers and manifest sources published together. Both have fields in the dashboard, under IPTV Provider and Manifest 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.tmdb_api_key— Affects one thing only: the catalog published through a Playlist Login to the Snappier IPTV app. TV series there, from a manifest 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, concurrency, the per-run time budget and the top-up interval. All five sit under Manifest Sources in the dashboard, and
--check-confignames the keys if you would rather editconfig.json. Worth reviewing if a source rate-limits you.
Once it is running
The first-run walkthrough at /getting-started is the fastest route through the new multi-source setup, and the dashboard now manages providers, manifest 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 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
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.
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.
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 manifest 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.
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 the primary way to manage the server when you're not using the desktop app or the Snappier IPTV mobile app. It works on phones, tablets, and desktops, and supports both light and dark themes (toggle in the top nav).
Authentication
On first load you'll be prompted for the API token (auto-generated on first server launch — find it in the desktop Preferences window or 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). Play in-browser, download, or delete.
- Streaming Devices: active HLS sessions (transcoding) and remux sessions, plus connected client info.
- Movies / TV Series: downloaded VOD content with metadata, posters, and play/delete actions.
- 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 Watch / Delete buttons. 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: Watch live, Record once, Create PVR rule, or Set reminder. Live channel previews open in a built-in HLS player. 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 desktop app picks up port changes live; the CLI needs a restart for a new port):
- Server: port; toggles for Remux, Commercial Skipping (Comskip), and the alternative download engine; download speed limit; log rotation.
- 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.
- 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
If you're running the CLI binary on a NAS or server with no GUI, the dashboard is your only management UI — everything the desktop Preferences window can do is also available here, plus the runtime panels (active jobs, logs, stats) that the desktop app doesn't have.
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
GUI Setup
- Tray icon → Preferences → EPG section
- Enable EPG, paste your URL, name the source, set priority (1 = highest)
- Set refresh interval (24h recommended), Save
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.
CLI Setup
# 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.
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).
- Desktop Preferences: Tick Enable Commercial Skipping.
- Environment:
ENABLE_COMSKIP=true - CLI:
--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 binary for Apple Silicon (
arm64). Intel Macs are not bundled — build from source if needed. - Windows: Bundled
comskip.exe(x86 build; runs on x64 Windows, and on ARM64 Windows under emulation). - Linux: Bundled binaries for both
x86_64andaarch64(ARM64). To rebuild from source:apt install autoconf libtool build-essential libargtable2-dev libavformat-dev, then./autogen.sh && ./configure --without-sdl && make.
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. - CLI:
--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.
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 (checked in order)
./certs/— the only location the CLI checks, relative to its working directory- User data directory (desktop app only):
- Windows:
%APPDATA%\snappierServer\certs\ - macOS:
~/Library/Application Support/snappierServer/certs/ - Linux:
~/.config/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.
- Config location: Desktop app stores config in the OS user-data directory (
%APPDATA%/~/Library/Application Support//~/.config/). CLI defaults to~/SnappierServer/config.json. - CLI binary: The CLI is a standalone executable with Node.js bundled in. No Node.js runtime needed — download and run. FFmpeg is still required.
- FFmpeg: Bundled on macOS/Windows (desktop app). Install separately on Linux and for all CLI installs.
- 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). Override with env vars or CLI args. Upgrades from an earlier release keep using an existing~/SnappierServer/folder. - Port conflicts: If port
8000is already in use, the server will fail to start with anEADDRINUSEerror. Change the port withPORT=9000or--port 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
Replace the binary or app with the new version. Your configuration, API token, and recordings are stored separately in ~/SnappierServer/ (CLI) or your OS user-data directory (desktop app) and persist across updates.
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: Delete the extracted folder. Remove
%APPDATA%\snappierServerto clear settings. - macOS: Drag the app from Applications to Trash. Remove
~/Library/Application Support/snappierServerto clear settings. - Linux: Delete the AppImage or CLI binary. Remove
~/.config/snappierServerfor a desktop install, or~/SnappierServerfor a CLI one.
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 (desktop installs — a CLI install keeps its config inside this same folder, 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.
- 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
Both share the same recording/download engine. The desktop app adds a Preferences UI, system tray with start/stop controls, a log viewer window, folder browser dialogs, and automatic port hot-reload when config changes. The CLI reads config once at startup.
Find Your IP
# Windows
ipconfig # Look for "IPv4 Address"
# macOS
ipconfig getifaddr en0 # Or check System Settings > Network
# Linux
hostname -I # Or: ip a
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 Windows and macOS builds as a separate executable (not on Linux, 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.
- Electron (desktop build) and Node.js (CLI build) — MIT Licence, along with the MIT/BSD-licensed npm packages listed in the notices file.
- hls.js — JavaScript HLS client using Media Source Extensions, loaded by the dashboard in your browser. Apache License 2.0.
Source code for the GPL components
FFmpeg and Comskip are free software, and you are entitled to their source. The macOS FFmpeg build comes from martin-riedl.de and the Windows build from BtbN/FFmpeg-Builds; both are built from github.com/FFmpeg/FFmpeg, at the exact version each binary reports from ffmpeg -version. Comskip is built from github.com/erikkaashoek/Comskip. 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 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.