M3U vs M3U8: what actually differs
The honest answer is “one character encoding”. The useful answer is longer,
because the .m3u8 extension is used for two unrelated things and
people conflate them constantly.
The original difference is encoding
Both files are playlists in the same format. The .m3u8 extension
marks the file as UTF-8, which is why it ends in “8”; the older
.m3u had no guaranteed encoding and in practice was often written
in a Windows code page. For a playlist of plain ASCII channel names the two
files are byte-for-byte identical, which is why renaming one to the other
usually appears to work.
What the 8 actually marks
The extension is a statement about bytes, not about content. UTF-8 is mandatory
for .m3u8 by convention, and the system code page is usually
assumed for .m3u — though in practice many .m3u files
are UTF-8 as well, which is why the distinction has blurred. There is no formal
specification to settle the question: the extension is the only signal, and it
carries no enforcement.
What breaks when the encoding is wrong
The difference shows up the moment a name contains an accented character, a currency symbol or an emoji. Saved as UTF-8 and read as a legacy code page, those characters become mojibake — the “é” and “’” that litter imported playlists. The reverse also happens: a file written in a Windows code page and read as UTF-8 produces replacement characters where the accents should be.
Saving as .m3u8 removes the ambiguity, because UTF-8 is now the
assumption rather than a guess. It does not repair a file that was already
mangled before you received it — the wrong bytes are wrong whatever the
extension says. Repairing that means re-encoding from the code page the file was
actually written in, or asking the provider for a fresh export.
What mojibake actually looks like
Mojibake is not random damage; it is UTF-8 bytes read as a single-byte code page, usually Windows-1252. An entry written correctly as:
#EXTINF:-1 group-title="Música",Café TV
https://example.com/cafe.m3u8
arrives on screen looking like this:
#EXTINF:-1 group-title="Música",Café TV
https://example.com/cafe.m3u8
Every accented character has become two characters, because UTF-8 spends two bytes on it and the reader gave each byte its own letter. The pattern is consistent enough to recognise on sight:
| Character | UTF-8 bytes | Shown when read as Windows-1252 |
|---|---|---|
é | C3 A9 | é |
ú | C3 BA | ú |
£ | C2 A3 | £ |
€ | E2 82 AC | € |
🎵 | F0 9F 8E B5 | 🎵 |
The reverse direction is worse, and this is the part worth understanding before
you try to repair anything. A file written in Windows-1252 stores
é as the single byte E9. Read as UTF-8, that byte is
not a valid sequence start, so it becomes a replacement character:
Caf� TV
That is why re-saving the file as UTF-8 cannot fix it. The bytes are already
wrong: the reader replaced them and the original values are gone from the text.
Repairing it means re-encoding from the code page the file was written in, which
needs a tool that still has the bytes — not a text editor that has already
displayed them. Where the file came from a provider, asking for a fresh export is
the shorter route; where you have the original, a conversion such as
iconv -f WINDOWS-1252 -t UTF-8 playlist.m3u does the job without the
display step in between.
The other meaning: HLS playlists
The same extension is used by HTTP Live Streaming, where an
.m3u8 file is not a channel list at all. This is the conflation
that causes most confusion: two different documents, one extension, and a parser
that has to decide which it is holding.
Media playlists
An HLS media playlist lists short transport-stream or fMP4 segments, each with a
duration in #EXTINF:9.009, form, plus tags such as
#EXT-X-TARGETDURATION so a player knows how long to wait between
refreshes. It describes a few seconds of one stream, and it is rewritten
continuously while that stream is live.
Multivariant (master) playlists
A multivariant playlist lists variant streams at different bitrates with
#EXT-X-STREAM-INF, letting a player choose one by resolution or
bandwidth. RFC 8216 calls it a Master Playlist; Apple's current authoring
specification calls it multivariant, and the tags are the same either way.
This is why a channel URL often ends in .m3u8 inside a playlist
that is itself a channel list. One file describes many streams; the other
describes the segments of one. They share an extension and a lineage, not a
purpose.
Telling which one you are looking at
Ignore the filename and read the first few lines. The tags decide:
| Signal | Channel list | HLS playlist |
|---|---|---|
| First line | #EXTM3U, often with x-tvg-url | #EXTM3U, plain |
| After that | Repeated #EXTINF with names | #EXT-X- tags |
| Duration means | -1 or 0 for live | Length of the following segment, in seconds |
| URLs point at | Streams, often already .m3u8 | Segment files, or variant playlists |
| Changes over time | Only when someone edits it | Rewritten as the live window moves |
The practical rule: treat #EXT-X- as the signal, not the extension.
A channel list saved as .m3u8 is normal and harmless. An HLS
playlist renamed to .m3u will not become a channel list, and a
validator will say so, because it finds no
channel entries to report.
A manifest you can open
A real media playlist looks nothing like a channel list. This is a complete, valid one — three segments of a single stream, ten seconds of video in total:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.009,
segment-00001.ts
#EXTINF:9.009,
segment-00002.ts
#EXTINF:9.009,
segment-00003.ts
#EXT-X-ENDLIST
Three details give it away. Every #EXTINF here carries a duration
with a fractional part and an empty name — the comma closes an attribute list
that has no attributes. The lines beneath the tags are relative filenames, not
addresses, because a segment sits next to the playlist that lists it. And the
durations describe the segment below them, not a channel above.
You can download this file and open it in the validator. It reports no channels, flags every segment line as text it cannot classify, and scores the file 10/100 with three errors. That is the honest outcome rather than a bug: the validator measures a file against channel-list rules, and a manifest fails them. The score says “this is not a channel list”, not “this stream is broken” — which is exactly the distinction the whole page is about.
The two documents also age differently. A channel list changes when someone
edits it. A media playlist is rewritten continuously while the stream is live,
and its #EXT-X-MEDIA-SEQUENCE moves forward as old segments leave
the window. The sample above ends with #EXT-X-ENDLIST, which marks a
finished stream; a live manifest omits that tag, because the list is never
finished.
Converting between them
Converting a channel list between the two extensions is a no-op on content and a fix for encoding. The converter writes UTF-8 either way, so exporting to a clean M3U is enough to normalise a file whose accents are wrong — provided the file was read correctly in the first place. If the mojibake arrived before the file reached you, re-exporting preserves the damage rather than repairing it.
Converting an HLS playlist into a channel list is not a conversion, and no tool can do it: the segments belong to one stream, and turning them into channels would mean inventing addresses. The format guide covers the channel-list structure in full.
Delivery is the other half of the same confusion: a manifest played from a URL is subject to rules a saved file is not, which the playlist URL guide covers. And if nothing opens either document, the opening guide starts from the file association rather than the file.
Sources
-
RFC 8216, HTTP Live Streaming
— §4.3.2.1 for
#EXTINF, §4.3.3.1 for#EXT-X-TARGETDURATION, §4.3.4.2 for#EXT-X-STREAM-INFand the Master Playlist. - HLS authoring specification for Apple devices — the playlist and multivariant-playlist requirements that use the newer name for the same structure.
- M3U — the source for the encoding convention itself, in the absence of a formal specification.