HLS Works on Your Phone but Fails on the TV: Casting Diagnosis Guide

Diagnose HLS that plays locally but fails after casting by separating sender, receiver, CORS, Range requests, codecs, authorization, and live-window evidence.

An HLS stream can play perfectly on a phone or laptop, connect to a television, and then stop after a few seconds. That result does not prove the television has weak Wi-Fi, and it does not prove the playlist is universally compatible. In many casting systems, the remote receiver loads the media itself. The sender's successful requests and decoder are no longer the whole playback path.

This guide separates sender control, receiver networking, media support, authorization, and output behavior. Use only streams you own or are authorized to inspect. Remove signed query strings, cookies, device identifiers, IP addresses, and account data before sharing logs.

Verification method — September 21, 2026: We ran a Node.js 24.12.0 loopback HTTP fixture with two synthetic request origins. The server authorized https://sender.example.test but omitted Access-Control-Allow-Origin for https://receiver.example.test. Both origins received the playlist bytes and a 206 response to a four-byte Range request, but only the sender received a matching CORS header. This verifies the fixture's HTTP header difference and Range response; Node's fetch does not enforce browser CORS. We did not use a Chromecast, Apple TV, AirPlay receiver, smart TV, DRM system, or real media decoder. Device-specific guidance below is documentation-based. The fixture is stored at scripts/test-cast-hls-origin-headers.cjs.

Identify where playback moved

“Casting” can mean several different architectures. A browser tab may be mirrored, a system may hand a media URL to a receiver, or an application may communicate with its own receiver app. The television can therefore be showing pixels produced by the sender, or it can be running a separate media player that makes its own HLS requests.

ObservationWhat it suggestsWhat it does not prove
Mirrored tab continues when the TV takes overSender may still render the pageThe receiver can load the HLS URL independently
Phone becomes a remote controlReceiver likely owns media playbackReceiver received the same cookies or authorization context
TV shows title/artwork, then exitsControl message and some metadata arrivedPlaylist, segments, codec, or license succeeded
Local playback keeps working after TV failsSender path is healthy for that sessionReceiver network, headers, decoder, or live position is healthy
All other videos cast successfullyBasic discovery and output workThis HLS presentation is compatible

Record whether this is screen mirroring, browser Remote Playback, Google Cast, AirPlay, a smart-TV app, or HDMI. Do not merge results from these paths under one label. MDN marks the web Remote Playback API as limited availability, so support cannot be inferred from a Cast or AirPlay button appearing elsewhere in the operating system.

Capture sender and receiver evidence separately

The sender's browser developer tools normally show requests made by the sender page. They may not show the receiver's requests. If the sender stops downloading segments immediately after handoff, that can be normal; if no receiver-side trace exists, the Network panel cannot tell you which receiver request failed.

For an application you control, collect receiver logs or CDN request records around the handoff time. Correlate them using a privacy-safe session or request identifier rather than publishing the media URL. Record:

  1. Exact handoff time and time zone.
  2. Sender device, browser/app version, network, and local playback status.
  3. Receiver model, firmware/app or receiver version, network, and output display.
  4. Final playlist URL after redirects and the first receiver-side request.
  5. Status, content type, Range header, cache result, and final URL for the first failure.
  6. Selected variant, codecs, audio group, subtitle track, and current media position.
  7. Whether control status changed to playing, buffering, idle, or error.

If you cannot access receiver logs, server or CDN logs are often the first reliable place to confirm whether the television requested the playlist. Our developer-tools request guide remains useful for the sender side, but it is not a receiver trace.

Check CORS for the receiver path

Google's Web Receiver documentation says streaming protocols use asynchronous requests guarded by CORS and that the content server controls where media may be included. Google also states that adaptive media and track streams need appropriate CORS headers. Authorizing only the website that contains the Cast button can therefore be insufficient when a receiver application has a different origin.

Our fixture demonstrates the diagnostic trap: both synthetic origins got HTTP 200 for the manifest, yet the receiver origin received no matching Access-Control-Allow-Origin. A server log containing 200 does not establish that receiver JavaScript could read the response. The actual receiver platform decides whether and how CORS is enforced; our Node test did not simulate that enforcement.

Inspect CORS across the entire chain:

  • Multivariant and media playlists.
  • Initialization and media segments.
  • Alternate audio and subtitle playlists and segments.
  • Encryption keys and permitted license endpoints.
  • Redirect destinations, not only the original hostname.
  • Responses to Range requests and preflight requests when applicable.

Do not install an open public proxy or weaken production access controls as the permanent fix. Configure the intended origins, credentials, methods, and request headers on infrastructure you control, then retest with the actual receiver.

Compare authorization without copying secrets

Local playback may depend on a browser cookie, an Authorization header, a referrer, or a short-lived signed URL. A remote receiver will not automatically inherit every part of the sender's session. A master playlist might load while its child playlists, keys, or segments use expired or incomplete authorization.

Follow the first receiver request through the entire playlist chain. Compare which query parameters and headers are present, how long each signature remains valid, and whether redirects strip or change authorization. If the stream works briefly and then stops, compare token expiry with the failure time, but do not assume timing alone proves expiry.

Never paste a working signed URL into a public bug report or hard-code it into a page. Provide sanitized paths, status codes, expiry intervals, and request identifiers to the service owner instead.

Verify Range behavior and response types

Receivers can use byte-range requests even when local playback happened to use full-object requests. Our fixture returned 206 Partial Content, Content-Range, and Accept-Ranges for a controlled segment request. It did not validate a media container or device behavior.

For real authorized media, check that a Range request receives a coherent response: status 206 when appropriate, a valid Content-Range, correct total length, the requested bytes, and a media content type. Watch for CDNs or authorization layers that ignore, strip, or reject Range. A response with 200 may be legitimate for some resource and client paths, so interpret it alongside the request and platform documentation rather than applying a universal rule.

Also confirm that .m3u8 endpoints return HLS text beginning with #EXTM3U, not an HTML login or CDN challenge. Our broader HLS playback troubleshooting guide explains how a successful status can still carry the wrong body.

Match codecs to the receiver, not the phone

The phone and television may have different hardware decoders, supported profiles, channel layouts, maximum resolution, frame rate, HDR capabilities, and container limitations. A stream that the sender decodes is not automatically compatible with the receiver.

Google publishes device-specific Cast media support and provides CastReceiverContext.canDisplayType() for compatible receiver applications. Its current documentation lists different codec and resolution limits by device and warns, for example, that HEVC is not supported in Transport Stream containers. Check the current target-device table rather than relying on the word “4K” or on a successful phone test.

Inspect the multivariant playlist's CODECS, RESOLUTION, FRAME-RATE, audio channels, and actual media. Provide a conservative H.264/AAC rendition if that matches the supported product requirements, but do not merely relabel incompatible media. For alternate audio problems, use the HLS audio-track diagnosis.

Treat live-window handoff as a timing problem

A receiver joining a live stream starts from its own playlist snapshot and chosen live position. If the playlist is cached too long, segments are announced before availability, or the receiver begins near a disappearing edge, local playback can remain healthy while the receiver fails.

Save consecutive receiver-side playlist responses. Compare #EXT-X-MEDIA-SEQUENCE, newest segment, cache headers, request time, and the first segment the receiver selected. Check whether that segment was still available at the handoff time. Do not infer receiver recovery from the phone's continuing playback; the two clients may be at different positions.

Use our stale-playlist versus missing-segment guide to separate an unchanged live snapshot from a newly advertised object returning 404. For Low-Latency HLS, verify that the chosen receiver path supports the actual features used by the presentation rather than assuming all HLS modes are equivalent.

Test the output and control state

If requests and decoding appear healthy, check whether playback is merely inaudible, routed to another output, paused, or hidden behind an HDMI/HDCP/display-mode problem. Record receiver volume, mute state, audio route, display capabilities, and whether video time advances.

A sender button reporting “connected” proves a control session, not successful media. Likewise, artwork on the television can come from metadata before any segment is decoded. Log receiver media status transitions and the first meaningful error instead of treating connection state as playback state.

DRM adds another boundary. A protected stream needs a receiver-supported DRM path, license exchange, credentials, and output protection. A generic receiver cannot invent a license or bypass protection. Test only within the official authorized application flow.

A reproducible device matrix

Test each supported combination without changing several variables at once:

DimensionMinimum useful record
SenderDevice, OS, browser/app version, local playback result
ReceiverExact model, firmware/receiver version, wired or wireless network
PresentationVOD/live/low-latency, selected variant, codecs, DRM status
Handoff pointBefore play, during steady play, after seek, after network recovery
ResultTime to first frame, first failed receiver request, final media state
ControlKnown-good authorized stream on the same sender and receiver

Test at least one low and one high rendition, alternate audio and subtitles, seeking, pause/resume, and a live handoff after the window has advanced. A desktop browser resized to TV dimensions is not a receiver test. Label unsupported or unavailable hardware as untested.

Write the report around the first receiver failure

An actionable report says: “Local playback continued. At 18:42:11, receiver model X requested the media playlist and received 200, then its first segment request returned 403 after a redirect. The sanitized request ID is Y.” This identifies an owner and next check.

Include the casting architecture, sender and receiver versions, first receiver-side URL type and status, CORS and Range headers, selected codec/rendition, authorization lifetime, live sequence, and media status transition. Exclude raw credentials and private URLs.

Primary references

When local HLS works and television playback fails, start by proving who requested the media. Then follow receiver CORS, authorization, Range behavior, codec support, live timing, decoding, and output in order. A successful phone request cannot clear a separate receiver path.