On Android and desktop, a broken camera usually announces itself: a rejected promise, an error event, something your code can catch. On an iPhone, the camera mostly goes quiet instead. The track stays "live", the call stays connected, and the person on the other end watches a frozen or black tile while your logs show nothing wrong.

That is the core difficulty of running a video SDK on iOS Safari. The failures are real, but they arrive as state changes, not errors. We ran a one-page test on a real iPhone with Safari 26.0.1 on 13 October 2026 to see which of the documented behaviours still hold. This post walks through what we found and the handful of handlers that catch it.

Every iPhone Browser Is Safari

Start with scope. On iOS, "Chrome" and "Firefox" use Apple's WebKit engine, because Apple's App Store guideline 2.5.6 requires browsing apps to use WebKit, as The Register reported when Japan moved against the rule. The exception is narrow: Apple's embedded browser engine entitlement allows other engines from iOS 17.4, and only in the EU and Japan.

So testing on Chrome for iPhone is testing WebKit. A bug that appears in Safari almost always appears in every iOS browser your users have.

Don't branch on the version in the user-agent string either. WebKit bug 298473 records that Safari now freezes the iOS version it reports, permanently, after sites misread "26" as lower than "18". Our test phone's Safari reported itself as version 26.0.1 running on iOS 18.7. Detect features, not versions.

Mute Is Not End

A camera track (MediaStreamTrack) can tell you two different things:

Signal

What it means

readyState

Can it come back?

mute event

The source has stopped delivering frames for now

still live

Yes, unmute fires when it resumes

ended event

The track is finished

ended

No; you need a new track

The trap is that a muted track is still attached to the peer connection. The call does not drop, so your reconnection logic never runs. Nothing is wrong with the network. The other side simply stops receiving useful video.

iOS uses both signals, for different triggers. Our test results:

Trigger

What happened (Safari 26.0.1)

Signal

Leave the page (Home Screen), return after ~5 s

Camera muted while away, resumed on return

mute, then unmute

Ask for the same front camera a second time

Both tracks kept running

none

Ask for the back camera while the front is live

Front camera track finished

ended

Remote video with sound, started without a tap, while capturing

Played

n/a

AudioContext created without a tap

Stayed suspended

n/a

One device and one run, so treat it as confirmation of documented behaviour, not a survey.

Three Ways the Camera Goes Quiet

Leaving the page

When the page is hidden, iOS mutes the camera, and unmutes it when the page is visible again. This has been deliberate since 2017: WebKit bug 172200 made iOS mute the video source according to document visibility so a background tab cannot capture the camera.

Our test showed it still holds, with one useful detail: the mute event fired about 0.8 seconds before the page's visibilitychange event. If your UI waits for visibility events to explain the pause, it is late. Listen on the track.

Users do this constantly: checking a message mid-call, taking a phone call, locking the screen. Every time, the other participants see the video freeze.

Switching cameras

This behaviour has changed over the years, and old advice is wrong. In 2017, WebKit bug 179363 reported that a second getUserMedia() call muted the first track with no way to unmute it, and WebKit called that expected. In 2022 it changed: asking for a different camera now stops the previous capture, because iOS cannot capture both at once, while the same camera can run in parallel.

Our test matched the 2022 behaviour. Requesting the back camera ended the front camera's track outright. Asking for the front camera again left both running.

So a camera flip on iOS is not a mute you can wait out. The old track is gone. Get the new track first, then swap it into the call with the sender's replaceTrack(), then stop the old one, and make sure your ended handler doesn't treat this as a failure.

Route changes in a single-page app

Sometimes the trigger is a WebKit bug. WebKit bug 272704 reported that in iOS 17.4.1, calling history.pushState() muted the camera track. That's what any single-page app router does when the user moves between screens. It worked in 17.4.0 and earlier, and a fix landed in WebKit under a related bug. We couldn't re-test it: the camera had already ended in the previous step of our test.

The lesson is not this particular bug. Point releases change camera behaviour, and the change shows up as a muted track, not an exception. Code that listens for mute catches the next regression too.

Sound and Autoplay

Video can autoplay on iOS only under conditions. WebKit's iOS video policy has allowed muted video to autoplay since iOS 10, requires playsinline for inline playback on iPhone, and pauses video that gains sound without a user gesture.

Calls get an exception. As webrtcHacks summarised from WebKit's WebRTC documentation, stream-backed video can autoplay when the page is already capturing the camera or microphone. Our test agreed: remote video with sound started without a tap while the camera was on. An AudioContext created without a tap stayed suspended, so Web Audio processing (meters, noise effects, mixing) still needs a gesture.

The case that still breaks is the viewer who isn't capturing: a webinar attendee, a monitoring wall, a listen-only participant. Without capture there is no exception, so sound needs a tap. Put a real "Join" button in front of the call and start playback from it.

What to Build

Four handlers cover most of it:

function watchCamera(track, sender) {
  track.onmute = () => showPaused('Camera paused');

  track.onunmute = () => hidePaused();

  track.onended = async () => {
    if (switchingCamera) return;

    const s = await navigator.mediaDevices.getUserMedia({ video: true });
    const fresh = s.getVideoTracks()[0];

    await sender.replaceTrack(fresh);
    watchCamera(fresh, sender);
  };
}

// Every <video> element: playsinline. Start playback from the Join button.

Alongside the code:

  • Tell the other side. Send a "camera paused" signal over the data channel or your signalling, so remote participants see a label instead of a frozen face.
  • Measure it. Count mute and unmute events per session, and watch outbound frame counts drop to zero when you collect getStats in production. A spike after an iOS update is how you learn about the next regression.
  • Flip cameras with replaceTrack. Don't tear down and rebuild the connection.
  • Feature-detect. Check for the API you need, not the iOS version.

How to Test Without a Device Lab

You need a real iPhone; simulators don't reproduce camera interruptions. You don't need a lab. We used a single HTML page, served over HTTPS (the camera requires it), that logs every track event with a timestamp and produces a copyable report. Someone with an iPhone opens the link, taps through each trigger, and sends the report back.

Re-run it after every major iOS release. The behaviours in this post moved twice in eight years.

The Bottom Line

A video SDK on iOS Safari fails quietly. Leaving the page mutes the camera, switching cameras ends the old track, point releases have muted it by accident, and none of it throws. Listen for mute and ended on the track, tell the other participants, start sound from a tap, and test on a real phone after each iOS update.

What's Next

Mobile is also where the embedding choice bites, because an iframe inside a native app means a webview. Next: choosing between an iframe, a UI kit and a headless SDK.

Frequently Asked Questions

Why does my video SDK on iOS Safari show a black screen with no error?

Usually the camera track has been muted, most often because the user left the page. The track stays live and the call stays connected, so no error fires. Listen for the track's mute and unmute events and show the state to both sides.

Does Chrome on iPhone behave differently from Safari for video calls?

Not in most of the world. Apple requires iOS browsers to use WebKit, so Chrome on iPhone has Safari's camera and autoplay behaviour. Other engines are allowed only in the EU and Japan, from iOS 17.4.

Why does switching to the back camera stop the front camera on iPhone?

iOS can't capture from two cameras at once, so requesting a different camera ends the previous camera's track. Get the new track, swap it into the call with replaceTrack(), then stop the old one.

Can a web video call keep sending video when the user leaves the page on iOS?

No. iOS mutes camera capture while the page is hidden and resumes it on return. Native apps have more options, which is one reason teams with heavy iPhone use ship a native client, for example on Samvyo's React Native SDK. For web, the right response is a clear "camera paused" state for the other participants.

Why won't remote audio play automatically on iPhone?

iOS needs a user gesture to start audio, unless the page is already capturing the camera or microphone. Viewers who only watch need a tap, so start playback from a Join button.

Do these iOS issues depend on which video platform I use?

The behaviour comes from WebKit, so every web video SDK sees it, Samvyo's JavaScript and React SDKs included. What differs is how much of the handling a platform does for you, so test mute, camera switching and autoplay on a real iPhone with any SDK you evaluate.