PWA + WebM + iOS/Mac Safari : I need your feedback


When we implemented Ogg Opus/WebM audio, I forgot that WebM doesn’t work on Safari yet. There is starting to be support for WebM with iOS 15, however it is video with Ogg Vorbis (Opus is the successor to Vorbis. See What is the difference between Vorbis and Opus? if you want to know the details.).

To support PWA with Ogg Opus/WebM audio, there are a couple of options:

  1. Have the browser detect being on Safari and look for an mp3 instead of webm. I could even have a visual switch for smaller or larger bandwidth usage and have it disabled and stuck on larger for Safari.
  2. Use a JavaScript library to transcode from WebM in the browser on Safari. This is a lot more work since I have to implement or find a JavaScript library to display audio controls.

Who is interested in using WebM in a PWA? Do you have an opinion on which way I should go?

Chris Hubbard

I am inclined to say we should postpone using WebM in PWA. Just use mp3 files for now. If the time comes when there is wider support, we could look into it. --Loren

I wouldn’t put much effort into this now (so option 1). It seems all the roads are converging to support WebM/Opus but they are not intersecting at this present time. When I say all roads, FCBH is presently working on adding Opus formatted audio via Biblebrain .com, but that is a work in progress and not yet readily available. Also, the Mac/iOS/Safari world is also heading to support WebM/Opus, but again, not quite there yet.

@LorenHawthorne, the problem with not using WebM for PWA is that you would need to have a separate project is you are using WebM with the Android and/or iOS app. That is more maintenance.

@Jon_C I think that WebM in BibleBrain is ready (not a work in progress). If you have a language that was brought over from the previous DBP2, then you can request that the WebM files be created if they are not already there.

Apple is supporting WebM for video (which used Ogg Vorbis for audio format instead of Ogg Opus). We shall see if they add Opus, but I wouldn’t hold your breath.


I never noticed this problem as I have never used Safari. We have the webm files in our PWA html files on our app’s website. I tried it just now out of curiosity and indeed it does not work. (it works fine on every other browser I have tried)
Since we have our app on the App Store, I doubt that there are many people trying from Apple devices.
Instead of having a separate project to maintain as a workaround, one could have separate AWS buckets (other providers are available) for mp3 and webm files. In SAB make a separate source for each bucket. Before making the PWA, simply select all the audio and change the source to the mp3 bucket.
Having said that, if it isn’t much work to implement option 1 (Safari detection) then that would be a good idea.

I am looking forward to a time when all of the desktop and smartphone browsers will have the latest and greatest media container format. Unfortunately, right now they don’t do that yet. Earlier in May I have emailed (with Chris, Bill, and Loren) that Safari can’t do Ogg (Vorbis and Opus codecs) and only does WebM if it has WebRTC loaded (which would require users to make a second download and then install) or if the operating system is iOS 15 (which is available as of late last month, September 2021). In ScriptureEarth analytic the second browser per month is Safari. We need to continue on with the mp3s at this time so that Safari will be able to handle the audio.

ScriptureEarth can easily detect what the user is running on a Safari browser. But, if all of the SAB HTML files have this
< audio controls>
< source src=“audio.webm” type=“audio/webm”>
< source src=“audio.mp3” type=“audio/mpeg”>
Your browser does not support the audio element.
< /audio>

could the template do this without having the PHP browser detector work? Although, you would have to use 2 formats (webM and mp3 audio files).

@scott_starker: It must be obvious I am not a web developer. Thank you for the suggestion! This works fine. So if you use WebM in PWAs you will need to include the fallback mp3.



In Chrome, if both webm and mp3 are there in the audio controls element, is there a way to provide UI to the users for them to select webm or mp3?

If Chrome does use webm, as it does, why would you want mp3 as a selectable option? If the first source (i.e. webm) in the audio control in Chrome exists it gets executed and not touching the other “sources”.

If there is music, MP3 is slightly better quality.

I don’t think there’s a good way to do the music. Let me think on that…

I’ve a PWA with webm files that I know didn’t work on safari. Are you saying this change has already been implemented? Since my PWA is published through scriptoria, should I now re-submit it to them, including the mp3 files for them to issue an upgrade? Thanks

I have an idea that seems to work. Are you able to add a js in all of the SAB HTML files? If so, I will make the MP3 additions to ScriptureEarth and you (Chris) make the changes to the SAB HTML files. The filename will be ‘js/see-mp3.js’ (or whatever filename you want) and the script have the attribute “defer” in each the the sab folders. The js script is:

// Scott Starker - 10/14/2021
// sessionStorage.setItem("mp3", "mp3") in website
// if sessionStorage.setItem("mp3", "mp3") then remove the all of the other audio "source"s src
// assume the audio "source" have "id"s of "audio1", "audio2", "audio3", "audio4", and "audio5" maximum
// all of the audio HTML files will have <script type='text/javascript' src='js/see-mp3.js' defer></script> if they want to use this js
let srcmp3 = "";
if (typeof(Storage) !== "undefined") { // sessionStorage is found
    if (srcmp3 = sessionStorage.getItem("mp3")) { // if "mp3" is found from the users browser and assign it to srcmp3
        let re = /.*\.([a-z0-9]+)$/i; // regex
        let i = 1;
        for (; i <= 5; i++) { // assume 5 sources
            let audioZ = document.getElementById('audio' + i); // iterate through audio "source"
            if (audioZ.src.replace(re, '$1') != srcmp3) { // if file extension = "mp3"
                 audioZ.removeAttribute("src"); // remove "*.mp3" from audio "source"
            } else {
                 const mediaElement = document.querySelector("#audio");
                 mediaElement.load(); // reload "audio"
        if (i == 6) {
            console.log("This isn't supposed to happen. mp3 is not found in audio sources.");
    } else { // = "" or undefined
        console.log("mp3 sessionStorage is not found");
} else {
    console.log("sessionStorage is not found");