Both libraries wrap the same two native players: AVPlayer on iOS and ExoPlayer on Android. Both therefore play adaptive HLS with no extra configuration, which retires the question people usually arrive with. What actually separates them is the surrounding machinery. One is maintained alongside the Expo SDK and runs in Expo Go for basic playback. The other is the community package that most third-party tooling is written against, including analytics SDKs.
TL;DR
expo-video is the smaller, better-integrated choice for an Expo app that plays video and doesn't need anything to hook into the player instance. It runs in Expo Go for basic playback, installs with npx expo install, and its API is small enough to learn in one sitting. react-native-video is the choice when something else has to attach to the player. Analytics SDKs, DRM integrations and ad frameworks are overwhelmingly written against it, the FastPix React Native Video Data SDK included. If you need playback metrics, that decides for you, before any comparison of the player APIs matters.
expo-video vs react-native-video: neither one decodes
The libraries are bindings. On iOS both end up at AVPlayer. On Android both end up at ExoPlayer. Those are the components that parse the manifest, request segments and switch renditions.
So playback quality, HLS support, adaptive bitrate behaviour and codec coverage are properties of the operating system rather than of the package you chose. A stream that plays in one will play in the other.
That's worth stating because most comparisons of these two spend their length on playback, which is the part where the answer is "identical".
| Concern | expo-video | react-native-video |
|---|---|---|
| HLS playback | Native, no config | Native, no config |
| Underlying player | AVPlayer, ExoPlayer | AVPlayer, ExoPlayer |
| Basic playback in Expo Go | Yes | No, needs a development build |
| Install | npx expo install expo-video | npm install, then native setup |
| API surface | Small, hooks-based | Large, prop-heavy |
| Third-party SDK support | Limited | The common integration target |
| FastPix Video Data SDK | Not supported | Required |
What you need before you start
- An Expo or bare React Native app on React 18.1.0 or 19.x.
- A FastPix playback ID. The stream URL is
https://stream.fastpix.com/{PLAYBACK_ID}.m3u8. - A development build if you're going anywhere near analytics, Picture-in-Picture or uploads.
expo-video is a two-export player API
You only need two of its exports to get a video on screen. useVideoPlayer creates the instance and takes a setup callback that runs once, and VideoView renders it. The package exports more than that, including picture-in-picture, audio-session and thumbnail helpers, but none of it is required to play a stream:
import { useVideoPlayer, VideoView } from "expo-video";
const player = useVideoPlayer(`https://stream.fastpix.com/${playbackId}.m3u8`, (player) => {
player.loop = false;
player.play();
});
<VideoView player={player} style={styles.video} contentFit="contain" allowsPictureInPicture nativeControls />Configuration in the setup callback stays out of the render body, which runs many times. Muting and volume are independent values, so unmuting restores the previous level rather than jumping to full.
Two absences catch people. expo-video draws no poster of its own, so you overlay an image and hide it once playback starts. Either onFirstFrameRender on VideoView or the player's playingChange event will do: both reflect actual playback rather than the request to play. And timeUpdate events are off by default, so set player.timeUpdateEventInterval in the setup callback or you'll wonder why nothing fires.
react-native-video is what third-party SDKs integrate with
The API is larger and the install is heavier, and neither is the reason to pick it. The reason is that it's what the ecosystem integrates with.
FastPix is a concrete example of that pattern rather than an exception to it. The React Native Video Data SDK is a higher-order component. It wraps a react-native-video component and returns an instrumented one:
import Video from "react-native-video";
import { fastpixReactNativeVideo } from "@fastpix/react-native-video-data";
const FastPixVideo = fastpixReactNativeVideo(Video);That wrapper needs the player's internal event stream. That's why it takes the component rather than a URL. There's no equivalent seam in expo-video, so the same pattern can't be applied to it. The wrapper's full prop surface is in monitor React Native.
You can try this against a real stream before committing to it. The free plan covers 10 videos and 100K streaming minutes a month with no credit card.
The instrumented component then needs three props. Most people miss them on the first attempt:
<FastPixVideo
source={{ uri: streamUrl }}
Platform={Platform} // mandatory
Dimensions={Dimensions} // mandatory
reportBandwidth={true} // required for bitrate and rendition metrics
fastpixData={{ data: { workspace_id: "WORKSPACE_ID", video_title: "...", video_id: "..." } }}
/>Platform and Dimensions are imported from react-native and passed in explicitly. The SDK uses them to compute device and render-quality metrics. Leaving reportBandwidth off means bitrate switching goes unrecorded, which quietly removes the render-quality half of your dashboard.
Why the FastPix React Native docs point at both players
Anyone integrating FastPix into React Native runs into this. The React Native quickstart builds its player on expo-video. The Video Data SDK requires react-native-video. Both are correct documents and they describe different destinations.
The quickstart optimises for time to first frame. expo-video installs in one command, plays in Expo Go, and gets a video on screen in a few minutes with no native build. That's the right choice for the first hour.
The Data SDK optimises for instrumentation, and instrumentation needs a seam to attach to. Once playback metrics are a requirement, the player choice is already made.
The practical consequence is a migration nobody warned you about. Follow the quickstart, then add analytics later, and you're swapping the player component rather than adding a package. Decide up front whether metrics are in scope, because deciding later costs a rewrite of every screen that plays video.
Choosing a React Native video player, in one question
Ask whether anything other than your own code needs to touch the player instance.
If the answer is no, and you're in Expo, expo-video is less to install, less to maintain and less to learn. A poster overlay and a timeUpdate interval you have to set are minor annoyances against a much smaller surface.
If the answer is yes, the specific integration usually names react-native-video in its own README, and arguing with that is a losing position. Analytics, DRM and ad insertion all cluster there.
If you land on react-native-video and see nothing render, why react-native-video shows no player covers the four causes. The Expo Go question is a tiebreaker rather than a decider, because the moment uploads enter the picture Expo Go is out anyway. The FastPix Uploads SDK depends on native modules that Expo Go doesn't carry. Uploading video from Expo Go doesn't work covers why.
Get a FastPix stream playing in your Expo app
Pick the player your analytics requirement implies, then point it at https://stream.fastpix.com/{PLAYBACK_ID}.m3u8 and you have adaptive playback on both platforms. If metrics are in scope, start on react-native-video and wrap it with fastpixReactNativeVideo on day one. The free plan covers 10 videos and 100K streaming minutes a month, no credit card. Try both players against a real stream before the choice gets expensive.
Frequently Asked Questions (FAQs)
Is expo-video better than react-native-video?
Neither is better at playback. Both wrap AVPlayer on iOS and ExoPlayer on Android, and those components do the decoding. expo-video is smaller, installs with one command, and runs in Expo Go for basic playback. react-native-video has the larger API and is what most third-party SDKs integrate against, which is usually what decides it.
Does expo-video support HLS?
Yes, with no configuration. The native players it wraps support HLS directly, so passing an https://stream.fastpix.com/{PLAYBACK_ID}.m3u8 URL to useVideoPlayer is the entire setup. Adaptive bitrate switching is handled by the OS player rather than by the library.
Can I add video analytics to expo-video?
Not with the FastPix React Native Video Data SDK. It is a higher-order component that wraps a react-native-video component and needs that player's internal event stream. expo-video exposes no equivalent seam. If playback metrics are a requirement, choose react-native-video before you build the screens.
Why does the FastPix quickstart use expo-video if the analytics SDK needs react-native-video?
Because they optimize for different things. The quickstart is built for time to first frame: one install command, works in Expo Go, and gets video on screen in minutes. The Data SDK is built for instrumentation and needs a player it can wrap. Decide whether metrics are in scope before you follow the quickstart, since switching later means replacing the player component everywhere.
Do I need a development build for either library?
For basic playback with expo-video, no. Expo Go is enough. You need a development build for Picture-in-Picture, for react-native-video at all, and for the FastPix Uploads SDK. All three depend on native modules Expo Go does not include.





