iptv-org/epg: Download and Serve EPG XML Guides for Thousands of TV Channels
Project brief: Utilities for downloading the EPG (Electronic Program Guide) for thousands of TV channels from hundreds of sources.
At a glance
- What is it?
- iptv-org/epg is a Node.js toolkit for downloading Electronic Program Guide data from hundreds of scraper sources, outputting XMLTV-format guide.xml files. It includes a Docker image that runs on a cron schedule, parallel download support, and a custom channel list mechanism for combining sources.
- Who is it for?
- iptv-org/epg is suited to self-hosted IPTV setups where the player can consume a XMLTV guide.xml over HTTP and where the operator wants control over which sources are scraped and how often. It is not suited to situations where the target site blocks scrapers, since heavy parallel loads can trigger rate limiting or IP bans as the README warns.
- Can I use it commercially?
- Yes. Unlicense is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly HTML, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What EPG Data Is and Why This Tool Exists
Electronic Program Guide data tells an IPTV player what is currently airing on a channel, what comes next, and how to display a schedule grid. Without EPG data, IPTV clients show only a live stream with no program context. Most IPTV players accept XMLTV-formatted XML files, commonly named guide.xml, as their EPG source.
iptv-org/epg provides a set of Node.js scripts that scrape program schedule data from hundreds of websites and broadcast data sources, then output XMLTV-compatible XML files. Each source in the repository has a corresponding scraper in the `sites/` directory. The repository also maintains a channel mapping that links channel names across sources. The project is part of the iptv-org organization, which also maintains public IPTV channel lists.
Installing and Running the First Download
Node.js and Git are required. Clone the repository with a shallow clone to avoid downloading the full history:
git clone --depth 1 -b master https://github.com/iptv-org/epg.gitNavigate into the directory and install dependencies:
cd epg
npm installThe `npm install` step also runs a `postinstall` script that calls `api:load` to initialize the channel database from the iptv-org API. To download the guide for a single site, pick a site name from the SITES.md file and run:
npm run grab --- --sites=example.comWhen finished, a `guide.xml` file appears in the current directory. To update the repository code and dependencies after pulling new commits:
git pull
npm installParallel Downloads and Custom Channel Lists
By default, channel guides are downloaded one at a time. To fetch from multiple sites simultaneously, increase the connection count with `--maxConnections`:
npm run grab --- --sites=example.com --maxConnections=10The README warns that heavy parallel loads can cause some sites to return errors or block access entirely, so the appropriate value depends on the source.
To download from multiple sites and split the output into separate files:
npm run grab --- --sites=example1.com,example2.com --output=guides/{site}.xmlFor a custom channel list, create an XML file and copy the channel definitions from the `sites/` directory:
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="arirang.com" lang="en" xmltv_id="ArirangTV.kr" site_id="CH_K">Arirang TV</channel>
</channels>Then pass the file path via `--channels`:
npm run grab --- --channels=path/to/custom.channels.xmlAdditional options include `--lang` to restrict downloads to specific language codes, `--timeout` in milliseconds for each request (default: 30000), and `--delay` between requests.
Serving the Guide Over HTTP
To make the downloaded guide available to IPTV players over a local network, serve the directory with npx serve after the download completes:
npx serveThe guide then becomes available at `http://localhost:3000/guide.xml`. Other devices on the same network can reach it at `http://<your_local_ip_address>:3000/guide.xml`. This is documented in the README as the simplest way to expose the guide via URL.
For automated recurring downloads, the README shows using chronos with a cron expression:
npx chronos --execute="npm run grab --- --sites=example.com" --pattern="0 0,12 * * *" --logThis example runs the grab command at midnight and noon every day, logging output.
Running with Docker and Environment Variables
A pre-built Docker image is available at `ghcr.io/iptv-org/epg:master`. The image runs on Node.js 22 Alpine and uses PM2 to manage the grab process on a schedule. To pull and start the container:
docker pull ghcr.io/iptv-org/epg:masterdocker run -p 3000:3000 -v /path/to/channels.xml:/epg/public/channels.xml ghcr.io/iptv-org/epg:masterBy default, the grab runs every day at 00:00 UTC and saves the result to `/epg/public/guide.xml` inside the container. Configure behavior through environment variables passed with `-e`. The documented variables include `CRON_SCHEDULE` for the cron expression, `MAX_CONNECTIONS` for concurrent request limit, `GZIP` and `JSON` to create compressed or JSON variants of the guide, `PROXY` for a SOCKS5 or HTTP proxy, `DAYS` for how many days of schedule to retrieve, `TIMEOUT` per request in seconds, `DELAY` between requests, and `RUN_AT_STARTUP` to trigger a download immediately when the container starts.
The `--lang` flag restricts downloads to channels in specific languages, which is useful when a single site source covers multiple languages but you only need one. The flag accepts comma-separated language codes, for example `--lang en,id` to download only English and Indonesian channels. This reduces download time and output file size for setups focused on specific regions.
The `--output` flag supports a `{site}` template variable that expands to the site name, making it straightforward to maintain one output file per source. When combining guides from multiple sources into a single file for an IPTV player, omit the template and all results write to the same `guide.xml`.
Limitations and What the Tool Cannot Do
The scraper coverage depends entirely on whether a site has a corresponding file in the `sites/` directory. Channels from sources not listed in SITES.md are not available. The project has no mechanism for automatically adding new sources; contributors must write and submit scrapers through the standard pull request process.
Each site's scraper lives as a directory under `sites/`, containing a `.test.ts` test file alongside the scraper implementation. The package.json shows test commands for running per-site tests, which the CI system uses to validate scraper submissions before merging them. This means the quality of scrapers depends on the test coverage that contributors include when they submit them.
Schedule coverage is also limited by what each source publishes. Some sources may provide only a few days of schedule data ahead, while others offer more. The `DAYS` Docker environment variable and its equivalent CLI option control how far ahead to request, but they cannot extend beyond what the source offers.
Site access restrictions are a practical concern. Some sites rate-limit automated requests and will block access under heavy parallel load. The README explicitly warns about this when describing the `--maxConnections` flag. Running with a high connection count against a site that blocks bots may result in partial or empty output files without clear error messages.
The Unlicense removes all copyright from the project, placing it in the public domain. This means anyone can use or modify the code without restriction, but it also means the project makes no guarantees about reliability or suitability. Organizations with open-source license compliance requirements should note that the Unlicense is treated differently from MIT or Apache-2.0 in some legal contexts.
A hosted alternative in the IPTV space is EPG.best, a service that provides pre-assembled XMLTV feeds for many countries. The key difference is that EPG.best is a third-party service with no self-hosting option, while iptv-org/epg runs on your own infrastructure and gives you control over which sources are scraped and how often.
Maintenance and License
The last push was on 2026-09-24. The project is released under the Unlicense, which places it in the public domain with no conditions. The repository uses GitHub Actions for update workflows and includes Husky for pre-commit hooks. The package.json marks the project as private, meaning it is not published to npm as a package and must be used by cloning the repository.
Editorial conclusion
iptv-org/epg is suited to self-hosted IPTV setups where the player can consume a XMLTV guide.xml over HTTP and where the operator wants control over which sources are scraped and how often. It is not suited to situations where the target site blocks scrapers, since heavy parallel loads can trigger rate limiting or IP bans as the README warns. Teams running this on a server should review the sites/ directory to confirm the channels they need are covered before committing to the setup. The project is licensed under the Unlicense, which places it in the public domain.
Frequently asked questions
How to use iptv org epg to get an EPG guide?
Clone the repository, run npm install, then run npm run grab with the --sites flag set to a site name from SITES.md. The command writes a guide.xml file in the current directory. Serve it with npx serve to make it available to IPTV players over HTTP on port 3000.
Does iptv-org/epg provide a hosted EPG URL?
No. The project is a self-hosted tool. You clone the repository, run the grab command on your own server or machine, and serve the resulting guide.xml yourself. The Docker image automates the scheduling.
Can iptv-org/epg run on a schedule automatically?
Yes, in two ways. The Docker image runs the grab command on a configurable CRON_SCHEDULE environment variable, defaulting to midnight UTC daily. Outside Docker, the README shows using npx chronos with a cron expression to run the grab command at specified intervals.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/iptv-org-epg)