An EPG is the TV guide that turns a raw IPTV playlist into a browsable schedule. To set one up, get an XMLTV URL from your provider, paste it into your player's EPG settings, match channels by tvg-id, then refresh. Nightmare TV merges multiple XMLTV sources and the Xtream API automatically.

The EPG is the difference between an IPTV subscription you actually watch and a 5,000-channel haystack you scroll through and give up on. But XMLTV (the format that powers IPTV EPGs) was designed in 2001 for a different era. It works. It just requires you to understand five things that nobody bothers to document.

What an EPG is, what XMLTV is

An EPG (Electronic Program Guide) is the metadata that tells your player "Channel 12 is News One; right now it's showing Evening News from 19:00 to 19:55, then Night Documentary". Without an EPG you have a list of channel names and live video, but no idea what's on or what's coming next. For traditional cable, this came on a Channel 100 grid. For IPTV, it comes from a separate XML file your player has to fetch and match.

XMLTV is the de facto file format. Originally a Linux project for parsing Zap2it grids, it became the standard the way M3U did: by being there first and being simple enough that everyone copied it. The format describes channels and programmes in XML. There's no central registry, no canonical source: each provider, broadcaster, or community generates their own and serves it at a URL.

XMLTV anatomy: the actual file format

An XMLTV file has two kinds of element: <channel> and <programme>. Channels come first, then programmes. Trimmed example:

<?xml version="1.0" encoding="UTF-8"?>
<tv generator-info-name="example-grabber" date="20260515030000">

  <channel id="newsone.uk">
    <display-name lang="en">News One HD</display-name>
    <icon src="https://example.com/icons/newsone.png"/>
    <url>https://example.com/newsone</url>
  </channel>

  <channel id="newstwo.uk">
    <display-name lang="en">News Two HD</display-name>
    <icon src="https://example.com/icons/newstwo.png"/>
  </channel>

  <programme start="20260515190000 +0100" stop="20260515195500 +0100" channel="newsone.uk">
    <title lang="en">Evening News</title>
    <sub-title lang="en">The Star Beast</sub-title>
    <desc lang="en">The Doctor and Donna meet again, but reality is unravelling.</desc>
    <category lang="en">Drama</category>
    <category lang="en">Sci-Fi</category>
    <episode-num system="onscreen">S14E01</episode-num>
    <icon src="https://example.com/posters/dw-s14e01.jpg"/>
    <rating system="UK"><value>PG</value></rating>
  </programme>

  <programme start="20260515195500 +0100" stop="20260515203000 +0100" channel="newsone.uk">
    <title lang="en">Night Documentary</title>
  </programme>

</tv>

Key things to notice:

  • The channel id is opaque, it can be anything. Here it's newsone.uk, but it could be news.1 or News_One_HD or id-12345. There is no standard.
  • The programme references the channel by id, not by name.
  • Times are YYYYMMDDHHMMSS with an explicit timezone offset (+0100 here is BST).
  • Most fields are optional. A minimum-viable programme is just title + start + stop + channel.

A full XMLTV file with 7-day coverage for 800 channels is 25 to 50 MB plain text. Compressed (gzip), it's 4 to 8 MB.

XMLTV vs Xtream-served EPG: what changes

If you read our M3U vs Xtream Codes article you'll remember Xtream has its own in-band EPG via the get_short_epg API. So why bother with XMLTV at all? Several reasons:

AspectXMLTVXtream API
Coverage7 to 14 days standardUsually 1 to 3 days, sometimes 24h only
Detail per programmeFull: title, description, cast, ratings, postersOften just title + description
Offline useLocal file worksRequires live connection
Channel matchingManual tvg-id headacheAutomatic (server-paired)
Update frequency1 to 4 times dailyOn-demand, fresher
Last-minute schedule changesStale until next refreshCaught quickly

The split decision most power users land on: Xtream's API for live UX (refreshing programme cards, current programme indicators) plus a supplementary XMLTV file for 7-day depth (planning what to record on Friday, reminders, etc.). Nightmare TV merges both transparently: Xtream wins for "now/next" displays, XMLTV fills the future days.

tvg-id matching: the most common cause of EPG failures

Your M3U file has channels with tvg-id attributes:

#EXTINF:-1 tvg-id="newsone.uk" tvg-name="News One HD" tvg-logo="..." group-title="UK | HD",News One HD
https://stream.example.com/live/abc/12345.m3u8

Your XMLTV file has channels with id attributes:

<channel id="newsone.uk">
  <display-name lang="en">News One HD</display-name>
</channel>

The player matches these by string equality. newsone.uk in the M3U matches newsone.uk in the XMLTV. Case-sensitive. Whitespace-sensitive. No normalisation.

This is where most "my EPG is broken" complaints come from. The M3U from your provider has tvg-id="News One HD" (with spaces) but the community XMLTV uses id="newsone.uk". They don't match. Your player shows no EPG for News One: even though the data is there in both files.

How to diagnose

The fastest test:

  1. Open your M3U file in a text editor. Find one channel with a known broadcast. Note its tvg-id exactly.
  2. Open your XMLTV file (gunzip it first if needed). Search for the channel's display name to find its <channel id="...">.
  3. Compare the two strings byte-for-byte. Spaces? Capitals? Suffix differences?

If they don't match exactly, EPG won't work for that channel. The fix is to make them match.

How to fix

Three approaches in increasing difficulty:

  1. Find a matched playlist+EPG pair. Some XMLTV providers publish M3U files designed to match their XMLTV. The tvg-ids already line up. Easiest path.
  2. Rewrite your M3U's tvg-id. A Python script that opens the M3U, looks up each channel name in the XMLTV, and rewrites the tvg-id to match. This is what most "EPG mapping tools" do.
  3. Make the player apply a translation table. Some players (TiviMate, Nightmare TV) let you set up channel mappings in the UI. Slower than scripting but UI-friendly.

Approach #1 is the right answer for most users. If you're paying for IPTV, your provider's recommended XMLTV source should match their M3U tvg-ids. If it doesn't, that's a complaint to send back to support.

Timezones: the three clocks that interact

This is where serious users lose a Saturday afternoon.

An XMLTV file has explicit timezone offsets on every start and stop. But there are three different clocks involved:

  1. The broadcast's timezone, what time it actually airs in the country it's from.
  2. The XMLTV file's stated timezone: what +0100 or UTC the generator wrote into the file.
  3. Your display's timezone: what your Windows/Android device thinks the time is.

The player's job is to interpret #2 and display in #3. If the file says start="20260515190000 +0100" and your machine is set to UTC+02:00 (Istanbul), the player should show "20:00 local time". This is straightforward when everyone follows the standard.

The problems start when:

  • The XMLTV generator writes start="20260515190000" with no timezone offset. Some players assume UTC, others assume local time. Same file, different display, different schedule.
  • The generator writes +0000 but actually means BST. Times shift by an hour, sometimes seasonally (DST).
  • Your player has an "EPG timezone offset" setting and you've set it to "fix" what was already correct. Now everything is off by exactly the amount you "corrected".
  • The generator does daylight saving wrong: uses CET year-round when half the year should be CEST. UK channels go 1 hour off in summer.
THE GOLDEN RULE

Never apply a manual EPG timezone offset in your player unless you've verified the XMLTV file omits or misstates the timezone. A well-formed XMLTV file with explicit +0100/-0500/etc. offsets needs no correction. If everything is off by exactly one hour twice a year, that's a DST bug in the XMLTV generator, not something to fix on your side.

How to verify your XMLTV's timezone

Open the file in a text editor. Find a programme whose broadcast time you actually know: e.g. the evening news on a major channel. Compare the XMLTV time + offset against the real broadcast time. They should match. If they're off by exactly one hour, suspect DST. If they're off by 5 hours, suspect a generator that wrote UTC offsets as +0000 on Eastern US content.

Compression, size, and update cadence

A full 7-day XMLTV for 800 channels is around 30 to 50 MB uncompressed. Gzipped, that drops to 4 to 8 MB and gzip is essentially free for the server (Cloudflare and similar do it automatically) and free for the client (every HTTP library handles it transparently).

Players support three common formats:

  • guide.xml, plain text, biggest, simplest
  • guide.xml.gz, gzipped, 6× smaller
  • guide.xml.xz: LZMA compressed, 8× smaller but not all players support

For most providers, the URL pattern is https://example.com/epg.xml.gz and the player handles the decompression. If your player times out on a 30 MB plain-text fetch but works with 5 MB gzip, that's bandwidth not the player.

Update cadence

How often should the player refetch the XMLTV file?

  • Once daily: fine for most. Schedules change occasionally but a daily refresh catches most.
  • Twice daily (every 12h): better. Catches schedule changes faster.
  • Every 4h: overkill except for live sports where schedules shift constantly.
  • On player startup: wasteful if you start the player multiple times a day. Don't refetch unless > some interval has passed.

Nightmare TV's default is "every 12 hours, plus on startup if the cached EPG is > 6 hours old". This keeps the guide fresh without hammering the source server.

Where to get XMLTV (and the multi-source trick)

Where to get an XMLTV file in 2026:

  1. From your IPTV provider. Most ship an xmltv_url in your account dashboard. This is the primary source.
  2. Community-maintained sources. Public XMLTV grabbers and aggregators publish files covering common channels. Quality varies; check coverage for your region.
  3. Self-generated. If you're determined, projects like tvgrabnl or iptv-tools scrape broadcaster websites and generate XMLTV themselves. Maintenance burden is real.

The multi-source merge trick

For a 5,000-channel IPTV list mixing UK, US, Turkish, Arabic, and Latin American channels, no single XMLTV source covers everything well. The trick is to load multiple XMLTV files into the player and let it merge them by channel id.

The strategy:

  1. Load the primary XMLTV first, typically the one from your provider.
  2. Load secondary XMLTV second: covers gaps in your primary (e.g. Turkish channels if your primary is UK-focused).
  3. Load tertiary if needed: region-specific, fills the long tail.

The player merges by channel id. If channel news24.tr exists in both primary and secondary, you get duplicates. The fix is usually to use a primary that's clearly distinct from your secondaries: different naming conventions on purpose.

Nightmare TV lets you configure multiple XMLTV URLs with per-source priorities: higher priority sources win on conflicts.

Nightmare TV merges multiple EPG sources transparently

Load primary + secondary + tertiary XMLTV URLs, set per-source priority, and the player handles the merge. Plus the Xtream API can co-exist as a "now/next" overlay on top of XMLTV depth.

Download free trial Microsoft Store · 7-day trial · Windows 10/11

A clean EPG setup from scratch

If you're starting fresh:

  1. Get the XMLTV URL from your IPTV provider. It's usually in your dashboard under "EPG", "XMLTV URL", or "TV Guide".
  2. Test it in a browser. Paste the URL. You should either see XML text or a download prompt. If you get a 404 or 403, the URL is wrong or your subscription doesn't include EPG.
  3. Verify it matches your M3U. Pick one channel from your M3U, find its tvg-id, search for it in the XMLTV. Match found = good. No match = mismatch problem (see section above).
  4. Configure your player. Settings → EPG → add XMLTV URL. Pick a sensible refresh cadence (every 12 hours is fine).
  5. Force first fetch. Most players have a "refresh EPG now" button. Do that. Watch for an error.
  6. Open a channel and check the guide. The current programme should appear with title, time, description. If not, drop to troubleshooting.

How to set up an XMLTV EPG in Nightmare TV (step by step)

Middleware docs explain the XMLTV format but rarely walk you through the player itself. Here is the exact four-step path inside Nightmare TV: the same flow works on Windows, macOS and Android TV:

  1. Get the XMLTV URL from your IPTV provider's dashboard, usually listed under EPG, XMLTV URL or TV Guide. Paste it into a browser to confirm it returns XML text or a download rather than a 404 or 403. If your provider has no XMLTV link, a region-matched community source works as a fallback.
  2. In Nightmare TV open Settings, go to the EPG section and choose Add XMLTV source. Paste the URL you verified, then save. You can add several XMLTV URLs here and set a per-source priority, so a UK-focused primary and a Turkish secondary can both load and the higher-priority source wins on any conflict.
  3. Match channels by tvg-id. The id in your M3U must equal the channel id in the XMLTV byte-for-byte, because matching is case- and whitespace-sensitive. If a channel shows no guide, open both files and compare the strings, or use Nightmare TV's channel-mapping screen to point a playlist channel at the correct EPG id.
  4. Refresh the guide. Use Refresh EPG now to force the first fetch, then open any channel and confirm the current programme shows its title, time and description. Nightmare TV re-fetches every 12 hours, plus on startup if the cached guide is over six hours old, so the schedule stays fresh without hammering the source server.

The 10 silent failures and how to spot them

  1. EPG empty for some channels. tvg-id mismatch. Open the M3U, open the XMLTV, compare strings for the missing channel.
  2. EPG empty for all channels. XMLTV didn't fetch. Test the URL in a browser; check player logs.
  3. EPG one hour off. DST bug. Either the XMLTV generator handles DST wrong, or your machine's timezone is set wrong.
  4. EPG several hours off. XMLTV omits timezone offset. Try a different source, or set a manual offset in the player (last resort).
  5. Programme titles in wrong language. XMLTV has multilingual <title> tags; player picks the wrong one. Player settings → preferred EPG language.
  6. EPG shows yesterday's schedule. Cached, didn't refresh. Force a refresh; check the cache TTL setting.
  7. "Now playing" wrong, but the rest of the day correct. Programme is overrunning or schedule changed at the last minute. XMLTV is stale until next refresh. Switch to Xtream's API for "now" data.
  8. Description text shows as &amp; or &#x.... XMLTV is double-escaped. Source file is malformed; report to the provider.
  9. Programme icons missing. The <icon> URLs are 404 or HTTPS-mixed-content blocked. Check one of the URLs in a browser.
  10. Random channels have wrong EPG. tvg-id collision: your M3U has two channels with the same id, so both pick up the first one's guide. Fix: make M3U tvg-ids unique.

Frequently asked questions

How do I add an XMLTV EPG to Nightmare TV?

Get an XMLTV URL from your IPTV provider's dashboard, then in Nightmare TV open Settings, go to the EPG section and choose Add XMLTV source. Paste the URL, save, and press Refresh EPG now. Open a channel to confirm the current programme appears with its title, time and description. If a channel is blank, it is almost always a tvg-id mismatch.

Why is my IPTV EPG not working for some channels?

The single most common cause is a tvg-id mismatch: the id in your M3U does not exactly equal the channel id in the XMLTV file. Matching is case-sensitive and whitespace-sensitive with no normalisation, so News One HD will never match newsone.uk. Open both files, compare the strings byte-for-byte, and make them identical or remap them in your player.

Can I load more than one XMLTV source at once?

Yes. In Nightmare TV's EPG settings you can add several XMLTV URLs and give each a priority. The player merges them by channel id, so a UK-focused primary plus a Turkish or Arabic secondary covers a mixed playlist's long tail. On any duplicate channel, the higher-priority source wins, which keeps the merged guide clean.

Why is my EPG one hour off?

Almost always a timezone problem. A well-formed XMLTV file carries an explicit offset like +0100 on every programme and needs no correction. If everything is off by exactly one hour twice a year, that is a daylight-saving bug in the XMLTV generator. Only apply a manual EPG offset in the player after you have confirmed the file omits or misstates its timezone.

What is the difference between XMLTV and the Xtream Codes EPG?

XMLTV is a standalone file, typically covering 7 to 14 days with full descriptions, cast and posters, and it works offline. The Xtream Codes API serves EPG in-band, usually only 1 to 3 days, but it updates on demand and catches last-minute changes. Nightmare TV uses both: Xtream for accurate now and next, XMLTV for the deeper future schedule.

TL;DR

  • An EPG is what makes 5,000 IPTV channels actually browsable. XMLTV is the file format; Xtream's API is an alternative for richer real-time data.
  • tvg-id matching between M3U and XMLTV is the #1 source of "EPG doesn't work" complaints. Strings must match byte-for-byte.
  • Timezones: three clocks interact (broadcast, file, display). Trust XMLTV files with explicit offsets; suspect DST when off by exactly an hour.
  • Use gzip-compressed XMLTV URLs: 6× smaller, supported everywhere.
  • Refresh cadence: 12-hourly is the sweet spot. Anything more aggressive wastes bandwidth.
  • Multi-source XMLTV merge covers the long tail; configure priorities so primary wins on conflicts.
  • Best practice: primary XMLTV (provider) + Xtream API (now/next) + optional secondary XMLTV (regional fills).