Skip to content
Tools

Check your m3u8 against the spec — and against its own bytes.

Paste an HLS or CMAF playlist URL. This reads your master, follows the ladder, and opens the first few kilobytes of each initialization segment to check that the CODECS you declare is the codec the file actually contains. No key, no signup, no account.

Public http(s) playlists only. Nothing is stored except the playlist path and what the check concluded, for seven days — the query string is removed first, so a signed URL's token is never written down.

Try one:

How the check runs

Four steps, in order, inside a fifteen-second budget. The fourth is the one most free playlist linters stop short of.

  1. Step 1

    It reads the playlist you gave it

    One GET, from our servers, identified in your access log as TranscodelyHLSCheck. Master playlists and media playlists are both accepted, and a file that is neither is told so.

  2. Step 2

    It judges the text against RFC 8216

    Required tags, attribute grammar, EXT-X-VERSION against the features actually in use, target duration against the segment durations, byte ranges, discontinuity sequencing, key signalling, and the low-latency tags from the 8216bis draft.

  3. Step 3

    It follows the ladder

    Up to twelve variant and rendition playlists, so audio and subtitle groups are resolved against the EXT-X-MEDIA tags that are meant to define them, and each variant is read rather than assumed.

  4. Step 4

    It opens your initialization segments

    A ranged GET for the first 4 KiB of each EXT-X-MAP target, then a walk of the ISO base media boxes down to the sample entry — avc1, hvc1, av01, mp4a. The codec that walk finds is compared with the CODECS string the variant declares.

What this checker does not do

Read this before the rule catalog. A checker that overstates its reach is worse than no checker, because the next person stops believing the findings that are real.

It never plays your stream

Nothing here opens a media pipeline, requests a DRM licence or renders a frame. A clean report means the playlists are well-formed and the initialization segments say what the playlists claim. It does not mean every player will play it.

It does not decode

There is no decoder in it. So it can tell you the sample entry is hvc1 where you declared avc1, and it can tell you nothing about pixel format, colour volume, HDR metadata inside the bitstream, frame-level conformance, or whether the real bitrate matches the declared BANDWIDTH.

MPEG-TS variants are not codec-probed

The CODECS comparison needs fMP4. A transport-stream codec lives in the PMT of every segment, which is a different parser over a much larger fetch, so a TS ladder gets every other check and not that one.

DASH is not checked yet

An .mpd is not parsed as DASH at all — it is read as a playlist, found not to start with #EXTM3U, and reported as not being one. The MPD rules are not written yet, and nothing here pretends they are.

It checks encryption signalling, not encryption

It reads EXT-X-KEY and tells you the method is undefined, the URI is missing, or the KEYFORMAT names no registered system. It never fetches a key and never attempts a decrypt, so "signalled correctly" is not "the keys work".

It reads part of your stream, and says when it stopped

One check reads the submitted playlist, up to twelve further playlists and up to six initialization segments, inside fifteen seconds. When a budget runs out the check stops, reports budget-exhausted, and grades the result "Partly checked" rather than passing off a partial walk as a clean stream. A ladder with many audio and subtitle renditions reaches that cap easily — the second example above is one, deliberately.

It is not Apple’s Media Stream Validator

mediastreamvalidator runs on a Mac, downloads segments and decodes them. That is a larger and different tool. If you are submitting to the App Store, run it as well as this.

Rule catalog

Every rule the checker can report, with the severity it always carries. Error means a specification MUST is violated, or a conforming player will break on it. Warning means a SHOULD is violated, or the stream works but degrades. Note is an observation. Severity belongs to the rule rather than to where it fired, so the same finding is graded the same way every time.

54 rules: 32 errors, 15 warnings, 7 notes.

RuleSeverityWhat it means
bandwidth-missingError

Variant has no BANDWIDTH

BANDWIDTH is required on every EXT-X-STREAM-INF; without it a player cannot choose a variant.

RFC 8216 §4.3.4.2

budget-exhaustedNote

Check stopped at its fetch budget

Only part of the stream was examined. Re-run against a smaller ladder for full coverage.

byterange-invalidError

EXT-X-BYTERANGE is malformed or has no offset

Write n[@o]; the offset may be omitted only when the previous segment was a sub-range of the same resource.

RFC 8216 §4.3.2.2

codecs-malformedError

CODECS value is not a valid RFC 6381 string

Use the registered form, e.g. avc1.640028, hvc1.2.4.L120.B0 or hvc1.1.6.H150.90, mp4a.40.2, av01.0.05M.08.

RFC 6381 §3.3

codecs-mismatchError

Declared CODECS disagrees with the initialization segment

Emit the CODECS string derived from the actual sample entry; players reject or mis-select on a wrong one.

codecs-missingWarning

Variant has no CODECS

Declare CODECS so players can rule a variant out before fetching it. Apple requires it for App Store playback.

RFC 8216 §4.3.4.2

discontinuity-sequence-invalidError

EXT-X-DISCONTINUITY-SEQUENCE is not a non-negative integer

The value must be a decimal integer of zero or more.

RFC 8216 §4.3.3.3

discontinuity-sequence-missingWarning

Discontinuities without EXT-X-DISCONTINUITY-SEQUENCE

A playlist that has already rolled past a discontinuity must declare the sequence number so players stay aligned.

RFC 8216 §4.3.3.3

empty-playlistError

Playlist is empty

The URL returned no playlist tags. Check that it serves the .m3u8 and not an error page.

encryption-inconsistentWarning

Some variants are encrypted and others are not

Encrypt the whole ladder. A player that switches into a clear variant leaks the content.

endlist-missingWarning

VOD playlist has no EXT-X-ENDLIST

A finished playlist must end with EXT-X-ENDLIST, or players keep reloading it forever.

RFC 8216 §4.3.3.5

extinf-missingError

Segment URI has no EXTINF

Every media segment URI must be preceded by its own EXTINF tag.

RFC 8216 §4.3.2.1

findings-truncatedNote

Not every finding is listed

This playlist produced more findings than one result carries. Fix the listed ones and run the check again.

group-id-unresolvedError

Variant references a group with no renditions

Every AUDIO / SUBTITLES / CLOSED-CAPTIONS value must match the GROUP-ID of an EXT-X-MEDIA tag in the same playlist.

RFC 8216 §4.3.4.2.1

hold-back-too-smallError

HOLD-BACK is below three target durations

HOLD-BACK must be at least three times EXT-X-TARGETDURATION. Unlike PART-HOLD-BACK's three-times rule, this one is a MUST.

RFC 8216bis §4.4.3.8

iframe-uri-missingError

I-frame stream has no URI attribute

EXT-X-I-FRAME-STREAM-INF carries its playlist as a URI attribute, not on the following line.

RFC 8216 §4.3.4.3

independent-segments-missingNote

EXT-X-INDEPENDENT-SEGMENTS is not declared

Add it when every segment starts with a keyframe; players can then switch variants without buffering a whole segment.

init-not-fmp4Warning

Initialization segment is not an ISO base media file

An EXT-X-MAP target must be an fMP4 init segment starting with an ftyp box.

init-unparseableWarning

Initialization segment could not be parsed

The first bytes are not a readable ISO base media file. This check needs the moov box inside the first few kilobytes.

init-unreachableWarning

Initialization segment could not be read

The EXT-X-MAP URI did not return bytes. Check it resolves and that the origin allows range requests.

key-method-invalidError

EXT-X-KEY METHOD is not a defined value

METHOD must be NONE, AES-128, AES-256, AES-256-CTR, AES-256-GCM, SAMPLE-AES or SAMPLE-AES-CTR.

RFC 8216 §4.3.2.4 / RFC 8216bis §4.4.4.4

key-uri-missingError

Encryption key has no URI

URI is required on EXT-X-KEY unless METHOD is NONE.

RFC 8216 §4.3.2.4

keyformat-unknownNote

KEYFORMAT names no recognized DRM system

Widevine, PlayReady and FairPlay have registered identifiers. A custom KEYFORMAT only plays where it is understood.

ladder-bandwidth-duplicateWarning

Two variants declare the same BANDWIDTH

Give each rung a distinct BANDWIDTH; identical values make variant selection arbitrary.

ladder-unsortedNote

Variants are not ordered by BANDWIDTH

No specification requires an order. But a player that has not measured bandwidth yet may start on the first entry, so whichever variant you list first is your startup default — make sure it is the one you want.

map-missingError

fMP4 segments with no EXT-X-MAP

CMAF/fMP4 segments need an EXT-X-MAP naming the initialization segment.

RFC 8216 §4.3.2.5

map-unexpectedWarning

EXT-X-MAP declared for MPEG-TS segments

Transport-stream segments are self-initializing. Remove the EXT-X-MAP or switch the segments to fMP4.

media-playlist-unreachableWarning

Variant playlist could not be read

The variant playlist did not return readable text. Check the URI resolves and is publicly served.

media-sequence-invalidError

EXT-X-MEDIA-SEQUENCE is not a non-negative integer

The value must be a decimal integer of zero or more.

RFC 8216 §4.3.3.2

missing-extm3uError

Not an HLS playlist

The first line of every playlist must be exactly #EXTM3U.

RFC 8216 §4.3.1.1

mixed-segment-formatsError

One playlist mixes MPEG-TS and fMP4 segments

Keep one container per variant. A player that initialized for one cannot decode the other.

no-segmentsError

Media playlist has no segments

A media playlist with no EXTINF segment is unplayable.

no-variantsError

Master playlist declares no variants

Add at least one #EXT-X-STREAM-INF followed by its playlist URI.

part-hold-back-below-minimumError

PART-HOLD-BACK is below twice PART-TARGET

PART-HOLD-BACK must be at least twice PART-TARGET. This is the hard floor; three times is the recommendation.

RFC 8216bis §4.4.3.8

part-hold-back-too-smallWarning

PART-HOLD-BACK is below three part targets

PART-HOLD-BACK should be at least three times PART-TARGET; below that, players stall at the live edge on any jitter.

RFC 8216bis §4.4.3.8

part-inf-missingError

EXT-X-PART without EXT-X-PART-INF

A playlist containing partial segments must declare EXT-X-PART-INF:PART-TARGET.

RFC 8216bis §4.4.3.7

part-no-independentWarning

No partial segment is marked INDEPENDENT=YES

Mark the parts that start with a keyframe INDEPENDENT=YES; a player joining at the live edge needs one.

RFC 8216bis §4.4.4.9

part-target-exceededError

A partial segment is longer than PART-TARGET

No EXT-X-PART DURATION may exceed PART-TARGET. Raise PART-TARGET or shorten the part.

RFC 8216bis §4.4.3.7

playlist-kind-ambiguousError

Master and media tags in one playlist

A playlist is either a master (EXT-X-STREAM-INF) or a media playlist (EXTINF), never both. Split them.

RFC 8216 §4

playlist-type-invalidError

EXT-X-PLAYLIST-TYPE is not VOD or EVENT

The only valid values are VOD and EVENT.

RFC 8216 §4.3.3.5

playlist-unparsableError

Playlist could not be read to the end

A line exceeded the length this checker reads, so everything after it was skipped. Check the playlist is line-delimited text.

rendition-default-conflictError

Group has more than one DEFAULT=YES rendition

At most one rendition per group may be DEFAULT=YES.

RFC 8216 §4.3.4.1

rendition-default-not-autoselectWarning

DEFAULT=YES rendition sets AUTOSELECT=NO

A DEFAULT=YES rendition must also be AUTOSELECT=YES.

RFC 8216 §4.3.4.1

rendition-uri-missingError

Subtitle rendition has no URI

URI is required on EXT-X-MEDIA when TYPE is SUBTITLES.

RFC 8216 §4.3.4.1

resolution-missingNote

Variant has no RESOLUTION

Add RESOLUTION so a player can avoid fetching a variant larger than the viewport.

server-control-missingWarning

Partial segments without EXT-X-SERVER-CONTROL

Low-latency playback needs CAN-BLOCK-RELOAD=YES and PART-HOLD-BACK; without them players fall back to normal latency.

RFC 8216bis §4.4.3.8

target-duration-exceededError

A segment is longer than EXT-X-TARGETDURATION

From EXT-X-VERSION 6 the comparison is EXTINF rounded to the nearest integer; below it, TARGETDURATION is a hard maximum. Raise TARGETDURATION or shorten the segment.

RFC 8216 §4.3.3.1

target-duration-missingError

Media playlist has no EXT-X-TARGETDURATION

EXT-X-TARGETDURATION is required in every media playlist.

RFC 8216 §4.3.3.1

target-duration-oversizedNote

EXT-X-TARGETDURATION is far above the longest segment

Players derive their live edge and reload cadence from TARGETDURATION; an inflated value slows both.

variant-uri-missingError

Variant has no playlist URI

The line after an EXT-X-STREAM-INF must be the variant playlist's URI.

RFC 8216 §4.3.4.2

version-duplicateError

More than one EXT-X-VERSION tag

A playlist must contain at most one EXT-X-VERSION tag.

RFC 8216 §4.3.1.2

version-missingWarning

No EXT-X-VERSION, but version-2+ features are used

A playlist with no EXT-X-VERSION is version 1. Declare the version the features need.

RFC 8216 §7 / RFC 8216bis §8

version-too-lowError

EXT-X-VERSION is lower than the tags used require

Raise EXT-X-VERSION to the compatibility version of the newest feature in the playlist.

RFC 8216 §7 / RFC 8216bis §8

vod-mutableError

VOD playlist carries low-latency tags

EXT-X-PLAYLIST-TYPE:VOD promises the playlist never changes; partial segments and preload hints contradict it.

RFC 8216 §4.3.3.5

Why the CODECS check is the one that matters

A playlist can be perfectly well-formed and still fail to play. The usual cause is a CODECS attribute that disagrees with the file behind it: a packager set to H.264 in front of an HEVC encode, a hand-edited ladder, a profile string copied from another stream. Safari rules the variant out before it fetches a byte, and the player reports nothing more useful than a blank frame.

Reading the playlist text cannot find that. Reading the initialization segment can, and it costs one ranged request per variant. That is the check this page was built around. The rest of the rule catalog comes along with it.

Or have the ladder built correctly in the first place

Transcodely encodes into your own S3, GCS or R2 bucket and writes the HLS and DASH manifests with it. One API call in, a playable manifest out, at output paths you choose.

Open the quickstart