The Chrome Webstore has decided to stop allowing inline installation for Chrome extensions. This has quite an impact on WebRTC applications since screensharing in Chrome currently requires an extension. Will the getDisplayMedia API come to the rescue?
Screensharing in Chrome
When screensharing was introduced in Chrome 33, it required implementation via an extension as a way to address the security concerns. This was better than the previous experience of putting this capability behind a flag which lead to sites asking their users to change that flag… that got those sites an official yikes.
Chrome did not change much since 2013. Requiring an extension adds friction to the process of sharing, but thanks to inline installation it was possible to minimize this friction:
- user clicks a button to start screensharing
- web application detects Chrome and determines the required extension is not installed
- web application triggers the inline installation API, gets a success callback
- Chrome desktop/window/tab sharing picker pops up, allow the user to choose what is going to be shared.
For a full implementation see the getScreenMedia example extension.
The sharing picker is the crucial element here. Is it safe enough to expose to the Web Platform without the safety net of the Webstore?
Tab sharing is a particular concern in this setup since it breaks up the cross-origin sandbox.
Screensharing in Firefox
Firefox took a different approach, having a whitelist of sites allowed to access the API. The process of getting onto that whitelist involved asking Mozilla for it and showing that your site had terms of service and a privacy policy. You could modify this whitelist through an extension as well. The need for this whitelist was removed in Firefox 52, allowing any secure origin to to use screensharing. It is not using the newer getDisplayMedia API, which we’ll discuss in a moment, but the implementation is nearly identical:
1 2 3 4 5 6 7 |
navigator.mediaDevices.getUserMedia({video: {mediaSource: 'screen'}}) .then(stream => { // we have a stream, attach it to a feedback video element videoElement.srcObject = stream; }, error => { console.log("Unable to acquire screen capture", error); }); |
This will be updated to support the spec eventually.
The getDisplayMedia API
The W3C has been working on standardizing the API for Screen Capture. It is relatively simple and promise-based like getUserMedia :
1 2 3 4 5 6 7 |
navigator.getDisplayMedia({ video: true }) .then(stream => { // we have a stream, attach it to a feedback video element videoElement.srcObject = stream; }, error => { console.log("Unable to acquire screen capture", error); }); |
Microsoft Edge just shipped screensharing using the this API earlier this year. The user experience here is quite well done, adding a yellow border to the display or window the user is sharing, ensuring the user is aware of what is shared at all times.
Times a changin’ with Chrome extensions
Speaking from experience, the appear.in screen sharing extension works as described above and it is quite successful with over a million installations. The vast majority of users comes via inline installation, so many that we haven’t bothered to update the extension screenshots in the Chrome Webstore since… probably 2014.
Now the Chrome Webstore is removing inline installations as explained in this blog post. This came as quite a surprise when I learned about it from an old Chrome issue about making screensharing more widely available. (Thank you Wilhelm Wanecek for pointing this out.)
If I understand the announcement correctly, this will open the Chrome WebStore in a different tab. This will make detecting when the user installed the extension from your web app quite a bit harder, essentially requiring polling or a timeout. The timeline in the post is as follows:
- new extensions don’t get inline installation anymore as of… June 12th. No notice period.
- inline installation will be disabled for existing extensions on September 12th. A three month notice period.
Gripes
There are a couple of things wrong about this. And I am not even talking about Google Hangouts/Meet completely avoiding the UX friction everyone else has to deal with through its use of a built-in extension. The Chrome folks are twisting arms here already.
I would have expected some outreach about this from the Chrome Webstore team (the email came around 24 hours after the blog post). The appear.in extension has more than a million users which makes it one of the largest screensharing extensions. Our users have an existing trust relationship with our website - which normally goes as far as allowing us to transmit their webcam and microphone. Using inline installation building on this established trust relationship with is arguably safer than installation from the Chrome Web Store. We have also had to ask the WebStore developer support to take down illegitimate copies of our extension installed by several hundred users more than once.
It would have also been nice the WebRTC folks at Google gave us a heads up.
Moving to getDisplayMedia
The path forward is for Chrome to ship the getDisplayMedia API. The “intent to ship” was published shortly after the news came. However, given the Chrome release cycle it will take a few weeks to land this. This is a non-trivial change in terms of security and user experience reviews which makes it doubtful this happens until the September 12th deadline. The branch point for Chrome 69 which will be the stable release on September 12th is less than a month away.
And the situation in Chrome is more complicated since it currently allows tab sharing as well as limiting which display surfaces the user can choose. Audio output sharing which is supported by Chrome is not specified by getDisplayMedia either.
How to prepare for the eventual changes in Chrome
The actual code changes to support getDisplayMedia are relatively simple. This API call typically goes into the exact same place where you would use Firefox’s getUserMedia call with a mediaSource argument. Feature detection is easily done by checking for the existence of getDisplayMedia and preferring it when available:
1 2 3 4 5 |
if ('getDisplayMedia' in window.navigator) { // use it. } else { // fall back to extension way } |
It is still somewhat unclear how to specify the capture frame rate. Using applyConstraints on the MediaStreamTrack returned works for getUserMedia and probably will continue to do so for getDisplayMedia :
1 2 3 4 5 |
navigator.getDisplayMedia({video: true}) .then(stream => { stream.getTracks()[0].applyConstraints({frameRate: 5}); return stream; }) |
See the specification issue for more details.
Unfortunately adapter.js can not really shim getDisplayMedia since the communication with the extension is done slightly different for each extension out there.
Onward and upward
I am looking forward to see whether the WebRTC folks at Google can influence the deadline of the inline extension removal or ship getDisplayMedia in time. Building for the web platform can be messy sometimes, but it does generally produce the best result in the end. We are looking forward to the end on this one and will be very happy to wave goodbye to our extensions.
{“author”: “Philipp Hancke“}
Alexander Patrakov says
Is any of this going to simplify the situation for Chinese users? appear.in screensharing does not work there currently because there is no way to install the required extension without connecting to an illegal VPN (Google web store is blocked).
Philipp Hancke says
getDisplayMedia will most likely make that easier, yes.