Picture-in-Picture Mode: Complete Implementation Guide 2025 — cover illustration

Key takeaways

Picture-in-Picture mode is cheap retention, not a gimmick. On our own mobile-first video projects, shipping PiP lifted average session length by high single digits and nudged D7 retention up a few points. It is one of the highest-return features per engineering hour in a video product.

The web now has two PiP APIs. The classic Picture-in-Picture API (video element only) is near-universal; the newer Document Picture-in-Picture API (arbitrary DOM) runs in Chrome/Edge and, as of Firefox 151 (May 2026), Firefox too.

iOS is the hardest surface. App Store review of the background-audio capability, AVPictureInPictureController vs the video-call controller, and the WebRTC path each have their own traps.

Android is the cleanest. Activity PiP plus PictureInPictureParams covers most cases in 30–60 engineering hours, and Media3/ExoPlayer needs no special handling.

PiP scope splits into three tiers. Tier 1: passive video playback PiP (about 2 weeks). Tier 2: iOS and Android added (5–6 weeks). Tier 3: WebRTC call PiP and Document PiP with controls (8–10 weeks).

Why Fora Soft wrote this playbook

Fora Soft has built video and real-time products since 2005 — 250+ projects across telehealth, live streaming, video conferencing, OTT, education and surveillance, with 50 in-house engineers and a 100% job-success record on Upwork. We have shipped Picture-in-Picture on all four surfaces this guide covers, so we have also hit the failure modes: iOS review rejections, Android OEM quirks, Safari gaps, and the WebRTC-in-PiP dance that no vendor documents end to end.

This is what we tell clients in week one of a PiP-heavy build: which API to reach for on each platform, what it costs, where it breaks, and when to say no. For the iOS-only deep dive, read our companion piece, Picture-in-Picture on iOS: implementation and peculiarities. For the product context, see our video and audio streaming development work and the education platforms in our BrainCert case study.

Need PiP on web, iOS and Android in one sprint?

A 30-minute call with a Fora Soft engineer scopes your PiP work across all three platforms, WebRTC included, in a single pass.

Book a 30-min call → WhatsApp → Email us →

What Picture-in-Picture mode is in 2026

Picture-in-Picture mode lets a video detach from its host tab or app and float in a small always-on-top window while the user does something else. It first shipped on Safari for macOS (2016) and Android (2017), and it now runs on every major consumer platform. The details differ per surface, so the first job is knowing exactly what each one supports.

Picture-in-Picture support 2026: classic video PiP works everywhere; Document PiP in Chrome, Edge and Firefox 151, not Safari

Figure 1. Classic video-element PiP is near-universal; Document PiP is desktop Chromium plus Firefox 151 (2026), and not Safari.

Platform Video element PiP Document / DOM PiP Notes
Chrome / Edge / Opera Yes, since Chrome 70. Yes, stable since Chrome 116 (2023). Full controls, auto-PiP on tab switch.
Firefox (desktop) Browser toggle only, no JS API. Yes, new in Firefox 151 (May 2026). No requestPictureInPicture(); users trigger PiP from the built-in control.
Safari (macOS / iOS) Yes (macOS 2016, iPhone since iOS 14). No. Long-standing presentation-mode API; check MDN for the standard-API version you target.
Android Yes, via Activity PiP (API 26+). n/a (native OS PiP) Media3/ExoPlayer integrates directly; some OEM skins gate it.
iOS / iPadOS Yes, via AVPictureInPictureController. n/a (native OS PiP) Background “audio” mode required; review-prone.

Reach for classic video-element PiP when: you are shipping VOD or a simple live viewer. Reach for Document PiP when you need custom controls, chat, overlays or an editor UI inside the floating window and can target Chromium or Firefox. The full spec lives at the W3C Picture-in-Picture and MDN.

Web PiP: the video element in 10 lines

For a standard HTML5 video, PiP is a one-method call on the element. This is the baseline every OTT product should ship. Feature-detect first, then toggle:

const video = document.getElementById('player');

if (document.pictureInPictureEnabled && !video.disablePictureInPicture) {
  pipBtn.addEventListener('click', async () => {
    try {
      if (document.pictureInPictureElement) {
        await document.exitPictureInPicture();
      } else {
        await video.requestPictureInPicture();
      }
    } catch (err) {
      console.warn('PiP failed:', err);
    }
  });

  video.addEventListener('enterpictureinpicture', () => {/* shrink main UI, track event */});
  video.addEventListener('leavepictureinpicture', () => {/* restore main UI */});
}

Two things to wire alongside it. First, navigator.mediaSession, so pause, seek and next show up in the PiP chrome and on OS media-control surfaces. Second, the disablePictureInPicture attribute on ad or DRM-forbidden frames where PiP must not be allowed. The :picture-in-picture CSS pseudo-class lets you restyle the player automatically as it enters and leaves the mode.

Document PiP: float any DOM, not just video

Classic PiP floats a bare video element. The Document Picture-in-Picture API (stable in Chromium since Chrome 116, 2023) floats any DOM you hand it: the player, a chat sidebar, a whiteboard, controls, an overlay. That turns PiP from “watch while doing email” into a miniaturized instance of your app. Firefox 151 added support in May 2026; Safari still does not have it.

Classic PiP floats one video element; Document PiP floats a mini-app with video, chat, presence and custom controls

Figure 2. The two web PiP APIs: classic floats a single video; Document PiP floats an entire interactive window.

if ('documentPictureInPicture' in window) {
  const pipWindow = await documentPictureInPicture.requestWindow({ width: 320, height: 180 });

  // Copy stylesheets so the PiP window matches the host.
  [...document.styleSheets].forEach(sheet => {
    try {
      const css = [...sheet.cssRules].map(r => r.cssText).join('');
      const style = pipWindow.document.createElement('style');
      style.textContent = css;
      pipWindow.document.head.appendChild(style);
    } catch { /* cross-origin sheet, skip */ }
  });

  // Move the live call UI into the PiP window, and put it back on close.
  pipWindow.document.body.append(document.getElementById('live-call'));
  pipWindow.addEventListener('pagehide', () => {
    document.body.append(document.getElementById('live-call'));
  });
}

Where it earns its keep. Video meetings (gallery plus visible chat), live commerce (product panel next to the stream), collaborative editors (document plus a presence indicator) and coding tools (tests running beside the editor). Document PiP is the only way to keep a WebRTC grid interactive without leaving the tab. The window API also gives you resizeTo, focus handoff to the opener, a disallowReturnToOpener flag, and the display-mode: picture-in-picture media query for restyling the host page. Chrome’s own Document PiP guide has the full option list and lifecycle details.

Reach for Document PiP when: you need controls, chat or any interactive UI inside the window and Chrome, Edge or Firefox 151+ is acceptable. Keep a classic-PiP fallback for Safari and older Firefox.

Android PiP: Activity mode and params

Android PiP is an Activity-level mode, available since Oreo (API 26). You declare support, expose an aspect ratio and optional remote actions, then call enterPictureInPictureMode(). Media3/ExoPlayer needs no special handling; auto-enter arrived in Android 12 (API 31).

<!-- AndroidManifest.xml -->
<activity android:name=".PlayerActivity"
    android:supportsPictureInPicture="true"
    android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
    android:launchMode="singleTask" />

// PlayerActivity.kt
override fun onUserLeaveHint() {
  super.onUserLeaveHint()
  if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && player.isPlaying) {
    val params = PictureInPictureParams.Builder()
      .setAspectRatio(Rational(16, 9))
      .setActions(buildPipActions())
      .setAutoEnterEnabled(true)   // Android 12+
      .build()
    enterPictureInPictureMode(params)
  }
}

Gotchas. The Activity must be singleTask. Handle onPictureInPictureModeChanged to swap in a minimal UI. On some OEM skins (Xiaomi MIUI, Huawei EMUI) users must grant a per-app PiP permission, so surface a helper on first use and log when it is missing. The Android PiP docs cover the params in full; for battery and memory tuning that compounds with PiP, see our Android video-streaming optimization guide.

iOS PiP: controller, audio, review traps

iOS PiP is built on AVPictureInPictureController. Wiring it up is about 15 lines. Shipping it through App Review without surprises is the hard part.

// Info.plist: UIBackgroundModes = ["audio"]
// AVPlayer + AVPlayerLayer is the normal path. For a video call, use
// AVPictureInPictureVideoCallViewController (iOS 15+) or a sampled layer.

import AVKit

let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resizeAspect
view.layer.addSublayer(playerLayer)

guard AVPictureInPictureController.isPictureInPictureSupported() else { return }
let pip = AVPictureInPictureController(playerLayer: playerLayer)!
pip.delegate = self
pip.canStartPictureInPictureAutomaticallyFromInline = true

try AVAudioSession.sharedInstance().setCategory(.playback)
try AVAudioSession.sharedInstance().setActive(true)

The four traps we keep debugging. First, apps that declare the “audio” background mode but do not actually play audio in the background get rejected; the app must legitimately continue audio for the user. Second, returning from PiP means restoring the player into your view hierarchy, and forgetting to do so leaves a live-but-disconnected PiP window. Third, for WebRTC calls use AVPictureInPictureVideoCallViewController (iOS 15+); AVPlayerLayer cannot render an RTCVideoTrack. Fourth, on iPad, Slide Over and Stage Manager confuse first-time users, so document the behaviour. Apple’s AVKit reference and our iOS PiP deep dive go further.

PiP for WebRTC calls: the hard mode

The most common PiP request we get in 2026 is: put the active speaker of a meeting into PiP when the user switches tab or app. Every platform answers it differently.

Web. Either render the RTCVideoTrack into a <video> fed by a MediaStream and use classic PiP, or move the whole call UI into a Document PiP window. The second option is better for meetings because you keep controls and roster.

Android. Run the call UI in one Activity and flip to PiP with auto-enter; the WebRTC SurfaceViewRenderer renders inside PiP without extra work.

iOS. Use AVPictureInPictureVideoCallViewController (iOS 15+) with an AVPictureInPictureSampleBufferDisplayLayer, and push CMSampleBuffers from the WebRTC track. PiP for WebRTC content inside a WKWebView is still not reliable, so native is the path. Budget 60–100 hours for a production-grade iOS call-PiP. Our WebRTC architecture course and the business WebRTC guide give the broader stack context.

Bringing PiP to a video-call app?

We have shipped PiP for WebRTC calls on iOS, Android and web. Skip the trial-and-error and get a working implementation in a sprint.

Book a scoping call → WhatsApp → Email us →

PiP in React Native, Flutter and hybrid

React Native. Use the built-in PiP prop in react-native-video, or react-native-pip-android for Android. For WebRTC, pair react-native-webrtc with a small native bridge to the iOS video-call controller and the standard Activity PiP on Android.

Flutter. The floating and simple_pip_mode packages wrap Android PiP cleanly; iOS needs a platform channel to AVPictureInPictureController. Flutter-WebRTC PiP is workable, but budget 2–3 extra days for the iOS glue.

Capacitor / Cordova wrappers. Web PiP just works inside the web view; for native PiP you add a small platform plugin per OS.

UX rules that make PiP actually useful

1. Make auto-PiP opt-in. Unsolicited PiP on tab switch reads as spyware. Offer a setting, default it off.

2. One PiP button, where users already look. On a video player that is bottom-right, next to fullscreen. Do not reinvent the placement.

3. Keep controls inside PiP. Play, pause, seek, skip, mute. On web that is mediaSession; on iOS and Android the system chrome handles it.

4. Restore state when PiP ends. Seek position, play/pause, volume, mute and fullscreen should all round-trip.

5. Respect DRM and ads. Disable PiP on unskippable ads and DRM-forbidden windows via disablePictureInPicture.

6. Treat accessibility as day-one work. The toggle needs an aria-label, a keyboard shortcut (P is common) and a visible focus ring; announce state changes to screen readers.

Tooling and libraries we reach for

Web players with built-in PiP. Video.js, Shaka Player, HLS.js, Bitmovin, THEOplayer and JW Player all support classic PiP out of the box; Bitmovin and THEOplayer lead on Document PiP integration.

Android. AndroidX Media3 (ExoPlayer) plus a short PictureInPictureParams builder. For WebRTC, the official org.webrtc SurfaceViewRenderer.

iOS. AVKit, AVFoundation, AVPictureInPictureVideoCallViewController (iOS 15+) and AVPictureInPictureSampleBufferDisplayLayer. Third-party: MobileVLCKit for non-AVPlayer content.

Testing matrix. At minimum: Chrome 120+, Safari 17+, Firefox 151+, Android 8/11/14 on Samsung, Xiaomi and Pixel, iOS 15/17 on iPhone and iPad. BrowserStack, Sauce Labs or LambdaTest for the cloud grid.

Analytics hooks you need from day one

You cannot improve what you do not measure. Instrument six events and tag each with platform, device class and session ID:

1. pip_enter. When PiP activates, flagged user-initiated or auto.

2. pip_exit. When PiP ends, with duration and reason (user-closed, navigation, end-of-video, error).

3. pip_denied. API refused to enter PiP; log the error code to catch OEM quirks.

4. pip_control_click. Pause, play or next from inside the PiP window.

5. pip_state_mismatch. Exit left the player inconsistent; it should never fire if your restore logic is right.

6. pip_feature_seen. The user saw the PiP button, for conversion analysis against actual use.

Mini case: PiP on an education platform

Situation. An online-education client shipped Android, iOS and web, with lectures over HLS and live Q&A over WebRTC (the same kind of live-class load we run for Scholarly). Students wanted the lecture visible while taking notes. The recurring support ticket: “why does PiP work in YouTube and not in your app?”

The 4-week plan. Week 1: web classic PiP for VOD plus Document PiP for the WebRTC Q&A. Week 2: Android Activity PiP with Media3 and auto-enter. Week 3: iOS PiP via AVPlayerLayer for VOD and the video-call controller for Q&A. Week 4: UX pass, the six analytics hooks, and an App Review resubmission with the audio capability properly declared and used.

Outcome. Average session length rose about 11% in the first month; D7 retention among mobile-first users gained roughly 3 points; PiP-related support tickets went to zero. Total spend was around 170 engineering hours across two mobile engineers plus web. Want a similar assessment? Book a 30-minute call and we will scope it against your stack.

What shipping PiP actually costs

The estimates below assume our Agent-Engineering-accelerated workflow. Teams without that acceleration should add 40–60% more hours. Every number is engineering hours, not calendar time.

PiP cost by scope in engineering hours: web classic 10-20, Document 40-80, Android 30-60, iOS 30-50, iOS WebRTC 60-100

Figure 3. Engineering effort by scope. iOS WebRTC call PiP is the single most expensive line item.

Scope Hours Includes
Web (video element PiP) 10–20 Toggle, mediaSession, analytics.
Web (Document PiP) 40–80 DOM move/restore, style copy, lifecycle.
Android (Activity PiP) 30–60 Manifest, params, actions, OEM testing.
iOS (AVPlayerLayer PiP) 30–50 Controller, audio session, review.
iOS (WebRTC call PiP) 60–100 Video-call controller, sample-buffer layer.
Full cross-platform PiP ~170–310 All of the above, QA on 10+ devices.

Worked example. A typical “we want PiP everywhere” build lands mid-range: web classic 15h + Android 45h + iOS AVPlayer 40h + iOS WebRTC call 80h + QA across 10 devices 30h = 210 hours. At an example blended rate of $80/hour that is 210 × $80 ≈ $16,800 — a small line item next to the retention it buys, and far cheaper than the three separate discovery cycles most teams spend rediscovering these same traps.

Five pitfalls that sink PiP projects

1. Skipping iOS App Review due diligence. The “audio” background mode is inspected. Enable it and justify it: the app must actually continue audio in the background. A rejection cycle costs 5–10 days.

2. Not testing OEM skins on Android. Xiaomi MIUI, Huawei EMUI and some Samsung builds require a manual PiP permission. Surface a helper and log when the permission is missing.

3. Losing player state across enter and exit. The bug we fix most often. Keep a small PlayerState object and snapshot-restore on every transition.

4. Letting PiP escape your ads. Users pop unskippable ads into PiP and keep watching content. Set disablePictureInPicture during ad slots and flip it back after.

5. Accessibility as an afterthought. A missing aria-label, no keyboard shortcut, no focus ring: these are accessibility-audit findings waiting to happen. Build them in from the start.

KPIs to measure after shipping PiP

Quality. PiP enter success rate above 98%, exit-with-state-loss under 1%, and average PiP window duration above 45 seconds (proof users choose it rather than trigger it by accident).

Business. Session-length lift versus a control cohort, D7 and D30 retention lift, and feature awareness (unique users who used PiP at least once in 30 days).

Reliability. Crash rate no worse than the pre-PiP baseline, and App Store / Play Store review sentiment no worse after launch.

Decision framework: do you need PiP?

Five questions decide both whether to ship PiP and which tier to scope.

PiP decision tree: is video core, do users multitask, is it WebRTC, how many platforms, mapping to Skip or Tier 1/2/3

Figure 4. Four questions down the stem map your product to Skip, Tier 1, Tier 2 or Tier 3.

Q1. Is video or audio the core activity? Yes, PiP is table stakes. No, video is peripheral, skip it.

Q2. Do users multitask on the same device during playback? The more they do, the higher the return on PiP.

Q3. Is content DRM-gated or ad-heavy? Both shrink where PiP is allowed, so the scope narrows.

Q4. Is the product WebRTC-based? If yes, plan the call-PiP path (iOS video-call controller, Document PiP on web) from day one; retrofitting costs 2–3× as much.

Q5. How many platforms ship? Web only is Tier 1, about 2 weeks. Add iOS and Android for Tier 2, 5–6 weeks. Add WebRTC call PiP for Tier 3, 8–10 weeks total.

Reach for Tier 1 PiP (passive video element) when: you are shipping an OTT MVP or a simple live viewer. It is the highest return per engineering hour in the whole video-product feature set.

Rejected in App Review over PiP?

We have untangled dozens of App Store rejections around PiP and background audio. Book 30 minutes and we will tell you exactly what to change.

Book a review call → WhatsApp → Email us →

When you should not ship PiP

Video is incidental. If the product is a form with a short explainer clip, PiP adds complexity for negligible retention.

Strict DRM forbids off-window playback. Some content licences contractually prohibit PiP; check with legal before scoping it.

Audio-only products. The OS already provides lock-screen and media-control surfaces, so a custom PiP UI is wasted effort.

Kids’ products. Regulators increasingly discourage features that keep video playing while a child’s app is backgrounded. Default off, with a hard switch in settings.

Reach for Document PiP when: the product is a live-collaboration, editor, meeting or coding tool on web and you can target Chromium or Firefox 151 first, keeping a classic-PiP fallback for Safari.

FAQ

Does Picture-in-Picture mode work in Safari on iPhone, not just iPad?

Since iOS 14, yes. Safari on iPhone supports PiP for video elements; earlier iOS versions did not. For in-app PiP on iPhone you still use AVPictureInPictureController.

Does PiP work for WebRTC video meetings?

Yes. On web, Document PiP is the preferred path because it keeps your controls. On iOS, use AVPictureInPictureVideoCallViewController (iOS 15+). On Android, plain Activity PiP with a SurfaceViewRenderer works.

Does Firefox support the Document Picture-in-Picture API?

Yes, as of Firefox 151 (May 2026). Before that, Document PiP was Chromium-only. Note that Firefox still has no standard requestPictureInPicture() JS API for the classic video PiP; it exposes a browser-level toggle instead.

Does iOS PiP require background audio capability?

For PiP that keeps playing when the user leaves your app, yes. Add UIBackgroundModes with the “audio” value in Info.plist and set AVAudioSession to .playback. App Review checks that your app truly plays audio in the background, not just declares the capability.

Why does PiP not trigger on some Android phones?

Two common causes. First, PiP permission is disabled in system settings on Xiaomi and Huawei; surface a deep link to that screen. Second, the Activity is not singleTask or does not declare supportsPictureInPicture="true". Recheck the manifest.

Does PiP reduce video quality or bitrate?

Only because the window is small, so most players step down resolution. For ABR streams (HLS/DASH) that happens automatically via the bandwidth estimator; for WebRTC with simulcast, the SFU usually switches the subscriber to a lower layer.

How do you prevent PiP during ads?

On web, set disablePictureInPicture on the video element while an ad plays. On iOS, set canStartPictureInPictureAutomaticallyFromInline = false; on Android, call setAutoEnterEnabled(false) or exit PiP at ad start. Flip it back on at ad end.

Is PiP a core feature of modern OTT apps?

It is table stakes for mobile-first video products now. Our OTT platform development playbook treats PiP as an MVP feature alongside captions and casting.

iOS deep dive

PiP on iOS: Implementation and Peculiarities

The companion deep dive on the iOS APIs, review gotchas and WebRTC PiP.

WebRTC

WebRTC Architecture Guide 2026

The broader context when PiP is a feature of a video-call product.

OTT playbook

OTT Platform Development in 2026

Where PiP fits into the modern OTT feature matrix and budget.

Android

Optimize Android Apps for Video Streaming

Battery, memory and playback tuning that compounds with PiP.

Ready to ship a PiP that users actually love?

Picture-in-Picture mode is the cheapest meaningful feature you can add to a video product in 2026. The classic web API is universal; Document PiP now spans Chromium and Firefox 151 and opens up meetings, editors and collaboration; Android is straightforward; iOS is only tricky if you skip the review checklist. For most OTT, education, telehealth and meeting products, the highest-impact move is to ship Tier 1 PiP now and Tier 3 in the next sprint.

Fora Soft has shipped PiP on web, iOS, Android and WebRTC for years across video conferencing, e-learning and streaming products, and we run a full video-streaming curriculum for engineers. If you want a team that lands PiP in one focused sprint instead of three discovery ones, that is what we do.

Let’s scope your PiP work in one call

Bring your platforms, your players and your WebRTC stack. We will come back with an honest estimate and a sprint plan.

Book a 30-min call → WhatsApp → Email us →

  • Technologies