UniPlayer Документация
EN
Документация / Спецификации / The Complete M3U Playlist Format Reference for IPTV (Attributes, EPG & Catch-up)
Спецификации · Formats

The Complete M3U Playlist Format Reference for IPTV (Attributes, EPG & Catch-up)

A complete technical reference to the IPTV M3U format: every EXTINF and header attribute, EPG/XMLTV linking, and catch-up archive URLs (Flussonic, Xtream Codes) with examples.

9 мин чтения / Обновлено май 2026 г.
EN Эта статья ещё не переведена — показана английская версия.
Кратко

An IPTV M3U playlist is a plain-text file starting with #EXTM3U, where each channel is a #EXTINF line carrying double-quoted attributes (tvg-id, tvg-name, tvg-logo, group-title, catchup…) followed by its stream URL. tvg-id links the channel to its XMLTV EPG, and catch-up archive URLs are built from the live URL using Flussonic (UTC seconds) or Xtream Codes (local time, minutes) grammars. None of these attributes are a formal standard — they are de-facto conventions popularised by players like Kodi, TiviMate and OTT Navigator, and UniPlayer reads them the same way VLC opens a file you give it.

Overview

The M3U playlist is the lingua franca of IPTV: a plain-text file that tells a player which channels exist, where to stream them from, how to label and group them, where to find the program guide, and how to reach the catch-up archive. Yet there is no single formal specification — the format grew organically, and its attributes are conventions popularised by a handful of influential players. This reference brings those conventions together in one place, with exact attribute meanings, the rules players actually follow, the archive-URL formats used by Flussonic and Xtream Codes, and working examples you can copy.

UniPlayer reads M3U/M3U8 (and Xtream, Stalker, XML and VPortal) sources and normalises them into one interface, so understanding the format below helps whether you’re authoring a playlist or debugging why a channel won’t show its guide.

M3U vs Extended M3U vs HLS .m3u8 — clearing up the confusion

Three different things share the .m3u/.m3u8 extension, and conflating them is the single most common source of confusion.

  • Plain M3U is just a list of URLs, one per line. No metadata.
  • Extended M3U (#EXTM3U) adds a header line and #EXTINF lines carrying metadata (name, logo, group, EPG id). This is what “an IPTV playlist” means in practice.
  • An HLS manifest also uses the .m3u8 extension, but it describes the segments of one video stream using #EXT-X- tags such as #EXT-X-VERSION, #EXT-X-TARGETDURATION, #EXT-X-MEDIA-SEQUENCE and #EXT-X-STREAM-INF.

The practical rule: #EXT-X- tags belong to HLS and are not IPTV playlist attributes. An IPTV playlist points at HLS streams (the channel URL is often an .m3u8), but the playlist itself uses #EXTINF + tvg-* conventions, not #EXT-X- tags. The only difference between .m3u and .m3u8 as a playlist is encoding: .m3u8 signals UTF‑8, which you want for non‑Latin channel names.

Anatomy of a playlist entry

An extended playlist begins with a header and then repeats a two-or-more-line block per channel:

#EXTM3U url-tvg="https://example.com/epg.xml.gz"
#EXTINF:-1 tvg-id="bbcone.uk" tvg-name="BBC One HD" tvg-logo="https://example.com/logos/bbc1.png" group-title="UK",BBC One HD
https://provider.example/live/bbc1/index.m3u8

Reading the #EXTINF line:

  • #EXTINF: — the directive that introduces a media entry.
  • -1 — the duration in seconds. For live channels this is -1 (unknown/infinite); 0 is also tolerated by most players. For VOD it can be a real duration.
  • tvg-id="…" tvg-name="…" … — space-separated, double-quoted attributes (covered in detail below).
  • ,BBC One HD — everything after the first comma is the display name the user sees. It can differ from tvg-name.
  • The next line is the stream URL (HTTP/HTTPS for HLS/TS, or udp:// / rtp:// for multicast on a LAN).

Optional auxiliary lines (#EXTGRP, #EXTVLCOPT, #KODIPROP, #EXTHTTP) may sit between the #EXTINF line and the URL; they attach to that channel.

Header attributes (#EXTM3U line)

These set defaults for the whole playlist. A per-channel attribute of the same name overrides the header value.

AttributeMeaning
url-tvg / x-tvg-urlURL of the XMLTV EPG file for the whole playlist (.xml, .xml.gz, or .xz). The two names are synonyms; url-tvg is common in TiviMate/OTT Navigator, x-tvg-url in Kodi. Multiple comma-separated URLs are accepted by some players.
url-logoBase URL prepended to relative tvg-logo values.
tvg-shiftDefault EPG time shift in hours for all channels (see EPG section).
catchup, catchup-source, catchup-days, catchup-correctionDefault catch-up settings for all channels (see Catch-up section).
refresh / refresh_atHow often the player should reload the playlist (interval, or an explicit ISO‑8601 datetime).
m3uautoload1 tells some players to auto-load the EPG when the playlist opens.
max-connNumber of simultaneous connections the provider permits (lets the player open picture-in-picture etc.).
billed-till / billed-msgAccount expiry timestamp / a free-text message a provider can surface to the user.
#EXTM3U x-tvg-url="https://example.com/epg.xml.gz" tvg-shift="0" catchup="shift" catchup-days="7" catchup-correction="0"

Channel attributes (#EXTINF line)

None of these are part of a formal standard — they are widely-honoured conventions. The tvg- prefix historically stands for “TV Guide”.

Core, near-universal

AttributeMeaning
tvg-idThe channel’s unique identifier, used to map the channel to its EPG. Must equal the id of a <channel> in the XMLTV guide. This is the attribute that makes the program guide appear.
tvg-nameThe channel’s name as written in the EPG. Used as a fallback for EPG matching and sometimes for display.
tvg-logoURL of the channel logo/icon. If relative, .png is appended when missing and url-logo is prepended.
group-titleCategory/folder the channel belongs to (e.g. Sports, News). Some players accept several groups separated by ;.
tvg-chno / ch-numberThe channel number to display (LCN). Players can otherwise number channels by playlist order.

Common extras

AttributeMeaning
tvg-shiftPer-channel EPG time shift in hours (e.g. -3.5). Values outside roughly -12..14 are interpreted as seconds by some players.
radioradio="true" marks an audio-only stream.
tvg-language / tvg-countryBroadcast language / country of origin (used for filtering, not playback).
tvg-rec1 marks that the channel has an archive. Redundant if a catchup attribute is present; values >1 are read by some players as an alias for catchup-days.
parent-code / adultMarks a channel as restricted/adult so it can be hidden behind a PIN.
audio-track / video-trackAuto-select the Nth audio/video track (some players also accept a resolution like 1920x1080).
type="playlist" (a.k.a. content-type="playlist")The “channel” URL is an include — the player merges another playlist inline. Useful for composing large lists.
catchup, catchup-source, catchup-days, catchup-correction, timeshiftPer-channel catch-up overrides (see below).

A note on portability: a tag one player ignores, another may rely on. Players generally skip attributes they don’t recognise, so unknown attributes are safe to leave in place.

Auxiliary lines: headers, user-agent, referrer and DRM

When a stream needs custom HTTP headers or DRM, that information rides alongside the channel. There are several mechanisms, and they overlap.

Inline on the URL (pipe syntax). Append header fields after a |:

https://provider.example/live/cnn.m3u8|user-agent=MyPlayer/1.0&referer=https://provider.example/

Kodi supports a fixed set of standard header names this way (and user-agent, referer, cookie as special fields); non-standard headers must be prefixed with !.

#EXTVLCOPT: (VLC-style options). One key=value per line. The two that matter most are recognised by many players and folded into the request as HTTP headers:

#EXTVLCOPT:http-user-agent=Mozilla/5.0
#EXTVLCOPT:http-referrer=https://provider.example/

#EXTHTTP: (JSON headers). A JSON object of arbitrary headers, honoured by OTT Navigator and others:

#EXTHTTP:{"User-Agent":"Mozilla/5.0","X-Token":"abc123"}

#KODIPROP: (player properties, including DRM). One key=value per line. Beyond inputstream selection, this is how ClearKey/Widevine/PlayReady DRM is passed:

#KODIPROP:inputstream.adaptive.license_type=clearkey
#KODIPROP:inputstream.adaptive.license_key=https://license.example/getkey

#EXTGRP:Category Name is simply an alternative to group-title.

Linking the EPG (XMLTV)

Channels carry identity; the EPG (Electronic Program Guide) carries what’s on. UniPlayer and other players join the two using XMLTV, an XML guide format.

How matching actually works

Point the playlist at the guide with url-tvg/x-tvg-url, then players resolve each channel against the XMLTV in a fixed order (this is the logic Kodi’s IPTV Simple Client uses, and others mirror it):

  1. By id — does the channel’s tvg-id equal a <channel id="…"> in the XMLTV? If yes, done.
  2. By name — does <display-name> (as-is, or with spaces swapped for underscores) equal the channel’s tvg-name?
  3. By on-screen name — does <display-name> equal the channel’s display name (the text after the comma)?

The first match wins. The lesson: set tvg-id and make it exactly equal the XMLTV id. Name-based fallback is fragile (case, “HD” suffixes, spacing).

XMLTV structure

<tv>
  <channel id="bbcone.uk">
    <display-name>BBC One HD</display-name>
    <icon src="https://example.com/logos/bbc1.png"/>
  </channel>

  <programme start="20260612200000 +0000" stop="20260612210000 +0000" channel="bbcone.uk">
    <title>The Nine O'Clock News</title>
    <desc>The day's headlines.</desc>
    <category>News</category>
    <episode-num system="onscreen">S12E04</episode-num>
  </programme>
</tv>
  • <programme> start/stop use YYYYMMDDHHMMSS ±HHMM. Always include the timezone offset.
  • The guide can be served plain, gzip (.gz) or xz (.xz)-compressed.
  • An optional, non-standard catchup-id attribute on <programme> carries a provider-specific identifier some catch-up URLs require (see {catchup-id} below).

Time shift

If your guide’s timestamps don’t line up with the channel — usually a feed relayed from another timezone — correct it with tvg-shift (hours) at channel or header level, rather than editing the guide.

Catch-up / archive: the complete picture

Catch-up (a.k.a. archive, replay, time-shift) lets you watch a program that already aired. The provider records a rolling window — say 7 days — and the player constructs a timestamped URL for the program you pick from the EPG. The size of that window is declared with catchup-days.

The catch-up attributes

AttributeMeaning
catchup (alias catchup-type)The mode — how to build the archive URL. Values below.
catchup-sourceThe URL template (with placeholders). In default mode it’s the full URL; in append mode it’s only the query appended to the live URL. Omit it to let modes like flussonic/xc auto-generate the URL.
catchup-daysHow many days back the archive reaches.
catchup-correctionA time correction in hours applied to URL generation — the fix for archives that play the wrong time due to a timezone mismatch.
catchup-timeLegacy: archive window in seconds (prefer catchup-days).
timeshiftLegacy SIPTV tag combining shift + days into one field.

The catch-up modes

Mode (and aliases)What the player does
defaultTreat catchup-source as the complete catch-up URL (with placeholders). If no source is given, fall back to append.
appendAppend catchup-source (a query string with placeholders) to the live channel URL.
shift (SIPTV)Auto-append ?utc={utc}&lutc={lutc} to the live URL — or &utc=…&lutc=… if the URL already contains ?. No source needed.
flussonic (aliases fs, flussonic-hls, flussonic-ts)Auto-build a Flussonic archive URL from the live URL.
xtream (alias xc)Auto-build an Xtream Codes time-shift URL from the live URL.
vodTreat the entry as video-on-demand keyed by {catchup-id}; the program plays as a bounded video.

Format specifiers (placeholders)

These tokens, substituted at playback time, are the heart of catch-up. The list below follows Kodi’s implementation, which other players track closely.

TokenResolves to
{utc} / ${start}Program start time, Unix UTC seconds.
{lutc} / ${now} / ${timestamp}Current time, Unix UTC seconds.
{utcend} / ${end}Start time plus {duration}.
{Y} {m} {d} {H} {M} {S}Year / month / day / hour / minute / second of the start time.
{duration}Program duration (plus any start/end buffer).
{duration:X}Duration divided by X seconds — e.g. {duration:60} for minutes. X must be a positive integer.
{offset:X}(now − start) divided by X seconds — e.g. {offset:1} for seconds-ago.
{catchup-id}A program-specific id pulled from the XMLTV <programme catchup-id="…">.

Two refinements worth knowing:

  • Timestamp tokens accept a format argument. {utc:Ymd-H-M} or ${end:YmdHM} formats the time inline using Y m d H M S letters — handy when a provider wants 2026-06-12 rather than a Unix number.
  • OTT Navigator adds named date parts: ${start-year}, ${start-mon}, ${start-day}, ${start-hour}, ${start-min}, ${start-sec} — the same values, spelled out.

Worked templates:

?utc={utc}&lutc={lutc}
&t={Y}-{m}-{d}-{H}-{M}-{S}
?start={utc:YmdHM}&end=${end:YmdHM}
?offset={offset:1}

Archive URL construction by server type

The auto-generating modes exist because two server platforms dominate, each with a fixed URL grammar.

Flussonic. All timestamps are Unix UTC seconds. From a live URL like http://host/STREAM/index.m3u8, the archive forms are:

PurposeURL shape
Catch-up (HLS)http://host/STREAM/archive-{start}-{duration}.m3u8
Catch-up (MPEG‑TS)http://host/STREAM/archive-{start}-{duration}.ts
Catch-up (DASH)http://host/STREAM/archive-{start}-{duration}.mpd
Download a segmenthttp://host/STREAM/archive-{start}-{duration}.mp4
Event (open-ended)http://host/STREAM/archive-{start}-now.m3u8
Absolute time-shifthttp://host/STREAM/timeshift_abs-{start}.ts (or .m3u8)
Relative time-shifthttp://host/STREAM/timeshift_rel-{seconds_ago}.ts
Wide rewind windowhttp://host/STREAM/rewind-{seconds_ago}.m3u8

So a flussonic catchup-source for a one-hour show looks like …/archive-{utc}-{duration}.m3u8. (Add ?ignore_gaps=true if a feed had outages and you want playback to skip the holes.)

Xtream Codes. Two equivalent forms. Duration is in minutes, and the start time is the provider’s local time in YYYY-MM-DD:HH-MM — the usual cause of “catch-up plays an hour off”.

http://host:port/timeshift/USER/PASS/{duration_min}/{YYYY-MM-DD:HH-MM}/{stream_id}.ts
http://host:port/timeshift/USER/PASS/{duration_min}/{YYYY-MM-DD:HH-MM}/{stream_id}.m3u8

or the script form:

http://host:port/streaming/timeshift.php?username=USER&password=PASS&stream={stream_id}&start={YYYY-MM-DD:HH-MM}&duration={duration_min}

The xc mode builds these automatically from a live Xtream URL (…/live/USER/PASS/STREAM.ts); for .m3u8 channels it produces the .m3u8 variant. Because the format expects local time while EPGs are UTC, catchup-correction is frequently needed.

How this relates to the Xtream Codes API

An Xtream Codes login isn’t an M3U file — it’s an API. But it exports one. Requesting …/get.php?username=USER&password=PASS&type=m3u_plus&output=ts (or output=m3u8/hls) returns a standard extended M3U with the tvg-* attributes above, while …/player_api.php?…&action=get_live_streams returns the same catalogue as JSON. Channels whose API entry has tv_archive=1 support catch-up via the time-shift URLs in the previous section. In other words: Xtream is a delivery mechanism that resolves down to the same M3U conventions — which is why a player can treat “an M3U URL” and “an Xtream login” as two front doors to one model.

A complete, annotated example

#EXTM3U x-tvg-url="https://example.com/epg.xml.gz" catchup-days="7"

# A plain HLS channel with full EPG mapping and a logo
#EXTINF:-1 tvg-id="bbcone.uk" tvg-name="BBC One HD" tvg-logo="https://example.com/logos/bbc1.png" group-title="UK",BBC One HD
https://provider.example/live/bbc1/index.m3u8

# A channel needing a custom User-Agent and Referrer
#EXTINF:-1 tvg-id="cnn.us" tvg-logo="cnn" group-title="News",CNN
#EXTVLCOPT:http-user-agent=Mozilla/5.0
#EXTVLCOPT:http-referrer=https://provider.example/
https://provider.example/live/cnn/index.m3u8

# Flussonic catch-up, URL auto-generated by the player
#EXTINF:-1 tvg-id="sport1.de" group-title="Sports" catchup="flussonic" catchup-days="5",Sport 1
http://host:8080/sport1/index.m3u8

# Xtream Codes catch-up, URL auto-generated from the live link
#EXTINF:-1 tvg-id="film.fr" group-title="Movies" catchup="xc" catchup-days="3",Cinema FR
http://host:8080/live/user/pass/40521.ts

# Append-mode catch-up with an explicit query template and timezone correction
#EXTINF:-1 tvg-id="news.it" group-title="News" catchup="append" catchup-source="&cutv={Y}-{m}-{d}T{H}:{M}:{S}" catchup-correction="-1.0",News IT
http://host:8080/live/newsit/index.m3u8

# A DRM-protected (ClearKey) channel
#EXTINF:-1 tvg-id="drm.demo" group-title="Premium",DRM Demo
#KODIPROP:inputstream.adaptive.license_type=clearkey
#KODIPROP:inputstream.adaptive.license_key=https://license.example/getkey
https://provider.example/drm/demo/manifest.mpd

Validation checklist & common mistakes

  • First line must be #EXTM3U — and it must be the very first line, with no blank line above it.
  • Use UTF‑8 (.m3u8) for non‑Latin names; avoid a stray byte-order mark (BOM) before #EXTM3U.
  • No blank lines inside a channel block — the URL must immediately follow the #EXTINF/auxiliary lines.
  • Quote attribute values consistently and keep them on the single #EXTINF line.
  • tvg-id must equal the XMLTV id exactly — this is the number-one reason a guide is missing.
  • Don’t confuse tvg-name with the display name — the display name is after the comma; tvg-name is for EPG matching.
  • Watch the catch-up clock — Flussonic is UTC, Xtream is local time and minutes; reach for catchup-correction before blaming the stream.
  • De-duplicate — some providers rotate stream URLs; matching by name on refresh can create duplicates if names or links changed.

A note on player compatibility

Because there is no governing standard, support varies. Kodi’s IPTV Simple Client, TiviMate, OTT Navigator and Perfect Player each implement an overlapping but not identical attribute set, and they use aliases for the same idea (catchup vs catchup-type, flussonic vs fs, xtream vs xc, url-tvg vs x-tvg-url). When you author a playlist, target the attributes your players actually read, prefer tvg-id + a clean XMLTV for the guide, and test in the real app before shipping a large list.

UniPlayer treats your playlist as exactly that — yours. It plays M3U/M3U8 and Xtream (plus Stalker, XML and VPortal) sources you have the rights to, the same way VLC opens a file you give it. It doesn’t provide, host or sell channels.

Частые вопросы
(01)What is the difference between an M3U playlist and an HLS .m3u8 stream?

Both use the .m3u/.m3u8 text format, but they describe different things. An IPTV playlist lists channels using #EXTINF lines with attributes like tvg-id and group-title. An HLS manifest lists the video segments of a single stream using #EXT-X- tags. The #EXT-X- tags belong to HLS and are not IPTV playlist attributes.

(02)How does an M3U channel get matched to its EPG?

Players match by tvg-id first: the channel's tvg-id must equal the id of a <channel> element in the XMLTV guide. If there's no tvg-id match, most players fall back to matching tvg-name (or the on-screen channel name) against the XMLTV <display-name>.

(03)How are catch-up (archive) URLs built?

A channel declares a catch-up mode with the catchup attribute, and the player builds a timestamped URL from the live stream URL. Common modes are default/append (template in catchup-source), shift (appends ?utc={utc}&lutc={lutc}), flussonic (archive-{start}-{duration}), and xtream codes (/timeshift/user/pass/duration/start/id). Timestamps come from the EPG.

(04)Why does my catch-up play the wrong time?

Almost always a timezone mismatch. Flussonic uses Unix UTC timestamps, while Xtream Codes expects the provider's local time. Use a catchup-correction value (in hours) to shift the time used for URL generation back into alignment.

(05)Are M3U attributes an official standard?

No. The base M3U/EXTM3U format is a de facto convention, and the IPTV attributes (tvg-*, catchup-*, group-title) are conventions popularised by players like Kodi's IPTV Simple Client, TiviMate and OTT Navigator. Support overlaps but is not identical across players, so test in your target app.