M3U vs M3U8: What Actually Differs — M3UPlaylist
Guide

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:

One character becomes several
CharacterUTF-8 bytesShown 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:

Two documents, one extension
SignalChannel listHLS playlist
First line#EXTM3U, often with x-tvg-url#EXTM3U, plain
After thatRepeated #EXTINF with names#EXT-X- tags
Duration means-1 or 0 for liveLength of the following segment, in seconds
URLs point atStreams, often already .m3u8Segment files, or variant playlists
Changes over timeOnly when someone edits itRewritten 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

  1. 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-INF and the Master Playlist.
  2. HLS authoring specification for Apple devices — the playlist and multivariant-playlist requirements that use the newer name for the same structure.
  3. M3U — the source for the encoding convention itself, in the absence of a formal specification.