Presentation API
Limited availability
This feature is not Baseline because it does not work in some of the most widely-used browsers.
Secure context: This feature is available only insecure contexts (HTTPS), in some or allsupporting browsers.
Experimental:This is anexperimental technology
Check theBrowser compatibility table carefully before using this in production.
The Presentation API lets auser agent (such as a Web browser) effectively display web content through large presentation devices such as projectors and network-connected televisions. Supported types of multimedia devices include both displays which are wired using HDMI, DVI, or the like, or wireless, usingDLNA,Chromecast,AirPlay, orMiracast.

In general, a web page uses the Presentation Controller API to specify the web content to be rendered on presentation device and initiate the presentation session. With Presentation Receiver API, the presenting web content obtains the session status. With providing both the controller page and the receiver one with a messaged-based channel, a Web developer can implement the interaction between these two pages.
Depending on the connection mechanism provided by the presentation device, any controller- and receiver page can be rendered by the same user agent, or by separated user agents.
- For 1-UA mode devices, both pages are loaded by the same user agent. However, rendering result of the receiver page will be sent to the presentation device via supported remote rendering protocol.
- For 2-UAs mode device, the receiver page is loaded directly on the presentation device. Controlling user agent communicates with presentation device via supported presentation control protocol, to control the presentation session and to transmit the message between two pages.
In this article
Interfaces
PresentationIn controlling browsing context, the
Presentationinterface provides a mechanism to override the browser default behavior of launching presentation to external screen. In receiving browsing context,Presentationinterface provides the access to the available presentation connections.PresentationRequestInitiates or reconnects to a presentation made by a controlling browsing context.
PresentationAvailabilityAPresentationAvailability object is associated with available presentation displays and represents thepresentation display availability for a presentation request.
PresentationConnectionAvailableEventThe
PresentationConnectionAvailableEventis fired on aPresentationRequestwhen a connection associated with the object is created.PresentationConnectionEach presentation connection is represented by aPresentationConnection object.
PresentationConnectionCloseEventA
PresentationConnectionCloseEventis fired when a presentation connection enters aclosedstate.PresentationReceiverThePresentationReceiver allows a receiving browsing context to access the controlling browsing contexts and communicate with them.
PresentationConnectionListPresentationConnectionListrepresents the collection of non-terminated presentation connections. It is also a monitor for the event of new available presentation connection.
Example
Example codes below highlight the usage of main features of the Presentation API:controller.html implements the controller andpresentation.html implements the presentation. Both pages are served from the domainhttps://example.org (https://example.org/controller.html andhttps://example.org/presentation.html). These examples assume that the controlling page is managing one presentation at a time. Please refer to the comments in the code examples for further details.
Monitor availability of presentation displays
Incontroller.html:
<button>Present</button>.hidden { display: none;}// The Present button is visible if at least one presentation display is availableconst presentBtn = document.getElementById("presentBtn");// It is also possible to use relative presentation URL e.g. "presentation.html"const presUrls = [ "https://example.com/presentation.html", "https://example.net/alternate.html",];// Show or hide present button depending on display availabilityconst handleAvailabilityChange = (available) => { if (available) { presentBtn.classList.remove("hidden"); } else { presentBtn.classList.add("hidden"); }};// Promise is resolved as soon as the presentation display availability is known.const request = new PresentationRequest(presUrls);request .getAvailability() .then((availability) => { // availability.value may be kept up-to-date by the controlling UA as long // as the availability object is alive. It is advised for the web developers // to discard the object as soon as it's not needed. handleAvailabilityChange(availability.value); availability.onchange = () => { handleAvailabilityChange(availability.value); }; }) .catch(() => { // Availability monitoring is not supported by the platform, so discovery of // presentation displays will happen only after request.start() is called. // Pretend the devices are available for simplicity; or, one could implement // a third state for the button. handleAvailabilityChange(true); });Starting a new presentation
Incontroller.html:
presentBtn.onclick = () => { // Start new presentation. request .start() // The connection to the presentation will be passed to setConnection on success. .then(setConnection); // Otherwise, the user canceled the selection dialog or no screens were found.};Reconnect to a presentation
In thecontroller.html file:
<button>Reconnect</button>const reconnect = () => { const presId = localStorage.getItem("presId"); // presId is mandatory when reconnecting to a presentation. if (presId) { request .reconnect(presId) // The new connection to the presentation will be passed to // setConnection on success. .then(setConnection); // No connection found for presUrl and presId, or an error occurred. }};// On navigation of the controller, reconnect automatically.reconnect();// Or allow manual reconnection.reconnectBtn.onclick = reconnect;Presentation initiation by the controlling UA
In thecontroller.html file:
navigator.presentation.defaultRequest = new PresentationRequest(presUrls);navigator.presentation.defaultRequest.onconnectionavailable = (evt) => { setConnection(evt.connection);};Settingpresentation.defaultRequest allows the page to specify thePresentationRequest to use when the controlling UA initiates a presentation.
Monitor connection's state and exchange data
Incontroller.html:
<button>Disconnect</button><button>Stop</button><button>Reconnect</button>let connection;// The Disconnect and Stop buttons are visible if there is a connected presentationconst stopBtn = document.querySelector("#stopBtn");const reconnectBtn = document.querySelector("#reconnectBtn");const disconnectBtn = document.querySelector("#disconnectBtn");stopBtn.onclick = () => { connection?.terminate();};disconnectBtn.onclick = () => { connection?.close();};function setConnection(newConnection) { // Disconnect from existing presentation, if not attempting to reconnect if ( connection && connection !== newConnection && connection.state !== "closed" ) { connection.onclose = undefined; connection.close(); } // Set the new connection and save the presentation ID connection = newConnection; localStorage.setItem("presId", connection.id); function showConnectedUI() { // Allow the user to disconnect from or terminate the presentation stopBtn.classList.remove("hidden"); disconnectBtn.classList.remove("hidden"); reconnectBtn.classList.add("hidden"); } function showDisconnectedUI() { disconnectBtn.classList.add("hidden"); stopBtn.classList.add("hidden"); if (localStorage.getItem("presId")) { // If there is a presId in localStorage, allow the user to reconnect reconnectBtn.classList.remove("hidden"); } else { reconnectBtn.classList.add("hidden"); } } // Monitor the connection state connection.onconnect = () => { showConnectedUI(); // Register message handler connection.onmessage = (message) => { console.log(`Received message: ${message.data}`); }; // Send initial message to presentation page connection.send("Say hello"); }; connection.onclose = () => { connection = null; showDisconnectedUI(); }; connection.onterminate = () => { localStorage.removeItem("presId"); connection = null; showDisconnectedUI(); };}Monitor available connection(s) and say hello
Inpresentation.html:
const addConnection = (connection) => { connection.onmessage = (message) => { if (message.data === "Say hello") connection.send("hello"); };};navigator.presentation.receiver.connectionList.then((list) => { list.connections.forEach((connection) => { addConnection(connection); }); list.onconnectionavailable = (evt) => { addConnection(evt.connection); };});Passing locale information with a message
In thecontroller.html file:
connection.send('{"string": "你好,世界!", "lang": "zh-CN"}');connection.send('{"string": "こんにちは、世界!", "lang": "ja"}');connection.send('{"string": "안녕하세요, 세계!", "lang": "ko"}');connection.send('{"string": "Hello, world!", "lang": "en-US"}');In thepresentation.html file:
connection.onmessage = (message) => { const messageObj = JSON.parse(message.data); const spanElt = document.createElement("SPAN"); spanElt.lang = messageObj.lang; spanElt.textContent = messageObj.string; document.body.appendChild(spanElt);};Specifications
| Specification |
|---|
| Presentation API> # interface-presentation> |
Browser compatibility
See also
Presentation API polyfill contains a JavaScript polyfill of thePresentation API specification under standardization within theSecond Screen Working Group at W3C. The polyfill is mostly intended for exploring how the Presentation API may be implemented on top of different presentation mechanisms.