Customizing Safari Playback with the Media Session API

This article explores how the Media Session API in the Safari web browser empowers web developers to customize media playback controls and metadata displayed directly on the iOS Lock Screen, Control Center, and macOS Now Playing widget. By utilizing this JavaScript API, websites can provide a native-like media experience, displaying rich track information such as titles, artists, and album artwork, while simultaneously mapping system-level hardware and software buttons to custom web-based playback actions.

Displaying Custom Metadata

When a user plays audio or video on a webpage in Safari, the operating system attempts to show basic information in the Lock Screen and Control Center. Without the Media Session API, Safari simply displays the webpage's title and URL.

To override this default behavior, websites use the MediaMetadata interface. By instantiating a new MediaMetadata object and assigning it to navigator.mediaSession.metadata, developers can explicitly define the title, artist, album name, and artwork for the currently playing media.

if ('mediaSession' in navigator) {
  navigator.mediaSession.metadata = new MediaMetadata({
    title: 'Episode 1: The Web Audio Revolution',
    artist: 'Tech Daily Podcast',
    album: 'Season 4',
    artwork: [
      { src: 'https://example.com/album-art-512x512.jpg', sizes: '512x512', type: 'image/jpeg' }
    ]
  });
}

Safari reads this object and immediately updates the Lock Screen and Control Center interfaces with the provided strings and fetches the specified image URL to display as the thumbnail artwork.

Customizing Playback Controls

Beyond displaying information, the Media Session API allows websites to dictate which playback buttons appear in the system UI and how they behave when tapped. This is achieved using the setActionHandler method on the navigator.mediaSession object.

Safari supports several action types, including:

  • play and pause
  • previoustrack and nexttrack
  • seekbackward and seekforward
  • seekto

When a developer registers an action handler, Safari enables the corresponding button on the Lock Screen and in the Control Center. If an action handler is not set (or is set to null), Safari will either hide that specific control or fall back to default browser behavior.

Adding Next and Previous Track Buttons

For a music or playlist website, enabling track skipping requires mapping the system buttons to the website's internal playlist logic:

navigator.mediaSession.setActionHandler('previoustrack', () => {
  // Custom logic to load and play the previous media file
  playPreviousSong();
});

navigator.mediaSession.setActionHandler('nexttrack', () => {
  // Custom logic to load and play the next media file
  playNextSong();
});

Enabling Skip Forward and Backward Buttons

Podcasts and audiobooks typically prefer 10- or 15-second skip buttons instead of track-skipping buttons. If seekbackward and seekforward handlers are defined instead of track handlers, Safari automatically swaps the UI icons on the Lock Screen to reflect time-skipping controls:

navigator.mediaSession.setActionHandler('seekbackward', (details) => {
  const skipTime = details.seekOffset || 15;
  audioElement.currentTime = Math.max(audioElement.currentTime - skipTime, 0);
});

navigator.mediaSession.setActionHandler('seekforward', (details) => {
  const skipTime = details.seekOffset || 15;
  audioElement.currentTime = Math.min(audioElement.currentTime + skipTime, audioElement.duration);
});

Synchronizing Timeline and Scrubbing

Safari displays a progress bar in the Lock Screen and Control Center that allows users to scrub through the media. To ensure this progress bar accurately reflects the web player's state—especially when playback speed changes or when custom skipping occurs—developers use the setPositionState method.

function updatePositionState() {
  if ('setPositionState' in navigator.mediaSession) {
    navigator.mediaSession.setPositionState({
      duration: audioElement.duration,
      playbackRate: audioElement.playbackRate,
      position: audioElement.currentTime
    });
  }
}

To allow the user to drag the playhead on the Lock Screen to a new time, the seekto action handler must also be implemented:

navigator.mediaSession.setActionHandler('seekto', (details) => {
  if (details.fastSeek && 'fastSeek' in audioElement) {
    audioElement.fastSeek(details.seekTime);
    return;
  }
  audioElement.currentTime = details.seekTime;
  updatePositionState();
});

Safari-Specific Requirements

For the Media Session API to successfully take control of the Lock Screen and Control Center in Safari, the webpage must actively be playing media through a standard HTML <audio> or <video> element, or via the Web Audio API. Safari requires a user gesture (like a tap or click) to initiate the playback first. Once the audio stream is active, Safari grants the webpage permission to populate the system-level media controls with the defined metadata and action handlers. Additionally, because the API integrates directly with Apple's native "Now Playing" architecture, any customizations made for the Lock Screen and Control Center automatically extend to connected devices, including AirPods, CarPlay, and the Apple Watch.