· 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.

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:
- W3C Presentation API spec: https://www.w3.org/TR/presentation-api/
- MDN: Presentation API: https://developer.mozilla.org/en-US/docs/Web/API/Presentation_API
- Browser support overview: https://caniuse.com/presentation-api
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:
- MDN: https://developer.mozilla.org/en-US/docs/Web/API/Presentation_API
- Can I use: https://caniuse.com/presentation-api
- Chrome docs / experimental flags: https://developer.chrome.com/docs/web-platform/presentation-api/
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
- 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.
- 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
- 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.
- Security and validation
Treat incoming messages as untrusted. Validate payloads, check action types, and enforce rate limits if necessary.
- 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.



