Livestream Quickstart
This tutorial builds a low-latency in-app livestreaming experience, broadcast over Stream's global edge network.
It comes in two parts:
Part 1 - Watch a livestream in a React Native app
- Create a livestream in the Stream dashboard
- Push video to it over RTMP with OBS
- Play it in a React Native app with
LivestreamPlayer - Replace that with a custom player you control
Part 2 - Broadcast from the phone
- Publish a livestream from a mobile device over WebRTC
- Use backstage and go-live to control when viewers can watch
This page works for both humans and AI coding agents: every step is a file operation or a shell command, every step has a verification checkpoint, and the few steps that need a human are explicitly marked.
Before you start. Part 1 needs OBS, a free desktop broadcaster, and runs fine in an emulator since the phone is only watching. Part 2 publishes camera video, so it needs a physical device. Want to skip OBS? Do Steps 3.1 and 3.2 to create the project and install the SDK, then jump straight to Step 4 and broadcast from the phone.
Choose your path
This tutorial has two paths. In Path A you let your AI agent build the app for you. In Path B you build it yourself, step by step. Both paths end with the same working livestream, so pick the one you prefer instead of working through both.
Path A - Let your AI agent build it (recommended)
Install the Stream CLI once, then add the skills. This gives Claude Code, Cursor, or Codex the React Native integration patterns and current SDK APIs, so it builds against real docs instead of stale training data.
1234567# Install the getstream CLI curl -fsSL https://getstream.io/cli.sh | bash # Install the skills (router, docs, and builder). The React Native pack # installs on demand the first time it's needed, or add it explicitly: getstream skills getstream skills stream-react-native
Then ask your agent:
12/stream-react-native Build a React Native livestreaming app that plays a livestream and can also broadcast from the device camera with a go-live button.
Where you come in. The agent handles credentials and code. It stops three times: getstream init opening your browser to sign in and pick an app (new accounts get an organization in that flow), the build to a device, and the camera and microphone prompt.
Want to get the sign-in out of the way first? Run getstream init before you prompt the agent - it picks up the initialized project from there.
Human checkpoint: build the app to a device if the agent hasn't, then allow camera and microphone access. Tapping Go Live should start a stream you can watch from a browser.
Skim Important Building Blocks if you want to understand what the agent wrote before you extend it.
Path B - Build it manually
Choose this path if you'd rather write the code yourself, or you want to understand what the SDK is doing before you hand it to an agent. Follow the steps below.
For AI assistants reading this page: append
.mdto any Stream docs URL for a clean Markdown version. A condensed index for the React Native Video SDK is athttps://getstream.io/video/docs/react-native/llms.txt. Prefer these over parsing HTML.
Important Building Blocks
Four pieces, one mental model:
StreamVideoClient- the low-level client. Holds the API key, the user, the token and the websocket connection to the Stream Video service.Call- one livestream, created withclient.call("livestream", id). The sameCallobject powers video calling and audio rooms; the call type is what changes the defaults.LivestreamPlayer- the drop-in viewer. Give it a call type and call id and it plays the stream.- Call state hooks -
useCallStateHooks()hands you the hooks (useParticipantCount,useIsCallLive,useLocalParticipant, and the rest) that drive a custom UI.
Backstage controls when viewers get in. A livestream call starts backstage so you can set up your camera before an audience arrives; call.goLive() opens it. Streams created from the dashboard go live immediately by default, and you can change either behavior per call type in the dashboard.
Step 1 - Create a livestream in the dashboard
First, let's create our livestream using the dashboard. To do this, open the dashboard and select "Video & Audio" -> "Overview".
In that screen, you will see three buttons that allow you to create different types of calls, as shown in the image below.

Click on the third one, the "Create Livestream" option. After you do this, you will be shown the following screen, which contains information about the livestream:

You will need the RTMP URL and RTMP Stream Key from this page, which are needed to setup the livestream in OBS software.
Copy these values for now, and we will get back to the dashboard a bit later.
Step 2 - Setup the livestream in OBS
OBS is one of the most popular livestreaming software packages and we'll use it to explain how to publish video with RTMP.
After you download and install the software using the instructions provided on the link, you should setup the capturing device and the livestream data.
First, let's setup the capturing device, which can be found in the sources section:

Select the "Video Capture Device" option to stream from your computer's camera. Alternatively, you can choose other options, such as "macOS Screen Capture," to stream your screen.
Next, we need to provide the livestream credentials from our dashboard to OBS. To do this, click on the "Settings" button located in the "Controls" section at the bottom right corner of OBS.

This will open a popup. Select the second option, "Stream". For the "Service" option, choose "Custom". In the "Server" and "Stream Key" fields, enter the values you copied from the dashboard in Step 1.

With that, our livestream setup is complete. Before returning to the dashboard, press the "Start Streaming" button in the "Controls" section.
Now, let's go back to the dashboard. If everything is set up correctly, you should see the OBS livestream in the dashboard, as shown in this screenshot:

By default the dashboard starts the livestream immediately. To change that, enable or disable backstage for the livestream call type.
Checkpoint: the dashboard shows your OBS video playing under the livestream.
Step 3 - Show the livestream in a React Native app
The livestream is running. Now build a React Native app to watch it.
Step 3.1 - Create a new React Native app
First, set up your React Native environment. Then generate a project called "LivestreamExample" with the React Native Community CLI:
12npx @react-native-community/cli@latest init LivestreamExample cd LivestreamExample
If you are having trouble with iOS, try to reinstall the dependencies by running:
cd iosto navigate to theiosfolderbundle installto install Bundlerbundle exec pod installto install the iOS dependencies managed by CocoaPods
Checkpoint: you have a LivestreamExample directory and yarn ios or yarn android builds the React Native starter screen.
Step 3.2 - Install the SDK and its dependencies
To install the Stream Video React Native SDK, run the following command in your terminal of choice:
1yarn add @stream-io/video-react-native-sdk @stream-io/react-native-webrtc
The SDK requires installing some peer dependencies. You can run the following command to install them:
123456yarn add react-native-svg yarn add @react-native-community/netinfo yarn add react-native-safe-area-context # Install pods for iOS npx pod-install
Android specific: update buildscript with required SDK versions
In android/build.gradle add the following inside the buildscript section:
1234567buildscript { ext { ... minSdkVersion = 24 } ... }
Step 3.3 - View a livestream on a React Native app
Now build the viewer that plays the stream you started above.
Open App.tsx and replace its contents with this code:
1234567891011121314151617181920212223242526import { SafeAreaProvider } from "react-native-safe-area-context"; import { LivestreamPlayer, StreamVideo, StreamVideoClient, User, } from "@stream-io/video-react-native-sdk"; const apiKey = "REPLACE_WITH_API_KEY"; const callId = "REPLACE_WITH_CALL_ID"; // Anonymous viewers need no token - watching a public livestream requires no // identity. Anonymous users don't open a websocket, so they receive no events; // they can watch and join, which is all a viewer needs. const user: User = { type: "anonymous" }; const client = new StreamVideoClient({ apiKey, user }); export default function App() { return ( <SafeAreaProvider> <StreamVideo client={client}> <LivestreamPlayer callType="livestream" callId={callId} /> </StreamVideo> </SafeAreaProvider> ); }
Before running the app, replace the placeholders with values from the dashboard:
apiKey- the API Key on your livestream pagetoken- the Viewer TokencallId- the Livestream ID

Why there is no token here. For anonymous users the token is optional, so a public viewer needs nothing but your API key and the call id. Don't pass the dashboard's Viewer Token to an anonymous user: that token is minted for a named user, and anonymous auth requires the
user_idclaim to be the literal!anon. Pairing the two fails at connect time with "anon auth token must have user_id claim equal to!anon".If you do want to restrict which livestreams an anonymous viewer can watch, mint a call-scoped anonymous token with one of the server-side SDKs and pass it as
token. It must carrycall_cids:json1234567{ "user_id": "!anon", "role": "viewer", "call_cids": ["livestream:<your-call-id>"], "iat": 1726406693, "exp": 1726493093 }Neither the dashboard's Viewer Token nor
getstream tokenproduces this shape -getstream token '!anon'would get theuser_idright but omitscall_cids, which the API requires. See Client & Authentication for guest and authenticated viewers.
That's everything. LivestreamPlayer plays a livestream given a call id and call type; there's nothing else to wire up.
Prefer the CLI?
curl -fsSL https://getstream.io/cli.sh | bash, thengetstream initto sign in and pick your app, andgetstream token <user-id>to mint a token against it. The dashboard values above are the quickest path for this step, since the livestream you created there already has them on screen.
Run the app:
12345# run iOS app yarn ios # run Android app yarn android
An emulator is fine here, since the phone is only watching. Part 2 publishes camera video and does need a physical device.
Checkpoint: the app plays the video you're broadcasting from OBS.
The LivestreamPlayer docs cover its options.
Step 3.4 - Customizing the UI
LivestreamPlayer gets you a viewer in one line. When you need a different look, build your own UI on top of the same SDK components and state layer.
State & Participants
For anything beyond the default - filtering participants, sorting them your own way - read the call state via call.state or the Call State Hooks.
Filtering is the common case. To get every participant with the host role:
12345import { useCallStateHooks } from "@stream-io/video-react-native-sdk"; const { useParticipants } = useCallStateHooks(); const participants = useParticipants(); const hosts = participants.filter((p) => p.roles.includes("host"));
The participant state docs list every available field.
For sorting, combine the comparators the SDK ships with, or write your own. A livestream-shaped example:
12345678910111213141516import { combineComparators, role, dominantSpeaker, speaking, publishingAudio, publishingVideo, } from "@stream-io/video-react-native-sdk"; const livestreamComparator = combineComparators( role("host", "speaker"), dominantSpeaker, speaking, publishingVideo, publishingAudio, );
That ordering puts hosts first, then whoever is speaking, then anyone publishing video and audio.
Apply it like this:
1234567import { useCallStateHooks } from "@stream-io/video-react-native-sdk"; const { useParticipants } = useCallStateHooks(); const sortedParticipants = useParticipants({ sortBy: livestreamComparator }); // alternatively, you can apply the comparator on the whole call: call.setSortParticipantsBy(livestreamComparator);
The participant sorting docs go deeper.
Now build a custom player that shows the livestream plus a live viewer count. Create CustomLivestreamPlayer.tsx:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192import React, { useEffect, useState } from "react"; import { View, Text, StyleSheet } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import { Call, combineComparators, publishingVideo, role, StreamCall, callManager, useCallStateHooks, useStreamVideoClient, VideoRenderer, } from "@stream-io/video-react-native-sdk"; // Prioritize the host (and anyone publishing video) so the broadcaster's // stream is the participant we render, reusing the comparators shown above. const livestreamComparator = combineComparators( role("host", "speaker"), publishingVideo, ); export const CustomLivestreamPlayer = (props: { callType: string; callId: string; }) => { const { callType, callId } = props; const client = useStreamVideoClient(); const [call, setCall] = useState<Call>(); useEffect(() => { if (!client) return; const myCall = client.call(callType, callId); setCall(myCall); myCall.join().catch((e) => { console.error("Failed to join call", e); }); return () => { myCall.leave().catch((e) => { console.error("Failed to leave call", e); }); setCall(undefined); }; }, [callId, callType, client]); if (!call) return null; return ( <StreamCall call={call}> <CustomLivestreamLayout /> </StreamCall> ); }; const CustomLivestreamLayout = () => { const { useParticipants, useParticipantCount } = useCallStateHooks(); const participantCount = useParticipantCount(); const [firstParticipant] = useParticipants({ sortBy: livestreamComparator }); useEffect(() => { // Automatically route audio to speaker devices as relevant for watching videos callManager.start({ audioRole: "listener" }); return () => callManager.stop(); }, []); return ( <SafeAreaView style={styles.flexed}> <Text style={styles.text}>Live: {participantCount}</Text> <View style={styles.flexed}> {firstParticipant ? ( <VideoRenderer participant={firstParticipant} /> ) : ( <Text style={styles.text}>The host hasn't joined yet</Text> )} </View> </SafeAreaView> ); }; const styles = StyleSheet.create({ flexed: { flex: 1, backgroundColor: "white", }, text: { alignSelf: "center", color: "white", backgroundColor: "blue", padding: 6, margin: 4, }, });
The comparator picks the host out of the call state and VideoRenderer draws their stream, or a placeholder if nobody is publishing. useParticipantCount() drives the viewer label. The useEffect joins on mount and leaves on unmount - in a real app you'd hang those off explicit buttons.
Swap LivestreamPlayer for CustomLivestreamPlayer in App:
123456789101112// ... the rest of the code import { CustomLivestreamPlayer } from "./CustomLivestreamPlayer"; export default function App() { return ( <SafeAreaProvider> <StreamVideo client={client}> <CustomLivestreamPlayer callType="livestream" callId={callId} /> </StreamVideo> </SafeAreaProvider> ); }
Checkpoint: the custom player shows the OBS video with a Live: <n> label above it.
Part 2 - Build your own Youtube Live
Part 1 published over RTMP and authenticated through the dashboard. In a real application you'd mint tokens programmatically with a server-side SDK.
Part 2 drops OBS entirely and broadcasts from the phone.
Step 4 - Live streaming from a React Native app
Now send video straight from the app over WebRTC, with backstage controlling when viewers get in. This part publishes camera video, so it needs a real Android or iOS device.
Step 4.1 - Permissions setup
Publishing needs camera and microphone access, which starts with declaring the permissions in your app.
In AndroidManifest.xml add the following permissions before the application section.
1234567891011121314151617<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-feature android:name="android.hardware.audio.output" /> <uses-feature android:name="android.hardware.microphone" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.INTERNET" /> ... <application ...> ... </application> </manifest>
Add the following keys and values to Info.plist file, under dict tag.
123456789101112<plist version="1.0"> <dict> ... <key>CFBundleName</key> <string>$(PRODUCT_NAME)</string> <key>NSCameraUsageDescription</key> <string>$(PRODUCT_NAME) needs camera access for broadcasting</string> <key>NSMicrophoneUsageDescription</key> <string>$(PRODUCT_NAME) requires microphone access in order to capture and transmit audio</string> ... </dict> </plist>
Step 4.2 - Broadcasting a livestream
Replace the viewer code in App.tsx with the following (or start a fresh project using the same setup steps). This step gets the broadcast connected; Step 4.3 renders the video.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455import React from "react"; import { StreamVideoClient, StreamVideo, User, StreamCall, } from "@stream-io/video-react-native-sdk"; import { Text, StyleSheet } from "react-native"; import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context"; const apiKey = "REPLACE_WITH_API_KEY"; const token = "REPLACE_WITH_TOKEN"; const userId = "REPLACE_WITH_USER_ID"; const callId = "REPLACE_WITH_CALL_ID"; const user: User = { id: userId, name: "Tutorial" }; const client = new StreamVideoClient({ apiKey, user, token }); const call = client.call("livestream", callId); // The `livestream` call type ships with the mic off by default, so enable it // explicitly - otherwise you go live with video but no audio, and nothing // tells you. Enabling it is also what triggers the microphone permission // prompt on first run. call.join({ create: true }).then(() => { call.camera.enable(); call.microphone.enable(); }); export default function App() { return ( <SafeAreaProvider> <StreamVideo client={client} language="en"> <StreamCall call={call}> <SafeAreaView style={styles.container}> <LivestreamView /> </SafeAreaView> </StreamCall> </StreamVideo> </SafeAreaProvider> ); } const LivestreamView = () => ( <Text style={styles.text}>TODO: render video</Text> ); const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "white", }, text: { fontSize: 30, color: "black", }, });
Run the app and you'll see "TODO: render video" - a placeholder you replace in Step 4.3. It confirms the app builds and launches, but be aware it renders regardless of whether the call actually joined: LivestreamView reads no call state, and call.join() above is not awaited, so a failure surfaces only in the console.
Checkpoint: the app shows "TODO: render video", and the Metro console shows no error from join(). Watch specifically for a 403 - that means the call id already exists under a different owner, and you should pick a new one. In a release build the error would be invisible, so check it now.
Here's what that code did. First, the user:
123import type { User } from "@stream-io/video-react-native-sdk"; const user: User = { id: userId, name: "Tutorial" };
Then the client:
123import { StreamVideoClient } from "@stream-io/video-react-native-sdk"; const client = new StreamVideoClient({ apiKey, user, token });
Your backend normally generates that token when the user signs up or signs in.
The call is the part worth dwelling on. The SDK uses the same Call object for livestreaming, audio rooms and video calling:
12345const call = client.call("livestream", callId); call.join({ create: true }).then(() => { call.camera.enable(); call.microphone.enable(); });
Pass the call type livestream and a callId. That call type ships with sensible livestream defaults, and you can retune its features, permissions and settings - or add new call types - in the dashboard.
call.join({ create: true }) does two things: it creates the call on our servers and opens the realtime transport for audio and video.
You can also add members to a call and give them roles; see the call creation docs.
Step 4.3 - Rendering the video
Now show your local video with a button to start the livestream.
Replace the placeholder LivestreamView in App.tsx with the implementation below, along with the imports it needs. Here's the complete App.tsx at this point:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101import React, { useEffect } from "react"; import { StreamVideoClient, StreamVideo, User, StreamCall, callManager, useCall, useCallStateHooks, VideoRenderer, } from "@stream-io/video-react-native-sdk"; import { View, Button, Text, StyleSheet } from "react-native"; import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context"; const apiKey = "REPLACE_WITH_API_KEY"; const token = "REPLACE_WITH_TOKEN"; const userId = "REPLACE_WITH_USER_ID"; const callId = "REPLACE_WITH_CALL_ID"; const user: User = { id: userId, name: "Tutorial" }; const client = new StreamVideoClient({ apiKey, user, token }); const call = client.call("livestream", callId); call.join({ create: true }).then(() => { call.camera.enable(); call.microphone.enable(); }); export default function App() { return ( <SafeAreaProvider> <StreamVideo client={client} language="en"> <StreamCall call={call}> <SafeAreaView style={styles.container}> <LivestreamView /> </SafeAreaView> </StreamCall> </StreamVideo> </SafeAreaProvider> ); } const LivestreamView = () => { const { useParticipantCount, useLocalParticipant, useIsCallLive } = useCallStateHooks(); const call = useCall(); const totalParticipants = useParticipantCount(); const localParticipant = useLocalParticipant(); const isCallLive = useIsCallLive(); // Automatically route audio to speaker devices as relevant for watching videos. useEffect(() => { callManager.start({ audioRole: "communicator", deviceEndpointType: "speaker", }); return () => callManager.stop(); }, []); return ( <View style={styles.flexed}> <Text style={styles.text}>Live: {totalParticipants}</Text> <View style={styles.flexed}> {localParticipant && ( <VideoRenderer participant={localParticipant} trackType="videoTrack" /> )} </View> <View style={styles.bottomBar}> {isCallLive ? ( <Button onPress={() => call?.stopLive()} title="Stop Live" /> ) : ( <Button onPress={() => call?.goLive()} title="Go Live" /> )} </View> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "white", }, flexed: { flex: 1, }, text: { alignSelf: "center", color: "white", backgroundColor: "blue", padding: 6, margin: 4, }, bottomBar: { alignSelf: "center", margin: 4, }, });
Human checkpoint: the device asks for camera and microphone access the first time - allow both. Agents: build and launch, then ask the human to grant access and confirm their own camera preview renders.
Step 5 - Backstage and GoLive
Backstage lets you and your co-hosts set up camera and equipment before anyone can watch. Viewers can only join after you call call.goLive().
If you'd rather calls start the moment you join them, open the Stream dashboard, find the livestream call type and disable backstage.
Step 6 - Preview the livestream
The React Native docs cover running on a device. Press Go live in the app and you'll get this:

Click below to watch yourself as a viewer in the browser. The link points at the call id from the snippets above.
Checkpoint: the button reads Stop Live, your camera preview is on the device, and the browser tab plays your stream a moment later.
This is the payoff: you're broadcasting live from a phone to anyone with the link. On the shared tutorial credentials? Create your own Stream app - the free maker plan covers hobby projects.
Verify the whole build
Build to your device and run the full loop: allow camera and microphone, see your own preview, tap Go Live, then open the browser viewer and watch your stream arrive. Tap Stop Live and confirm the viewer drops out.
Troubleshooting
token is invalid/ auth error - the token was minted for a different app, or it expired. Re-mint withgetstream token <user-id>and confirm the API key matches.project credentials missing- the CLI has not been initialized here. Rungetstream initin the project directory first.- Viewer shows a black screen, or "The host hasn't joined yet" - OBS stopped streaming, or the API key, viewer token and livestream id came from different dashboard pages.
- OBS connects but the dashboard shows nothing - the Server and Stream Key must match the dashboard's
RTMP URLandRTMP Stream Keyexactly, and Service must be set to Custom. - No camera preview in Part 2 - you're on an emulator. Emulators have no camera; build to a physical device.
- Camera and mic permission prompts never appear - the usage description keys are missing from
Info.plist, or the permissions are missing fromAndroidManifest.xml(Step 4.1). goLive()does nothing - the user lacks permission on that call type, or the call was already live. Check the console.- Viewers can't join even though you're live - backstage is still on for the call type and
goLive()never succeeded. - iOS build fails to find a pod - run
bundle installthenbundle exec pod installfrom theiosfolder, ornpx pod-installfrom the project root. - Android build fails on minSdkVersion - set
minSdkVersion = 24in thebuildscript.extblock ofandroid/build.gradle.
Advanced Features
This tutorial covered watching a livestream over RTMP-in with OBS, and publishing one from a device.
There are several advanced features that can improve the livestreaming experience:
- Co-hosts You can add members to your livestream with elevated permissions. So you can have co-hosts, moderators etc. You can see how to render multiple video tracks in our video calling tutorial.
- Permissions and Moderation You can set up different types of permissions for different types of users and a request-based approach for granting additional access.
- Custom events You can use custom events on the call to share any additional data. Think about showing the score for a game, or any other realtime use case.
- Reactions & Chat Users can react to the livestream, and you can add chat. This makes for a more engaging experience.
- Notifications You can notify users via push notifications when the livestream starts
- Recording The call recording functionality allows you to record the call with various options and layouts
- HLS Another way to watch a livestream is using HLS. HLS tends to have a 10 to 20 seconds delay, while the WebRTC approach is realtime. The benefit that HLS offers is better buffering under poor network conditions.
Recap
It was fun to see just how quickly you can build in-app low latency livestreaming. Please do let us know if you run into any issues. Our team is also happy to review your UI designs and offer recommendations on how to achieve them with Stream Video SDKs.
To recap what we've learned:
- WebRTC is optimal for latency, HLS is slower but buffers better for users with poor connections
- You set up a call:
const call = client.call("livestream", callId) - The call type
livestreamcontrols which features are enabled and how permissions are set up - When you join a call, realtime communication is set up for audio & video:
call.join() - Call State Hooks make it easy to build your own UI
- You can easily publish your own video and audio from a React Native app on a mobile device
Calls run on Stream's global-edge network of video servers. Being closer to your users improves the latency and reliability of calls.
The SDKs enable you to build livestreaming, audio rooms and video calling in days.
We hope you've enjoyed this tutorial and please do feel free to reach out if you have any suggestions or questions.
Next steps
- Video calling - the same
Callobject, two-way: React Native Video Calling tutorial - Audio rooms - a Clubhouse-style experience with backstage and raised hands: React Native Audio Room tutorial
- Ringing - make calls ring on the recipient's device: React Native Ringing tutorial
- Chat alongside your stream - the Chat React Native SDK drops into the same app
- Recording and HLS - recording and broadcasting
Pricing is flexible with multiple tiers, including a free maker plan for hobby projects and small companies.
Final Thoughts
In this video app tutorial we built a fully functioning React Native video app with our React Native SDK component library. We also showed how easy it is to customize the behavior and the style of the React Native video app components with minimal code changes.
Both the video SDK for React Native and the API have plenty more features available to support more advanced use-cases.
Machine-readable resources
For AI agents and coding assistants working with this SDK:
- CLI + skills:
curl -fsSL https://getstream.io/cli.sh | bash, thengetstream skillsandgetstream skills stream-react-nativefor the React Native pack. (Alternative:npx skills add GetStream/agent-skills -s stream.) - Provisioning:
getstream init(auth + create/select org & app) ->getstream token <user-id>(mint a token).getstream env --target <expo|ios|android>writes keys into a project file where the platform has a convention for it. - Data & config from the CLI:
getstream api <Endpoint> --request '{...}'for users, calls, and call members - React Native integration skill: invoke
/stream-react-nativein your agent for React Native and Expo setup patterns;/stream-docssearches live SDK docs with citations - Docs index for LLMs:
https://getstream.io/video/docs/react-native/llms.txt - Markdown endpoints: append
.mdto any docs URL for a clean, token-efficient version - Source of truth for APIs: the SDK repository - check the installed version's source rather than assuming APIs from training data

