Skip to main content
For most Expo apps, Bunny Player is the recommended way to play Bunny Stream videos. Embed it in a WebView and you get adaptive playback, analytics, captions, chapters, and dashboard branding out of the box. Bunny Player supports features like Picture-in-Picture and background audio on the web, but when you embed it inside a native app, the WebView becomes the bottleneck. The OS won’t float a WebView for PiP, won’t let it play audio in the background, and won’t show it on the lock screen. Those are platform-level features that require a native player. expo-video plays Bunny Stream’s HLS URLs directly through the native video stack (AVPlayer on iOS, ExoPlayer on Android), giving your app full access to the platform APIs that a WebView can’t reach.
expo-video requires a development build. It won’t work in Expo Go. Run npx expo run:ios or npx expo run:android, or build with EAS.

Quickstart

1

Install expo-video

2

Configure the plugin

Add the expo-video config plugin to your app.json to enable Picture-in-Picture and background playback:
3

Play a video

Every processed Bunny Stream video has an HLS playlist at a predictable URL:
Find your Pull Zone hostname under Stream > API in the bunny.net dashboard.Pass the HLS URL to useVideoPlayer and render a VideoView:
That’s it. The player handles adaptive bitrate selection automatically, choosing the best quality for the device’s connection.
A complete working example with a video list screen, detail screen, chapter navigation, and caption picker is available at bunny-stream-expo.

URL structure

Every processed video is accessible via predictable URLs built from your Pull Zone hostname and the video’s GUID:

Fetching video metadata

The Get Video endpoint returns metadata including title, dimensions, chapters, captions, and available resolutions. Use this to build your UI around the player:
The AccessKey is a secret. In a production app, proxy API calls through your backend so the key never reaches the client.
The response includes fields you can pass directly to the player:
Setting metadata.title and metadata.artwork populates the lock screen and now playing notification on both iOS and Android.

Playback controls

useEvent from expo tracks playback state reactively:

Progress tracking

Set timeUpdateEventInterval on the player and listen for timeUpdate events using useEventListener from expo:

Chapter navigation

The Get Video response includes a chapters array with title, start, and end times in seconds. Since expo-video exposes a writable currentTime property, chapter navigation is straightforward:
The same pattern works for moments. Use moment.timestamp instead of chapter.start.

Captions

Bunny Stream includes subtitle tracks in the HLS manifest. After the source loads, expo-video exposes availableSubtitleTracks and a settable subtitleTrack property:

DRM

If your library has MediaCage Enterprise DRM enabled, expo-video can request play licenses directly from Bunny’s license servers using the drm source option.
The license endpoints apply the same referrer protection and token authentication as the player embed view. If either is enabled in your library settings, include the corresponding headers or query parameters in your requests. See Embedded view token auth for details.
On iOS, use FairPlay with Bunny’s certificate and license endpoints:
On Android, use Widevine:
Last modified on June 26, 2026