File: README.md
IPTVnator - IPTV Player Application
π Website | Telegram channel for discussions | Buy me a coffee | GitHub Sponsors
IPTVnator is a video player application that provides support for IPTV playlist playback (m3u, m3u8). The application allows users to import playlists using remote URLs or by uploading files from the local file system. Additionally, it supports EPG information in XMLTV format which can be provided via URL.
The application is a cross-platform, open-source project built with Electron and Angular.
β οΈ Note: IPTVnator does not provide any playlists or other digital content. The channels and pictures in the screenshots are for demonstration purposes only.
[!IMPORTANT]
Official sources only. IPTVnator is a free, open-source player β it never sells IPTV subscriptions, channels, or playlists. Websites offering "IPTVnator subscriptions/channels/premium/activated" builds are not affiliated with this project. Get the app only from the official website or GitHub Releases. See Beware of unofficial IPTVnator websites and IPTV services for details.
Features
Playlists & sources
- M3U / M3U8 playlists from local files or remote URLs π, with automatic updates on startup
- Xtream Codes (XC) and Stalker / Ministra (STB) portal support
- Custom "User-Agent" header per playlist
Playback
- Built-in HTML5 player (HLS.js or Video.js) with a resizable, resumable inline view
- Optional unified IPTVnator controls for HTML5, Video.js, and ArtPlayer, enabled in Settings β Playback (experimental)
- External players β MPV, VLC, and IINA on macOS (
mpv.app/VLC.appbundle paths supported) (desktop) - Embedded MPV β native mpv rendered inside the app window on macOS, Windows & Linux π₯οΈ (experimental Β· desktop)
- Dedicated radio player for
radio="true"streams π»
Live TV & EPG
- EPG / XMLTV TV guide with a live timeline ribbon and multi-channel grid (desktop)
- TV archive / catch-up / timeshift (desktop)
- Group-based channel list, channel-number selection, and search π
Movies & series (VOD)
- Redesigned two-state detail pages (browse β watch) with season tabs and resume positions
- Download manager for offline movies & episodes β¬οΈ (desktop)
- "Recently added" feeds and category grids with sorting & pagination
Discovery & metadata
- Global search across live TV, movies, and series (desktop)
- TMDB enrichment (opt-in) β plots, cast & crew, trailers, ratings, artwork, a "Similar" rail, clickable actor pages, and a trending dashboard rail (trending rail: desktop)
- Dashboard with recently watched & continue-watching
Organization
- Per-playlist and global favorites, aggregated across all playlists β
- Recently viewed / watch history
- Command palette (
Ctrl/Cmd+K)
Platform
- Cross-platform desktop (Electron) and installable PWA
- Desktop auto-updater and mobile remote control (desktop)
- Docker self-hosting for the PWA + web backend
- 19 languages (translation files), light & dark themes, and keyboard shortcuts
Keyboard shortcuts
Press ? or Shift+/ in the workspace to open the in-app shortcuts list.
| Area | Shortcut | Action |
|---|---|---|
| Global | Ctrl/Cmd+K |
Open command palette |
| Global | Ctrl/Cmd+F |
Open global search in the desktop app |
| Global | Ctrl/Cmd+R |
Open recently viewed in the desktop app |
| Global | Enter in workspace search |
Submit the current search |
| Navigation | Ctrl/Cmd+B |
Toggle the live sidebar |
| Navigation | 0-9 |
Select an M3U channel by number |
| Playback | Space / K |
Play or pause playback |
| Playback | F |
Toggle player fullscreen |
| Playback | ArrowLeft / ArrowRight |
Seek VOD playback by 5 seconds |
| Playback | ArrowUp / ArrowDown |
Adjust volume by 5% |
| Playback | M |
Mute audio |
| Dialogs and lists | ArrowUp / ArrowDown |
Move command palette selection |
| Dialogs and lists | Enter |
Run the selected command or open a focused item |
| Dialogs and lists | Escape |
Close dialogs and dismiss overlays |
Screenshots:
| Dashboard with recently watched content | Live channels with inline player and EPG |
|---|---|
| Add playlist dialog for M3U, Xtream, and Stalker | Live category channel list |
| Global search across live TV, movies, and series | Manage visible live categories |
| Movie category grid with sorting and pagination | Recently added movies and series |
| VOD details with playback and download actions | Download manager |
| Multi-channel EPG grid | External MPV player support |
| Radio playback with dedicated audio player | Light theme |
| Application settings | |
Note: First version of the application which was developed as a PWA is available in an extra git branch.
Self-hosted PWA
The Docker setup builds the Angular PWA and the monorepo web backend into one
image. The backend handles remote M3U parsing plus Xtream and Stalker proxy
requests under /api, so a separate 4gray/iptvnator-backend container is not
required for the default self-hosted flow.
docker compose -f docker/docker-compose.yml up --build -dThe application is available at http://localhost:4333. Seedocker/docker-compose.yml for the ready-to-run
compose file and docker/README.md for environment
variables, reverse proxy notes, PWA limitations, and build details.
The self-hosted image runs the browser PWA rather than the Electron desktop app:
EPG/XMLTV panels, Embedded MPV, managed MPV/VLC launching, the download manager,
and Electron remote-control features are not available there. If browser
playback fails, copy the stream URL and open it manually in an external player
such as MPV, VLC, or IINA.
Download
Download the latest version of the application for macOS, Windows, and Linux from the release page.
Alternatively, you can install the application using one of the following package managers:
Homebrew
$ brew install iptvnatorSnap
$ sudo snap install iptvnatorArch
Also available as an Arch PKG, iptvnator-bin, in the AUR (using your favourite AUR-helper, .e.g. yay)
$ yay -S iptvnator-binGentoo
You can install IPTVnator from the gentoo-zh overlay
sudo eselect repository enable gentoo-zh
sudo emerge --sync gentoo-zh
sudo emerge iptvnator-binLinux Embedded MPV Support
Embedded MPV on Linux is experimental and currently supports x64 desktop
sessions where IPTVnator runs under X11 or Xwayland. Native Wayland embedding
is not supported yet. Linux package launchers request X11 with--ozone-platform=x11, so Wayland desktops still need Xwayland available.
The Linux backend starts a system mpv executable with --wid, so mpv must
be installed and available on PATH. CI validates the Linux native addon and
standard packages on Ubuntu 22.04, with Flatpak packaging built on Ubuntu 24.04.
Expected user targets are Ubuntu/Debian .deb, Arch/Manjaro pacman, RPM
distributions, and AppImage on x64 systems with X11/Xwayland plus mpv
installed. Flatpak and Snap builds remain available, but embedded MPV is not
announced as supported there yet because those sandboxed formats do not expose
the host mpv executable to the embedded backend by default.
Troubleshooting
macOS: "App is damaged and can't be opened"
Older unsigned macOS builds may require removing the quarantine flag from the downloaded application:
xattr -c /Applications/IPTVnator.appAlternatively, if the app is located in a different directory:
xattr -c ~/Downloads/IPTVnator.appLinux: chrome-sandbox Issues
If you encounter the following error when launching IPTVnator:
The SUID sandbox helper binary was found, but is not configured correctly.
Rather than run without sandboxing I'm aborting now.
You need to make sure that chrome-sandbox is owned by root and has mode 4755.Solution 1: Fix chrome-sandbox permissions (Recommended for .deb/.rpm installations)
Navigate to the IPTVnator installation directory and run:
sudo chown root:root chrome-sandbox
sudo chmod 4755 chrome-sandboxSolution 2: Launch with --no-sandbox flag
Edit the desktop launcher file to add the --no-sandbox flag:
Find your desktop file location:
- Ubuntu/Debian:
~/.local/share/applications/iptvnator.desktop - System-wide:
/usr/share/applications/iptvnator.desktop
- Ubuntu/Debian:
Edit the file and modify the
Execline:textExec=iptvnator --no-sandbox %USave the file and relaunch the application from your application menu.
Alternatively, you can launch IPTVnator from the terminal with the flag:
iptvnator --no-sandboxGNU/Linux: Wayland startup failure
If IPTVnator exits on GNU/Linux with errors about failing to connect to
Wayland or initialize the Ozone platform, force X11/XWayland instead:
iptvnator --ozone-platform=x11This workaround is mainly for older or problematic Linux graphics stacks. The
Snap package already includes this X11 override by default. For AppImage,
direct binaries, and other Linux package formats, pass the flag manually when
needed.
How to Build and Develop
Requirements:
- Node.js 22.13β22.x or 24 and newer with pnpm (via Corepack)
Clone this repository and install project dependencies:
text$ corepack enable $ pnpm installStart the application:
text$ pnpm run serve:backend
This will open the Electron app in a separate window, while the Angular dev server will run at http://localhost:4200.
The equivalent Nx command is:
$ nx serve electron-backendTo start Electron with an empty, isolated data directory instead of your normal~/.iptvnator folder, set IPTVNATOR_E2E_DATA_DIR for that run:
$ rm -rf .tmp/iptvnator-empty && mkdir -p .tmp/iptvnator-empty
$ IPTVNATOR_E2E_DATA_DIR="$PWD/.tmp/iptvnator-empty" pnpm run serve:backendThis redirects the SQLite database, Electron user data, and local config under
the given directory. Delete that directory whenever you want a fresh empty
state.
If you need startup diagnostics for a white screen or a frozen route, you can
also turn on opt-in Electron tracing. These logs are written to the Electron
terminal output so they still help when the renderer DevTools never open:
$ IPTVNATOR_TRACE_STARTUP=1 pnpm run serve:backendNx equivalent:
$ IPTVNATOR_TRACE_STARTUP=1 nx serve electron-backendUseful narrower flags:
IPTVNATOR_TRACE_IPC=1logs rendererwindow.electron.*calls reaching the
Electron bridgeIPTVNATOR_TRACE_DB=1logs DB worker requests and request-scoped DB eventsIPTVNATOR_TRACE_SQL=1logs SQLite statements in both the main connection and
DB worker connectionIPTVNATOR_TRACE_WINDOW=1logs BrowserWindow load, navigation, and
unresponsive eventsIPTVNATOR_TRACE_RENDERER_CONSOLE=1mirrors renderer console messages into
the Electron terminal output
Security-sensitive network compatibility flags are opt-in:
IPTVNATOR_ALLOW_PRIVATE_NETWORK_URLS=1permits strict EPG fetches from
playlist metadata (x-tvg-url,url-tvg, ortvg-url) to resolve to
localhost, LAN, or other private addresses. Directly configured
Xtream/Stalker portals and private playlist servers remain supported without
this flag. Prefer the in-app source-scoped βAllow sourceβ action for a trusted
EPG URL.IPTVNATOR_ALLOW_INSECURE_TLS=1disables certificate validation for remote
playlist imports and refreshes for the whole Electron process. Prefer the
in-app host-scoped trust action for a trusted provider with a self-signed or
otherwise invalid certificate.
If the local Nx daemon gets into a bad state before rerunning Electron, reset it:
$ pnpm nx resetTo run only the Angular app without Electron, use:
$ pnpm run serve:frontendDisclaimer
IPTVnator doesn't provide any playlists or other digital content.
Trademark
The name "IPTVnator" and the IPTVnator logo are unregistered trademarks of the project owner. The MIT license covers the source code only β it does not grant rights to the name or logo. Forks and redistributions (including app-store submissions) must use a different name and their own icon. See TRADEMARK.md for details.
File: docker/README.md
Self-hosted IPTVnator
The self-hosted image contains both pieces required for the browser PWA:
- Angular PWA static files served by nginx
- The monorepo
web-backendExpress app proxied under/api
The historical standalone 4gray/iptvnator-backend image is no longer needed
for the default Docker deployment.
PWA Limitations And Playback Troubleshooting
The Docker image runs the browser PWA, not the Electron desktop application.
That means:
- EPG/XMLTV panels and multi-EPG views are not available in the self-hosted PWA.
- Playlist metadata is stored in the browser through IndexedDB, and Xtream user
data is stored by the PWA data source in localStorage. The PWA does not use
the Electron SQLite database or DB worker. - Docker cannot launch local desktop players or Embedded MPV. If a stream does
not play inline in the browser, use the in-app copy URL action and open the
stream manually in an external player such as MPV, VLC, or IINA. - Electron-only features such as the download manager, external-player process
control, and remote-control integrations are outside this runtime.
Run With Docker Compose
From the repository root:
docker compose -f docker/docker-compose.yml up --build -dThe ready-to-run compose file is docker-compose.yml.
By default the app is available at http://localhost:4333. No additional
environment variables, backend repository checkout, or separate backend
container are required for the default local deployment.
Build The Image
docker build -t 4gray/iptvnator -f docker/Dockerfile .The image build runs:
pnpm nx build web --configuration=pwa
pnpm nx build web-backendThose Nx builds generate platform-independent JS and static assets. In
multi-architecture CI builds, the Dockerfile runs this build stage on the native
BuildKit builder platform, then copies the generated output into each target
runtime image. That avoids running the Angular/Nx build through QEMU when
publishing linux/amd64 and linux/arm64 images.
Published Docker Tags
Pull request builds validate the Dockerfile without pushing an image. Docker
Hub publishing happens only from trusted repository events.
Publishing requires the repository secrets DOCKERHUB_USERNAME andDOCKERHUB_TOKEN; pull request builds and default manual runs do not use those
secrets.
| Tag pattern | Published from | Use case |
|---|---|---|
latest |
master pushes |
Default self-hosted image for users who want the newest merged PWA build. |
<version>-pwa |
master pushes |
Latest PWA image for the current package.json version. |
<version>-pwa-<sha> |
master pushes |
Immutable PWA image for a specific merged commit within a version. |
sha-<sha> |
master pushes |
Commit-addressable image, useful for rollback and support diagnostics. |
<version> / v<version> |
v* release tags |
Release image aligned with a repository release tag. |
stable |
Stable v* release tags |
Most recent non-prerelease tagged release image. |
manual-<sha> |
Manual runs with push |
Explicit maintainer-triggered rebuilds outside normal publish events. |
Use latest for the simplest self-hosted setup. Pin sha-<sha> or<version>-pwa-<sha> when you need reproducible deployments. Use release tags
when you want the Docker image to track a tagged IPTVnator release rather than
every merge to master.
Runtime Configuration
The container writes /usr/share/nginx/html/assets/app-config.js on startup.
That file sets window.__IPTVNATOR_CONFIG__.BACKEND_URL, which the PWA reads
before it creates PwaService.
These variables are supported by the Docker image. The compose file sets the
safe local defaults shown below.
| Variable | Default | Purpose |
|---|---|---|
BACKEND_URL |
/api |
Browser-facing backend URL used by the PWA. Keep /api for the bundled nginx proxy. |
CLIENT_URL |
http://localhost:4333 |
Allowed browser origin for backend CORS. Use the public URL when hosting behind a reverse proxy. Multiple origins can be comma-separated. |
PORT |
3000 |
Internal Express backend port. nginx proxy config is rendered from the template to match it at startup. |
IPTVNATOR_PROXY_ALLOW_PRIVATE_NETWORKS |
0 |
Set to 1 or true only for trusted local/LAN deployments that intentionally proxy private network IPTV or mock endpoints. |
NODE_EXTRA_CA_CERTS |
unset | Optional Node.js CA bundle path for providers using private certificate authorities. Mount the CA file into the container and set this path. |
The web backend proxy accepts only http and https provider URLs. The PWA
first registers provider URLs through /provider-targets, then uses the
returned targetId for playlist, Xtream, and Stalker proxy calls. The backend
blocks loopback, private, link-local, and reserved network targets by default so
a publicly exposed instance cannot be used as a generic internal-network
fetcher. If you enable IPTVNATOR_PROXY_ALLOW_PRIVATE_NETWORKS=1, keep the
instance restricted to trusted users.
For providers that use private certificate authorities, keep TLS validation
enabled and pass the CA bundle to Node:
services:
iptvnator:
volumes:
- ./ca.pem:/etc/ssl/private/provider-ca.pem:ro
environment:
NODE_EXTRA_CA_CERTS: /etc/ssl/private/provider-ca.pemThe entrypoint renders the nginx config from docker/nginx.conf, starts the
backend, waits for /health, and only then starts nginx. The nginx config
serves the PWA with SPA fallback, avoids caching assets/app-config.js, and
proxies /api/* to the internal backend. The Dockerfile and compose file both
define a health check against /api/health. If nginx or the backend exits
after startup, the entrypoint exits the container so Docker Compose can apply
the restart: unless-stopped policy.
IPv6, VPNs, And Connection Fallback
Node races IPv6 and IPv4 addresses when a provider hostname has both ("happy
eyeballs"), and its stock per-attempt budget of 250 ms is too short for many
VPN and container networks. The classic symptom is a provider that answerswget from inside the container but fails in IPTVnator withBad Gateway (ETIMEDOUT) β typically behind an IPv4-only VPN namespace such
as Gluetun/WireGuard, where the IPv6 route is unreachable and the working
IPv4 handshake needs more than 250 ms.
The backend therefore raises the per-attempt connection budget to 2500 ms at
startup. This keeps the IPv6βIPv4 fallback fully automatic in both
directions. If you pass--network-family-autoselection-attempt-timeout yourself throughNODE_OPTIONS, your value wins and the backend leaves it untouched.
If a provider still fails, check the container logs first: outbound provider
failures are logged with the target hostname and the underlying Node error
codes (ETIMEDOUT, ENETUNREACH, ENOTFOUND, ...), and the same code is
returned to the app in the error message. As a last resort you can pin the
legacy behavior entirely:
services:
iptvnator:
environment:
# Disables IPv6/IPv4 racing completely; only for networks where
# IPv6 can never work. Breaks IPv6-only deployments.
NODE_OPTIONS: '--dns-result-order=ipv4first --no-network-family-autoselection'Local Validation
pnpm nx test web-backend
pnpm nx build web --configuration=pwa --skip-nx-cache
pnpm nx build web-backend
pnpm nx run web-e2e:e2e -- --project=chromium --grep @self-hosted
docker compose -f docker/docker-compose.yml config