iptvnator Documentation

Tv: Cross-platform IPTV player application with multiple features, such as support of m3u and m3u8 playlists, favorites, TV guide, TV archive/catchup and more.

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy iptvnator on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name iptvnator -p 4333:4333 --restart always 4gray/iptvnator:latest
Configured Services & Ports
βš™οΈ iptvnator
image: 4gray/iptvnator:latest
πŸ”Œ Ports: 4333:80
docker-compose.yml
yaml (docker-compose.yml)
---
services:
  iptvnator:
    image: 4gray/iptvnator:latest
    build:
      context: ..
      dockerfile: docker/Dockerfile
    restart: unless-stopped
    ports:
      - "4333:80"
    environment:
      BACKEND_URL: /api
      CLIENT_URL: http://localhost:4333
      PORT: "3000"
      IPTVNATOR_PROXY_ALLOW_PRIVATE_NETWORKS: "0"
      # Server storage database on the /data volume. Set to "none" to keep
      # the backend stateless.
      IPTVNATOR_STORAGE: server
    volumes:
      - iptvnator-data:/data
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://127.0.0.1/api/health >/dev/null || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

volumes:
  iptvnator-data: {}

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.app bundle 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.

bash
docker compose -f docker/docker-compose.yml up --build -d

The application is available at http://localhost:4333. See
docker/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

shell
$ brew install iptvnator

Snap

shell
$ sudo snap install iptvnator

Arch

Also available as an Arch PKG, iptvnator-bin, in the AUR (using your favourite AUR-helper, .e.g. yay)

shell
$ yay -S iptvnator-bin

Gentoo

You can install IPTVnator from the gentoo-zh overlay

shell
sudo eselect repository enable gentoo-zh
sudo emerge --sync gentoo-zh
sudo emerge iptvnator-bin

Linux 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:

bash
xattr -c /Applications/IPTVnator.app

Alternatively, if the app is located in a different directory:

bash
xattr -c ~/Downloads/IPTVnator.app

Linux: chrome-sandbox Issues

If you encounter the following error when launching IPTVnator:

text
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:

bash
sudo chown root:root chrome-sandbox
sudo chmod 4755 chrome-sandbox

Solution 2: Launch with --no-sandbox flag

Edit the desktop launcher file to add the --no-sandbox flag:

  1. Find your desktop file location:

    • Ubuntu/Debian: ~/.local/share/applications/iptvnator.desktop
    • System-wide: /usr/share/applications/iptvnator.desktop
  2. Edit the file and modify the Exec line:

    text
    Exec=iptvnator --no-sandbox %U
  3. Save the file and relaunch the application from your application menu.

Alternatively, you can launch IPTVnator from the terminal with the flag:

bash
iptvnator --no-sandbox

GNU/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:

bash
iptvnator --ozone-platform=x11

This 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)
  1. Clone this repository and install project dependencies:

    text
    $ corepack enable
    $ pnpm install
  2. Start 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:

text
$ nx serve electron-backend

To start Electron with an empty, isolated data directory instead of your normal
~/.iptvnator folder, set IPTVNATOR_E2E_DATA_DIR for that run:

text
$ rm -rf .tmp/iptvnator-empty && mkdir -p .tmp/iptvnator-empty
$ IPTVNATOR_E2E_DATA_DIR="$PWD/.tmp/iptvnator-empty" pnpm run serve:backend

This 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:

text
$ IPTVNATOR_TRACE_STARTUP=1 pnpm run serve:backend

Nx equivalent:

text
$ IPTVNATOR_TRACE_STARTUP=1 nx serve electron-backend

Useful narrower flags:

  • IPTVNATOR_TRACE_IPC=1 logs renderer window.electron.* calls reaching the
    Electron bridge
  • IPTVNATOR_TRACE_DB=1 logs DB worker requests and request-scoped DB events
  • IPTVNATOR_TRACE_SQL=1 logs SQLite statements in both the main connection and
    DB worker connection
  • IPTVNATOR_TRACE_WINDOW=1 logs BrowserWindow load, navigation, and
    unresponsive events
  • IPTVNATOR_TRACE_RENDERER_CONSOLE=1 mirrors renderer console messages into
    the Electron terminal output

Security-sensitive network compatibility flags are opt-in:

  • IPTVNATOR_ALLOW_PRIVATE_NETWORK_URLS=1 permits strict EPG fetches from
    playlist metadata (x-tvg-url, url-tvg, or tvg-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=1 disables 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:

text
$ pnpm nx reset

To run only the Angular app without Electron, use:

text
$ pnpm run serve:frontend

Disclaimer

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-backend Express 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:

bash
docker compose -f docker/docker-compose.yml up --build -d

The 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

bash
docker build -t 4gray/iptvnator -f docker/Dockerfile .

The image build runs:

bash
pnpm nx build web --configuration=pwa
pnpm nx build web-backend

Those 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 and
DOCKERHUB_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:

yaml
services:
    iptvnator:
        volumes:
            - ./ca.pem:/etc/ssl/private/provider-ca.pem:ro
        environment:
            NODE_EXTRA_CA_CERTS: /etc/ssl/private/provider-ca.pem

The 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 answers
wget from inside the container but fails in IPTVnator with
Bad 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 through
NODE_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:

yaml
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

bash
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