getHlsStreamingUrl
function getHlsStreamingUrl(asset, opts?): string;Defined in: packages/asset-client/dist/index.d.ts:507
Build an HLS streaming URL for a VIDEO asset (Phase 5). Returns the master.m3u8 entry point — HLS-aware players (Video.js’s @videojs/http-streaming, hls.js, native iOS Safari) follow it to fetch the variant playlist + segments at the appropriate bitrate for the connection.
⚠️ A master.m3u8 is NOT a video file. Assigning it to <video src>
works only where the engine has native HLS; everywhere else it needs
an MSE player. And the classic feature test is now WRONG: Chrome 147
(April 2026) added native HLS, so canPlayType("application/vnd.apple.mpegurl")
answers “maybe” there and routes Chrome to the native branch, where it
opened a measured 17 s hero at 426x240 for ~8 s. Branch on the ENGINE:
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
asset |
Pick<AssetDTO, "sha"> & VisibilityHint |
opts? |
Omit<TransformOptions, "format"> |
Returns
Section titled “Returns”string
Example
Section titled “Example”function prefersNativeHls(video: HTMLVideoElement): boolean { if (video.canPlayType("application/vnd.apple.mpegurl") === "") return false; // Apple's engine, or an engine with no MSE to fall back on (iOS < 17.1). return "ManagedMediaSource" in globalThis || !("MediaSource" in globalThis);}
const src = getHlsStreamingUrl(asset);if (prefersNativeHls(video)) { video.src = src;} else { const hls = new Hls({ capLevelToPlayerSize: false, abrEwmaDefaultEstimate: 5_000_000 }); hls.loadSource(src); hls.attachMedia(video);}⚠️ Do NOT pass startLevel: -1 with testBandwidth: true. That pair is
documented by hls.js as “forces the player to download a fragment from the
lowest level to establish a bandwidth estimate” — on a clip short enough to
be one segment, the probe IS the whole video, and it plays at the bottom
rung from first frame to last. (This doc-comment recommended exactly that
until 2026-08-18; a 5.042 s 4K asset was measured being delivered at
426x240 because of it.) Leave startLevel unset: hls.js then opens on the
FIRST level in the manifest, and the server puts the right one there —
a mid rung for long video, the top rung for a clip under 18 s, which is the
same rung native HLS opens on per RFC 8216 §6.3.4. The ladder decides; the
player should not second-guess it.
capLevelToPlayerSize is worth disabling explicitly: @videojs/core
defaults it to true, which caps quality to the player’s rendered pixel box,
so a small inline player is pinned to 240p/360p on any connection.
On first request the server returns 202 Accepted while a background job transcodes the ladder (typically 1-3 min for a 90 s source); subsequent requests get 302 to the cached master.m3u8. Keep the progressive MP4 as a fallback source for that window.
The ladder’s ceiling is the source the job probes: built at ingest it
reads the RAW upload and a 4K master yields 1440p/2160p rungs; rebuilt
on demand after the raw is unavailable it reads the -v.mp4, which is
capped at 1920 wide. getAssetUrl(sha, "video") is always <= 1080p.