Skip to content

fix: make disableCookies reactive - #1349

Open
R-Delfino95 wants to merge 4 commits into
muxinc:mainfrom
R-Delfino95:fix/reactive-disable-cookies
Open

fix: make disableCookies reactive#1349
R-Delfino95 wants to merge 4 commits into
muxinc:mainfrom
R-Delfino95:fix/reactive-disable-cookies

Conversation

@R-Delfino95

@R-Delfino95 R-Delfino95 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Related to #1193 — that one made disableTracking reactive, disableCookies was left behind.

Description

disableCookies gates the persistent muxData cookie that players write through their built-in Mux Data. Today it only takes effect when a player initialises. Changing it afterwards doesn't work in either direction:

  • Turning it on deletes the cookie, but the running Mux Data monitor writes it straight back on its next beacon, about 10 seconds later.
  • Turning it off does nothing at all. The visitor's mux_viewer_id never comes back for the rest of the page.

That's a problem for consent flows. A consent manager answers after the page has rendered, so the value is almost always set after the player exists. The only way around it today is to not render the player until consent is known, which means it can't be server-rendered.

This PR makes the prop reactive, so a player can be rendered up front and told about consent later.

Why it wasn't reactive

Mux Data reads disableCookies once, when its monitor is created, and there's no setter for it afterwards. So the only way to apply a change is to create a new monitor. videojs/v10 reaches the same conclusion in its MuxData component, and this follows its shape — including its guards, so the two implementations stay comparable.

How it works

When disableCookies changes, Mux Data is re-attached: the old monitor is torn down and a new one is created with the new value. The <video> element and the hls.js instance are left alone, so playback isn't interrupted and anything attached to the element imperatively survives — chapters, caption tracks, listeners. That's the difference from the disable-tracking branch right above it, which reloads the media and loses all of that.

Turning cookies back on reuses the existing muxData cookie if it's still there, so a returning visitor keeps their identity.

Two behaviours worth being explicit about:

A change while a video is playing splits the Mux Data view in two — one viewend, one new viewstart. It's inherent to re-creating the monitor, and it's the same behaviour as videojs/v10. Applying the change before playback starts costs nothing, because Mux Data only closes a view that had already started, and that's the common case for a consent banner.

A player that initialises with cookies disabled no longer deletes an existing cookie. It used to, and that turned out to be harmful: a server-rendered page can't read consent, so it always renders the cookie-less state, and deleting there wiped a returning visitor's mux_viewer_id moments before the client granted consent. Mux Data then minted a new identity on every page load. The element can't tell "the visitor declined" from "consent isn't known yet" — same markup, opposite meaning — so it now leaves the cookie alone and never writes to it. Apps that need a stale cookie cleared should do it themselves, where the real consent state is known.

The React side

Making the element reactive isn't enough for server-rendered pages, because React never reconciles attributes during hydration — it warns that the mismatch "won't be patched up" and leaves the server's value in the DOM. So a server-rendered disable-cookies would stay there forever and the player would be stuck in the denied state.

mux-player-react and the @mux/mux-video/react wrapper now also apply disableCookies as a property after mount, which is what mux-player-react already does for playbackId, metadata and friends. That's the piece that makes a server-rendered, consent-gated player actually work.

@mux/mux-video-react is a separate implementation with no custom element, so it got its own equivalent: an effect that watches the prop.

Testing

13 unit tests in packages/mux-video/test/index.test.js (46 in the file now), covering both directions, no media reload, the cookie left alone at init, several changes in one tick collapsing into a single monitor, a change reverted in the same tick, and the cookie being cleared even when a monitor flushes its final beacon late or when several players are disabled at once.

Verified manually with real playback on <mux-video>, <mux-player>, @mux/mux-video/react and @mux/mux-video-react, plus a server-render-and-hydrate harness on React 18 and 19:

  • Revoking mid-playback deletes the cookie and it stays deleted well past the 10s heartbeat.
  • Granting mid-playback brings mux_viewer_id back within a second, reusing the existing one.
  • Zero emptied / loadstart / waiting events on any change, and the playhead never stops.
  • Chapters and the caption TextTrack object identity survive every change.
  • On a server-rendered page, a returning visitor keeps the same mux_viewer_id across reloads.
  • One viewstart and zero viewend per player when consent resolves before playback starts.

Note

Medium Risk
Touches Mux Data lifecycle, shared muxData cookies, and analytics view boundaries on mid-playback toggles; behavior is well-tested but affects privacy/consent and viewer identity.

Overview
Makes disableCookies react to updates after the player loads, so consent managers can flip cookie behavior without tearing down playback.

playback-core adds applyDisableCookies, reinitMuxData, and clearMuxDataCookies: when the value actually changes, Mux Data is torn down and re-monitored with the new setting (hls.js and the <video> stay put). Same-tick bursts coalesce to one re-init; enabling cookies at init no longer wipes an existing muxData cookie (SSR “unknown consent” case). Runtime disable clears cookies after monitor teardown flushes, including multi-player races.

<mux-video> swaps inline cookie deletion for applyDisableCookies on the disable-cookies attribute.

React: mux-player-react syncs disableCookies via useObjectPropEffect; @mux/mux-video/react re-applies the property after mount to fix hydration; mux-video-react watches the prop in a useEffect.

Adds a large disable-cookies unit test suite on <mux-video>.

Reviewed by Cursor Bugbot for commit ac0fc79. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

@R-Delfino95 is attempting to deploy a commit to the Mux Team on Vercel.

A member of the Team first needs to authorize it.

@snyk-io

snyk-io Bot commented Aug 4, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@R-Delfino95
R-Delfino95 marked this pull request as ready for review August 4, 2026 14:50
@R-Delfino95
R-Delfino95 requested a review from a team as a code owner August 4, 2026 14:50
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
elements-demo-nextjs Ready Ready Preview Aug 4, 2026 2:52pm

Request Review

@decepulis decepulis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems ok to me, but I think it should include mux-audio, too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants