Upgrade to v2
v2 of the React Native SDK is in beta. This page tracks what you have to change when moving from v1: new minimum versions, the removal of APIs that were deprecated in v1, a leaner Expo config plugin, a translation layer change that affects you only if you translated the SDK, and a client layer that is now generated from the OpenAPI spec.
Install the beta
v2 publishes to the beta npm tag. v1 keeps latest, so an unpinned install stays on v1.
yarn add @stream-io/video-react-native-sdk@betaThe optional native packages are on their own beta line and need the tag too:
yarn add @stream-io/noise-cancellation-react-native@beta
yarn add @stream-io/video-filters-react-native@beta
yarn add @stream-io/react-native-callingx@betaInstalling the latest build of any of those alongside the v2 beta pulls the v1 line and
reports an unmet peer dependency. That is the most common way to get a confusing install
error while trying the beta.
@stream-io/react-native-webrtc is versioned independently and is not part of this split,
so it has no beta tag. Install it without one.
What has changed so far
The 2.0 major was opened so the v2 line could release independently of v1. Since then it has raised its minimum versions, removed APIs that were deprecated in v1, moved translations to a shared runtime, and moved the client's coordinator calls onto generated OpenAPI code. Each is covered below.
The design-token work currently landing in the React SDK does not touch React Native theming, which has its own theme layer.
Translations moved to a shared runtime
The SDK now uses @stream-io/i18n, the
translation runtime shared with Stream Chat, and translation keys are namespaced
identifiers instead of the English text:
t("Incoming Call..."); // v1
t("ringingCall.incoming.title", "Incoming Call..."); // v2The second argument is the English copy, written at the call site. That is why the SDK no
longer ships an en.json or a translations export: a key missing from your dictionary
renders that inline English rather than a raw key.
If you never touched i18n, there is nothing to do. English is unchanged - every string renders exactly as it did in v1.
If you did translate the SDK
Re-keying is not optional, and it fails quietly. An old key never matches, so your override
silently stops applying and the SDK's English renders instead - no error, no warning,
nothing in the console. Type your dictionaries as TranslationDictionary to turn that into
a compile error.
| Removed | Replacement |
|---|---|
translationsOverrides |
translations - registers over the defaults instead of replacing |
fallbackLanguage |
removed - use i18nextConfigOverrides: { fallbackLng } |
StreamI18n |
Streami18n - different class, different options |
StreamI18nProvider |
removed - StreamVideo mounts the translation context |
TranslationsMap |
Record<string, LooseTranslationDictionary> |
TranslationLanguage, TranslatorFunction |
removed - use string and StreamTFunction |
the translations export, en.json |
removed - English is inline at each call site |
useI18n().i18n |
removed - useI18n() returns { t, tDateTimeParser } |
The old-to-new key mapping is published as
i18n-2.0-key-map.json
in the SDK repository, split by platform - use the reactNative half. Most rows are a
straight rename; a handful are not, and those carry a note explaining what to do.
Note that translationsOverrides replaced the SDK's dictionary in v1 rather than
merging with it, so supplying one German string dropped the rest. If you worked around that
by spreading the SDK's translations.en back into yours, delete the spread - translations
merges, and a partial dictionary is safe.
The i18n guide covers the new API in full.
The client layer is generated from OpenAPI
The client's coordinator calls are generated from the OpenAPI spec in v2. The SDK's own components and hooks were updated; what follows affects only code that calls the client or reads API responses directly.
Dates from the API are numbers now
Every date the server sends is a unix-nanosecond number instead of an ISO string, in
responses and in WebSocket events alike.
// v1
const startedAt = new Date(session.live_started_at);
// v2
import { convertTimestampToDate } from "@stream-io/video-react-native-sdk";
const startedAt = convertTimestampToDate(session.live_started_at);This does not throw. A nanosecond timestamp is outside the range Date accepts, so
new Date(...) returns an Invalid Date and .getTime() on it is NaN - which surfaces
as a blank timestamp or a NaN duration in your UI, with nothing in the console.
TypeScript catches new Date(timestamp).getTime() and other Date methods, but not
new Date(timestamp) on its own or .toLocaleString() on the result.
Values from call state hooks such as useCallCreatedAt() and useCallStartsAt() are still
Date objects, so there is nothing to wrap there.
Dates you send are still Date, which makes them not round-trippable: passing a
timestamp read from a response straight back into a request is a compile error in
TypeScript, and a 400 from the API in plain JavaScript. Convert it with nsToDate()
first.
Methods that changed
Several call and client methods now take a single object instead of positional arguments:
startRecording, stopRecording, blockUser, unblockUser, reject, getRingState,
stopRTMPBroadcast, deleteRecording, deleteTranscription, getCallReport,
getCallStatsMap, submitFeedback, queryParticipants, addDevice, addVoipDevice and
removeDevice. For example, call.blockUser("jane") becomes
call.blockUser({ user_id: "jane" }). TypeScript flags each of them.
If you register push devices yourself with client.addDevice() or
client.addVoipDevice(), pass an object: { id, push_provider, push_provider_name }.
The JavaScript upgrade guide has the full
table, along with the rest of the client changes: the baseURL suffix, the removed
*Enum exports, typed query filters, the metadata envelope on responses, the removed
streamClient request helpers and the axiosRequestConfig precedence change.
New minimum versions
| Requirement | v2 |
|---|---|
| React Native | 0.79 or newer |
| React | 18 or newer |
| Expo | SDK 53 or newer |
@react-native-firebase/* |
23 or newer |
| iOS | 15.1 or newer |
The iOS deployment target now follows React Native's own minimum.
Removed APIs
These were deprecated in v1, or never did anything, and are gone in v2. TypeScript flags
each of them, except StreamVideoReactNative.setup(), which fails the native build.
| Removed | Replacement |
|---|---|
logger and logLevel client options |
logOptions: { default: { level, sink } } |
call.publishVideoStream(), call.publishAudioStream(), call.publishScreenShareStream() |
call.publish(stream, TrackType.VIDEO) (or TrackType.AUDIO, TrackType.SCREEN_SHARE) |
secret and allowServerSideConnect client options |
Use @stream-io/node-sdk for server-side work |
ThemeProvider, ThemeProviderInputValue |
StreamTheme, StreamThemeInputValue |
push.isExpo in StreamVideoRN.setPushConfig() |
Remove it. Expo is detected automatically |
firebaseDataHandler() |
Remove the call. The SDK handles ring pushes natively |
size prop on CallControlsButton, HangUpCallButton and RejectCallButton |
style.container (width, height, borderRadius) |
ResolvedStreams type |
LoopbackTracks |
CallContent's initialInCallManagerAudioMode prop |
callManager.start({ audioRole, deviceEndpointType }) |
useAndroidKeepCallAliveEffect, useScreenShareAudioMixing, usePushRegisterEffect |
Nothing to call. StreamVideo and StreamCall already run them |
StreamVideoReactNative.setup() (Android and iOS) |
Remove the call from MainApplication and AppDelegate. It did nothing |
react-native-incall-manager is no longer used
v1 still started react-native-incall-manager alongside its own audio handling if your app
had it installed. v2 doesn't: the SDK's call manager owns audio routing. Uninstall the
library and configure audio with callManager.
Expo config plugin
The plugin now targets the Swift AppDelegate and the Kotlin MainActivity and
MainApplication that Expo SDK 53 and later generate. If your project still has an
Objective-C AppDelegate or Java Android files, prebuild fails with an error that names
the file to migrate. The plugin also no longer adds a compileOptions block to
android/app/build.gradle.
What to expect during the beta
Breaking changes land incrementally rather than all at once, so treat this page as the running list and re-read it when you bump. Each entry will name the version it landed in and the change you have to make.
If you hit something that behaves differently and is not listed here, that is worth reporting: an unlisted break is a bug in this page as much as in the SDK.
Staying on v1
v1 is maintained on its own release line and stays on the latest tag. If you are not
ready to move, pin @stream-io/video-react-native-sdk@latest and switch this page to v1
with the version picker above. The per-version upgrade guides for the 1.x line live there.