· deepdives  · 7 min read

Unlocking the Power of the Presentation API: A Comprehensive Guide for Modern Web Developers

Learn how to use the Presentation API to connect a web page to external displays and devices. This guide covers concepts, code examples for sender and receiver pages, browser support, integration patterns (including React), fallbacks, and real-world use cases to help you build richer second‑screen experiences.

Learn how to use the Presentation API to connect a web page to external displays and devices. This guide covers concepts, code examples for sender and receiver pages, browser support, integration patterns (including React), fallbacks, and real-world use cases to help you build richer second‑screen experiences.

What you’ll be able to do

Build web apps that push content to an external screen, create synchronized second‑screen experiences, and control remote views directly from the browser - without plugins. Read on and you’ll leave with working code, integration strategies, and practical fallbacks so your UX works across real environments.

Quick overview: What is the Presentation API?

The Presentation API provides a standard way for a web page (the “controller” or “sender”) to request that a URL be shown on an external display (the “receiver”). Once a presentation is started you get a two‑way messaging channel (a PresentationConnection) between the controller and receiver, enabling commands, state syncing, and real‑time messaging.

Why it matters: you can build second‑screen slideshows, remote controls for video playback, multi‑screen gaming UI, and kiosk experiences using standard web technologies.

Core pieces you’ll work with:

  • PresentationRequest - request a presentation to a target URL.
  • PresentationAvailability - know whether displays are available.
  • PresentationConnection - the live channel used to send and receive messages.
  • PresentationConnectionList - receiver-side list of incoming connections.

(See the W3C spec and MDN for the authoritative API documentation.)

References:

Basic end-to-end example

Below are minimal sender and receiver examples to get you started. These assume your pages are served over HTTPS (the API requires a secure context) and that user gestures will trigger the initial presentation request.

Sender page (controller)

// sender.js (controller)
const presentationUrls = ['https://example.com/receiver.html'];
const request = new PresentationRequest(presentationUrls);

// Monitor availability (optional)
request
  .getAvailability()
  .then(avail => {
    console.log('available?', avail.value);
    avail.onchange = () => console.log('availability changed', avail.value);
  })
  .catch(err => console.warn('getAvailability failed', err));

// Start presentation in response to a user gesture (e.g. button click)
document.querySelector('#startBtn').addEventListener('click', async () => {
  try {
    const connection = await request.start();
    console.log('Presentation started');

    connection.onmessage = e => console.log('Message from receiver:', e.data);
    connection.onclose = () => console.log('Presentation connection closed');

    // Send a message to the receiver
    connection.send(JSON.stringify({ action: 'play', timestamp: Date.now() }));
  } catch (err) {
    console.error('Presentation start failed', err);
  }
});

Receiver page (presentation)

// receiver.js (receiver page loaded in the external display)
if (navigator.presentation && navigator.presentation.receiver) {
  navigator.presentation.receiver.connectionList.then(connectionList => {
    // Existing connections
    connectionList.connections.forEach(connection =>
      attachConnectionHandlers(connection)
    );

    // New connections
    connectionList.onconnectionavailable = event => {
      attachConnectionHandlers(event.connection);
    };
  });
}

function attachConnectionHandlers(connection) {
  connection.onmessage = e => {
    const data = JSON.parse(e.data);
    console.log('Message from controller:', data);
    // React to commands (e.g., start playback)
  };

  connection.onclose = () => console.log('Connection closed');

  // Send message back
  connection.send(JSON.stringify({ status: 'ready' }));
}

Notes:

  • request.start() typically triggers a system UI (screen chooser) and must be called in response to a user gesture (click/tap).
  • Both sides can send messages via connection.send().

Events and lifecycle

Important events and lifecycle considerations:

  • getAvailability() returns a PresentationAvailability with a boolean .value and an onchange handler.
  • start() opens the platform chooser and resolves with a PresentationConnection when the receiver accepts.
  • connection.onmessage receives messages from the remote side.
  • connection.onclose and connection.terminate indicate the connection ending.
  • On the receiver, PresentationConnectionList exposes existing connections and an onconnectionavailable event for newly created ones.

Design for transient connections: displays can disconnect or be reclaimed by the user at any time. Implement reconnection strategies and graceful UI fallback.

Browser support and permissions

Important constraints:

  • Secure context: the API requires HTTPS (except localhost in development).
  • User gesture: starting a presentation must happen from a user gesture; otherwise start() will be rejected or trigger no chooser.
  • Support is limited: not all browsers implement the Presentation API uniformly. Check current browser support before relying on it in production.

Use these resources to check compatibility:

If a target device uses proprietary protocols (e.g., Chromecast), you may prefer the platform’s SDK (e.g., Cast SDK) for richer device features.

Practical integration patterns and best practices

  1. Progressive enhancement

Detect availability and fall back gracefully. Offer a QR code, manual URL, or in-app pairing as a fallback when no presentation targets are available.

  1. Keep messages small and semantic

Use compact JSON messages for commands and avoid sending large binary payloads over connection.send(). For media streaming, use native

  1. Synchronization strategy

If you need tight sync (e.g., for a video second screen):

  • Let the receiver host the media playback and the controller send control commands (play/pause/seek) with timestamps.
  • Consider periodic heartbeat/status messages to verify sync and correct drift.
  1. Security and validation

Treat incoming messages as untrusted. Validate payloads, check action types, and enforce rate limits if necessary.

  1. UI/UX considerations

Provide clear feedback when the connection is pending, connected, or disconnected. Offer a reconnection button and inform users when a remote screen is no longer reachable.

Integration example: React + hooks

A thin React hook that abstracts request and connection state (conceptual):

import { useEffect, useState } from 'react';

export function usePresentation(urls) {
  const [connection, setConnection] = useState(null);
  const [available, setAvailable] = useState(false);

  useEffect(() => {
    let req;
    if (!('PresentationRequest' in window)) return;

    req = new PresentationRequest(urls);

    req
      .getAvailability()
      .then(av => {
        setAvailable(av.value);
        av.onchange = () => setAvailable(av.value);
      })
      .catch(() => {});

    return () => {
      if (connection) connection.close();
      // no explicit cleanup for req
    };
  }, [urls]);

  const start = async () => {
    if (!('PresentationRequest' in window)) throw new Error('Not supported');
    const req = new PresentationRequest(urls);
    const conn = await req.start();
    setConnection(conn);
    return conn;
  };

  return { connection, available, start };
}

This hook simplifies wiring UI buttons to start the presentation and respond to connection events in your React components.

Advanced scenarios and alternatives

  • Media-heavy apps: Pair with WebRTC. Use the Presentation API for control and signaling, and WebRTC for high‑bandwidth media streaming between devices.
  • Cast/Chromecast: For maximum compatibility with Chromecast devices, prefer the Cast SDK. Presentation API can work with devices that expose the platform-level presentation chooser but may not match Cast SDK features.
  • Native-like kiosks: Use the API in a locked-down web kiosk to show remote admin UI on an attached screen.

Real-world use cases

  • Remote control for presentations and slides - controller shows presenter notes while the receiver shows the slides.
  • Second‑screen video controls - mobile device controls playback on a TV while the TV handles the heavy media decode.
  • Interactive retail displays - customers interact on their phone; the store screen updates accordingly.
  • Collaborative apps and games - one device drives shared state while others are spectators or controllers.

Debugging, testing, and troubleshooting

  • Test on real devices and displays. Emulators won’t exercise system-level choosers.
  • Use browser logs and connection.onmessage to validate messages.
  • When starting fails, confirm:
    • The page runs over HTTPS (or localhost).
    • start() is invoked from a user gesture.
    • The target URL is reachable and served correctly.
  • In Chrome, check flags and origin policies if behavior differs across versions.

Fallback strategies

Because support varies, plan fallbacks:

  • Offer a direct URL with a QR code so the remote device can open the receiver page manually.
  • Use WebSockets or a central server to coordinate pages when native device pairing isn’t available.
  • Provide a limited local-only experience if remote display is not available.

A short checklist before shipping

  • Ensure HTTPS for all pages.
  • Validate user gesture behavior for start().
  • Build graceful fallbacks (QR/manual URL, server signaling, or Cast SDK when appropriate).
  • Implement message validation and graceful reconnection.
  • Test on target hardware (TVs, Chromecast, smart displays) and common browsers.

Conclusion

The Presentation API unlocks native, browser-based second‑screen and remote control experiences without plugins or heavy SDKs. Use it when you want simple URL-based presentations, command/control messaging, and tight integration with standard web pages - and always layer in progressive enhancement and fallbacks for real users and devices.

Strong final point: the API gives you the plumbing to connect screens - but great second‑screen experiences are won with resilient UX, clear fallbacks, and careful synchronization.

Back to Blog

Related Posts

View All Posts »