Web video analytics attaches to an element. You add metadata-workspace-key to a player tag and the SDK reads the element's event stream from there. React Native has no elements and no DOM, so there's nothing to attach to. Instrumentation instead wraps your player component and returns a new one. That sounds like a detail. It's the constraint that decides which player library your app can use.
TL;DR
fastpixReactNativeVideo is a higher-order component: it takes your react-native-video component and returns an instrumented one, so there's no manual event tracking. That also means expo-video can't be used, because it exposes no equivalent seam. Three props are easy to miss, and each costs a category of metric. Platform and Dimensions come from react-native, because there's no window for the SDK to read device facts from. reportBandwidth={true} is the third, and without it bitrate and rendition data silently never arrives. workspace_id is the only strictly required field.
Why React Native video analytics wraps your player
fastpixReactNativeVideo is a higher-order component. It takes a react-native-video component and returns an instrumented version:
import Video from "react-native-video";
import { fastpixReactNativeVideo } from "@fastpix/react-native-video-data";
const FastPixVideo = fastpixReactNativeVideo(Video);That wrapping lets the SDK observe load, play, pause, seek, buffer and error events. You write no tracking calls at all. It also means the SDK needs a player whose event surface it knows.
expo-video doesn't expose an equivalent seam, so the same pattern can't be applied to it. If analytics is a requirement, the player decision is already made, and it's made before any screen gets built. The tradeoff between the two libraries is in expo-video vs react-native-video in 2026.
| Platform | How instrumentation attaches | What it needs |
|---|---|---|
| Web player | An attribute on the element | metadata-workspace-key |
| React Native | A higher-order component around your player | react-native-video, plus three props |
What you need before you start
- React 18.1.0 or 19.x, and React Native 0.72.0 or higher.
react-native-videoinstalled and working, since the SDK builds on top of it.- A FastPix Workspace key from set up a workspace, which isn't the same value as your Access Token ID.
Three props React Native analytics needs that the web does not
The instrumented component takes your normal video props plus a fastpixData object. Three of them are easy to miss, and each one costs a category of metric:
import { Platform, Dimensions } from "react-native";
<FastPixVideo
source={{ uri: `https://stream.fastpix.com/${playbackId}.m3u8` }}
controls
style={{ width: "100%", aspectRatio: 16 / 9 }}
Platform={Platform} // mandatory
Dimensions={Dimensions} // mandatory
reportBandwidth={true} // required for bitrate and rendition metrics
fastpixData={{
data: {
workspace_id: "WORKSPACE_ID", // required
video_title: "Onboarding part 1",
video_id: "vid_001",
viewer_id: "user_12345",
video_stream_type: "on-demand",
player_name: "react-native-video",
},
}}
/>Platform and Dimensions are imported from react-native and passed in explicitly. A browser SDK reads the equivalent facts off window and navigator. React Native has neither, so the SDK can't reach them on its own. Leave them out and device breakdowns and render-quality metrics have nothing to compute from.
reportBandwidth is off by default, and leaving it off silently removes bitrate switching and rendition data from your dashboard. Nothing errors. The charts are just empty in one section. That's the worst kind of missing telemetry, because it looks like a product with no quality problems.
workspace_id is the only genuinely required field. Without it the events have nowhere to land. Every accepted field is listed in monitor React Native.
You can run this against a real upload before committing to it. The free plan covers 10 videos and 100K streaming minutes a month with no credit card.
Viewer ID tracking has two strategies, pick deliberately
The SDK can manage viewer IDs or defer to yours, and the choice affects what your unique-viewer numbers mean.
If your app already has sessions, pass your own viewer_id and set shouldTrackViewer={false}. Your analytics then joins cleanly to your own user table. That's what you want if you ever have to answer a question about a specific account.
If you have no session concept, set shouldTrackViewer={true}. The SDK then generates an ID and persists it with AsyncStorage, which you install yourself so the generated ID survives app restarts:
npm install @react-native-async-storage/async-storageThen rebuild the native app. Adding that package changes the binary, exactly as it does for the Uploads SDK in Expo Go. ./gradlew clean && ./gradlew build on Android, cd ios && pod install on iOS. Reloading the JavaScript bundle isn't enough, for the same reason covered in uploading video from Expo Go doesn't work.
Without persistent storage, the generated ID resets whenever the app restarts, and every returning viewer counts as a new one. That inflates unique viewers and destroys retention analysis, quietly.
What mobile playback metrics mean differently
The metric names carry over from the web. What they mean doesn't, because the conditions are different.
Startup time on a phone includes cellular negotiation and often a cold app launch, so the distribution is wider and the tail is longer. A number that would indicate a CDN problem on desktop can be ordinary on a commute.
Rebuffering correlates with movement rather than with your encoding ladder. Viewers on trains and in lifts produce buffer events that no bitrate decision of yours will fix. That's why the rendition data from reportBandwidth matters. It separates "the network was bad" from "we served a rendition the connection couldn't sustain".
Render quality has a mobile-specific failure that doesn't exist on desktop. Serving 1080p to a 5.4 inch screen burns the viewer's data for detail they can't perceive. Dimensions is what lets the dashboard show you that you're doing it.
The full metric catalogue is in understand data definitions.
Custom dimensions for React Native video analytics
The named fields cover the general case. custom_1 through custom_10 cover yours.
Pass the dimension your product actually segments on: the course ID, the creator tier, the experiment arm, whether the viewer was on a trial. Those are the fields that turn a QoE dashboard into an answer about which cohort is being underserved.
Fill them at integration time rather than later. Metadata is attached at playback and can't be backfilled, so a field you add next quarter has no history behind it.
Start collecting playback metrics from your app
Wrap your react-native-video component with fastpixReactNativeVideo, pass workspace_id, Platform, Dimensions and reportBandwidth={true}, and data starts arriving as soon as playback begins. Decide your custom dimensions in the same sitting, since they can't be backfilled. The free plan covers 10 videos and 100K streaming minutes a month, no credit card. Watch real sessions from a real device arrive in the dashboard before anything ships.
Frequently Asked Questions (FAQs)
How do I add video analytics to a React Native app?
Install @fastpix/react-native-video-data. Wrap your react-native-video component with fastpixReactNativeVideo and render the result instead of the original. Pass workspace_id inside fastpixData.data, along with Platform and Dimensions from React Native. No manual event tracking is needed after that, because the wrapper observes the player's own events.
Can I use the FastPix Video Data SDK with expo-video?
No. The SDK is a higher-order component that wraps a react-native-video component and needs that player's internal event stream, while expo-video exposes no equivalent seam. If playback metrics are in scope, choose react-native-video before building the screens, because switching later means replacing the player everywhere.
Why do I have to pass Platform and Dimensions?
Because React Native has no window or navigator. The SDK cannot read device and viewport facts on its own. A browser SDK gets them for free; this one has to be handed them. Omitting them leaves device breakdowns and render-quality metrics with nothing to compute from, and nothing errors to tell you.
Why is bitrate data missing from my dashboard?
Almost certainly because reportBandwidth was left at its default of false. It is what enables tracking of bitrate switching and rendition changes for adaptive streams. Nothing fails without it, so the symptom is an empty section rather than an error.
Should I let the SDK generate viewer IDs?
Only if your app has no session concept. Passing your own viewer_id with shouldTrackViewer={false} joins the analytics to your user table. If you do let the SDK generate them, install AsyncStorage and rebuild the native app, because AsyncStorage ships native code. Without it, the ID resets on every restart, and every returning viewer counts as new.






