Guide · April 2026

How to Download m3u8 (HLS) Streams on Mac in 2026 — Including AES-128 Encrypted

By the shooff team · Last updated April 15, 2026 · 10 min read

HLS (HTTP Live Streaming) is how most of the web delivers video in 2026. Instead of one big MP4, the server hands the player a small text file called an m3u8 playlist, which points to hundreds of small .ts chunks the player assembles in real time. It's efficient, it's adaptive, and it's really annoying to download — because there's no single file.

This guide covers three practical paths, from easiest to most technical:

  1. Using shooff's built-in HLS capture (no CLI)
  2. Using yt-dlp on the command line
  3. Using ffmpeg directly when yt-dlp won't do

It also covers the thing that trips up most casual downloaders: AES-128 encrypted HLS streams where the decryption key requires session authentication.

First: what you're dealing with

An m3u8 file looks like this when you open it in a text editor:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-KEY:METHOD=AES-128,URI="https://cdn.example.com/key?token=xyz"
#EXTINF:5.0,
segment_001.ts
#EXTINF:5.0,
segment_002.ts
#EXTINF:5.0,
segment_003.ts
...
#EXT-X-ENDLIST

Key lines:

A proper HLS downloader handles all of this. The challenge is when the key fetch needs cookies.

Path 1: shooff (easiest, GUI)

shooff has a built-in webview that watches every HTTP request the page makes. When it spots an .m3u8 URL, it pops a download button into the UI. Because the playlist is fetched inside an authenticated browser session, the AES key URL is also fetchable.

  1. Open shooff. Click the Browser tab.
  2. Paste the video page URL into the address bar. Hit Enter.
  3. Play the video (or just let the page load — shooff catches m3u8 requests either way).
  4. A stream detected card appears with the title, resolution, and duration. Click + Add to Queue.
  5. shooff downloads segments in parallel (16 concurrent), fetches the AES key through the webview session, merges everything to MP4, and encrypts the result into your library.

No command line. No manual key handling. No session cookie export. For most people this is where the guide ends. Download shooff if you want this.

HLS downloads with AES-128, handled

shooff captures m3u8 streams automatically from its built-in browser and fetches encryption keys using the same authenticated session. Free tier available.

Try shooff free

Path 2: yt-dlp (CLI, free)

yt-dlp is the standard open-source tool. Install with Homebrew:

brew install yt-dlp ffmpeg

Unencrypted m3u8

If you already have the m3u8 URL:

yt-dlp "https://cdn.example.com/stream/master.m3u8"

yt-dlp will fetch the playlist, download all segments, and remux them to MP4. Default output filename is [title].mp4 in the current directory.

AES-128 encrypted m3u8 (with public key URL)

If the key URL doesn't need cookies:

yt-dlp -N 16 "https://cdn.example.com/stream/master.m3u8"

The -N 16 flag downloads 16 segments concurrently, which is much faster.

AES-128 with session-authenticated key

This is the hard case. You need to pass the same cookies the browser used to the tool:

  1. Install a cookie exporter extension in Firefox or Chrome (like "Get cookies.txt LOCALLY").
  2. Open the video page, play the stream briefly, then export cookies for that domain to a file.
  3. Run yt-dlp with the cookie file:
yt-dlp --cookies cookies.txt \
       --referer "https://originsite.example.com/" \
       -N 16 \
       "https://cdn.example.com/stream/master.m3u8"

The --referer flag is often needed because the CDN checks it before serving anything.

How to find the m3u8 URL

Open the video page in Safari or Chrome, open the Developer Tools → Network tab, play the video, and filter requests by m3u8. Right-click the first matching request and copy the URL. For master playlists, look for a list of bitrate-tagged child playlists and pick the highest.

Path 3: ffmpeg directly

ffmpeg can consume HLS natively. It's less friendly than yt-dlp but occasionally handles edge cases yt-dlp chokes on.

Simple case

ffmpeg -i "https://cdn.example.com/stream/master.m3u8" \
       -c copy \
       output.mp4

-c copy tells ffmpeg to remux without re-encoding, which is fast and lossless.

With cookies and referer

ffmpeg -headers "Referer: https://site.example.com/\r\nCookie: session=xyz\r\n" \
       -i "https://cdn.example.com/stream/master.m3u8" \
       -c copy \
       output.mp4

With a local m3u8 file (key URL rewritten)

Sometimes the m3u8 references URI="https://..." for the AES key but that URL needs cookies ffmpeg can't pass. Workaround: save the m3u8 locally, fetch the key separately, rewrite the URI to a local file path, then feed the local m3u8 to ffmpeg:

# 1. Fetch the original m3u8
curl --cookie "session=xyz" -o stream.m3u8 "https://cdn.example.com/master.m3u8"

# 2. Fetch the key with the same cookie
curl --cookie "session=xyz" -o key.bin "https://cdn.example.com/key?token=xyz"

# 3. Edit stream.m3u8, replace URI="https://..." with URI="./key.bin"

# 4. Feed local playlist to ffmpeg
ffmpeg -allowed_extensions ALL \
       -protocol_whitelist file,http,https,tcp,tls,crypto \
       -i stream.m3u8 \
       -c copy output.mp4

The -allowed_extensions ALL and -protocol_whitelist flags are required for ffmpeg to accept local playlist files that reference mixed protocols.

This is exactly what shooff does internally — but in a UI, with the session cookies taken from the authenticated webview automatically.

Common errors and fixes

"HTTP error 403 Forbidden"

Missing referer or cookie. Add --referer and --cookies in yt-dlp, or use shooff's built-in browser which handles both automatically.

"Unable to decrypt data"

The AES key didn't download correctly (wrong cookie, expired token). Refresh the page, re-export cookies, try again. Tokens often expire in minutes.

Output file is choppy or has gaps

Some segments failed to download. Increase concurrency carefully — too aggressive and the CDN rate-limits you. -N 8 is usually safe.

"Non monotonic DTS" warning but file plays

Harmless timestamp warning from ffmpeg on some HLS sources. The file is fine.

Master playlist but you only got 480p

yt-dlp selects by format by default. Use -f "bv*+ba/b" to force best video + best audio.

When to use which tool

Frequently asked

Is downloading HLS streams illegal?

Downloading streams you're authorized to access (content you purchased, content published under Creative Commons, content on sites that permit downloads) is generally legal. Downloading copyrighted content for redistribution, or bypassing DRM, is not. DRM-protected HLS (Widevine, FairPlay) is a separate thing — the tools in this guide don't touch it. This guide covers AES-128-encrypted streams, which are a transport-level obfuscation, not DRM.

What's the difference between AES-128 in HLS and DRM?

AES-128 in HLS is just transport encryption — it protects the stream in transit. The key is delivered to the player (with optional access control). DRM (Widevine, FairPlay, PlayReady) uses a hardware-backed key exchange and prevents the key from ever being accessible to user-space tools. You can't download Widevine-protected content with any of these tools.

How big will my downloaded file be?

Roughly the sum of all segment sizes. For 1080p, expect about 100-200 MB per hour. Lower bitrate streams will be smaller. Your downloader re-muxes segments into MP4 without re-encoding, so the file size matches the source.

Can I download HLS live streams?

While the stream is live, yt-dlp can record it in real time with --live-from-start. After the stream ends, the VOD replay (if the site offers one) is just a regular HLS download. For shooff, use the webview to open the live page and it'll start capturing automatically.

The stream works in Safari but not in a downloader. Why?

Usually the CDN is checking the User-Agent or Referer header and serving errors to anything that doesn't look like a browser. Pass --user-agent and --referer in yt-dlp, or use shooff's browser-based capture.

Can I convert m3u8 to MP4 after I already downloaded the .ts files?

Yes, if you have all the segments and (for encrypted streams) the AES key. Concatenate the decrypted .ts files: cat *.ts > combined.ts then remux: ffmpeg -i combined.ts -c copy output.mp4. Much easier to start with the m3u8 URL and let a tool do the whole pipeline.

Skip the CLI

shooff handles m3u8 — including AES-128 with session-authenticated keys — with a single click, inside a built-in browser. Free tier available.

Download shooff