JavaScript MediaSession Table

PieceWhat it doesField note
navigator.mediaSession.metadataLock-screen infotitle/artist/album/artwork - the OS media widget reads it
setActionHandler('play', fn)Hardware keysHeadphone buttons, lock-screen controls, car displays
playbackStateplaying / pausedSync the OS widget with your actual player state
setActionHandler(ยญ'seekbackward')Seek controlsOffset math is YOURS - the OS just signals
setPositionStateProgress on lock screenduration/position/playbackRate - keeps the scrubber honest
artwork sizes192/384/512pxMultiple sizes for different surfaces - icon-like contract
Requires media playingThe gateHandlers apply while audio/video actually plays
PWA pairingThe installed-app feelMedia apps without it feel broken on mobile - table stakes
Reference: the MDN MediaSession reference. MediaSession is how a web player reaches the OS: metadata (title, artist, artwork) paints the lock-screen widget and media flyout, and setActionHandler wires hardware keys - headphone buttons, lock-screen controls, car displays - to your player functions. The contract cuts both ways: the OS shows what you declare, so setPositionState keeps the scrubber honest and playbackState syncs reality. Bottom line: for any web audio/video app, MediaSession is table stakes on mobile - without it the widget says 'untitled' and the headphone buttons do nothing. Related tools: Web Audio table (the audio itself), video table (the element MediaSession describes), and service worker table (background playback persistence).

MediaSession is how a web player reaches the operating system: metadata (title, artist, album, artwork) paints the lock-screen widget and media flyout, and setActionHandler wires hardware keys - headphone buttons, lock-screen controls, car displays - to your player functions.

Bottom line: the contract cuts both ways. The OS shows what you declare - so setPositionState keeps the scrubber honest and playbackState syncs reality - and for any web audio or video app on mobile, MediaSession is table stakes: without it the widget says 'untitled' and the headphone buttons do nothing.

The honest part: MediaSession describes media; it does not play it. The handlers are signals ('the user pressed play'), and YOUR code performs the action - the seek buttons deliver intent, the offset math stays yours.

How to use

  1. Declare the widget: navigator.mediaSession.metadata = new MediaMetadata({ title, artist, album, artwork: [{ src, sizes: '512x512' }] }) - the lock screen paints it.
  2. Wire the keys: for (const action of ['play', 'pause', 'previoustrack', 'nexttrack']) navigator.mediaSession.setActionHandler(action, () => player.toggle()) - hardware buttons now work.
  3. Keep the scrubber honest: navigator.mediaSession.setPositionState({ duration, position, playbackRate }) on play, seek and rate changes - the OS progress reflects truth.

Frequently asked questions

What does MediaSession actually give a web player?

OS integration that native apps get by default. Without it, a web player plays audio but the lock screen shows a generic 'untitled' entry, headphone play/pause buttons do nothing, and car displays have nothing to show. With it: title, artist, album and artwork paint the system media widget; the hardware transport keys (play, pause, previous, next, seek) call YOUR handlers; and the playback position renders in system UI. The reach is broad - Android's media notification, iOS lock screen, desktop OS media flyouts, Bluetooth AVRCP displays in cars - one API feeding every surface the OS owns. It is the difference between 'audio playing in a tab' and 'an app playing media'.

Why is setPositionState called the honesty API?

Because the OS renders what you tell it, not what is true. The lock-screen scrubber shows position state YOU report: if you set it once at play and never update, the progress bar freezes while audio advances; if your playback rate changes and you do not report it, the estimate drifts. The contract: update on play, pause, seek and rate changes - duration, current position and rate - and the system scrubber tracks your player accurately. The same honesty applies to playbackState ('playing' while paused is a widget lie users can feel). MediaSession is declarative plumbing; stale state is the bug class it introduces.

What is the relationship between MediaSession and actually playing audio?

Description versus engine. MediaSession has no playback power: it needs real media ACTIVELY PLAYING (an audio/video element or Web Audio graph going to output) for handlers and metadata to apply - the browser will not keep a silent page's media session alive. The typical architecture on mobile is the pair: a media element (or Web Audio routed through one) does the playing, possibly kept alive in background by a service worker's mediated session, and MediaSession describes and controls it. The actions arrive as signals ('next pressed') - the seek offset math, playlist advancement and state updates are all your code, which is why the handlers are functions rather than configuration.

When is MediaSession integration worth the effort?

Immediately, for any real media experience on mobile. The cost is an afternoon: metadata once per track, four to six action handlers, position state updates on three events. The payoff is the difference between feeling broken and feeling installed on phones - headphone controls that work and a lock screen that shows the episode. The prioritization: metadata plus play/pause/prev/next first (the universal surface), seek handlers second, then position state for scrubber honesty. Desktop matters less (media flyouts are less prominent) but shares the same code. The only players that should skip it are ones with no mobile audience - and those usually skip mobile anyway.

Related tools