Skip to content

React Native with New Architecture (v11.0.0+)#

This guide covers Storyteller SDK v11.0.0 and higher, which uses React Native’s New Architecture. The current 12.x package requires Android API 24 or later and iOS 15.1 or later. Before integrating v12, apply the Android host requirements; enabling the New Architecture alone does not satisfy those build requirements.

Verify New Architecture is Enabled#

Android#

Check your android/gradle.properties file contains:

newArchEnabled=true

iOS#

Check your ios/Podfile file contains:

ENV['RCT_NEW_ARCH_ENABLED'] = '1'

Note: React Native 0.76 and above have the New Architecture enabled by default.

Installation#

Install the SDK using npm or yarn:

npm install @getstoryteller/react-native-storyteller-sdk

or

yarn add @getstoryteller/react-native-storyteller-sdk

Android Configuration#

The Storyteller Android SDK artifacts are published to Maven Central. Most React Native projects include mavenCentral() by default. If your project has a custom repository setup, make sure mavenCentral() is available in your android/build.gradle file:

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

iOS Configuration#

  1. Add the following sources to the top of your ios/Podfile:
source 'https://cdn.cocoapods.org/'
source 'https://github.com/getstoryteller/storyteller-lottie-ios-podspec.git'
source 'https://github.com/getstoryteller/storyteller-sdk-ios-podspec.git'
  1. Install the native dependencies:
cd ios && pod install

Basic Implementation#

Initialize the SDK (Promise-based API)#

Await initialization before mounting content, then request the list data through its ref. Replace the API key and category ID below with values for your tenant. This complete example keeps initialization errors separate from content-load errors and prevents concurrent initialization calls for the same attempt.

import React, { useEffect, useRef, useState } from 'react';
import { ActivityIndicator, Button, Text, View } from 'react-native';
import StorytellerSdk, {
  StorytellerStoriesRowView,
  type StorytellerStoriesRowViewInterface,
} from '@getstoryteller/react-native-storyteller-sdk';

let initialization: Promise<void> | undefined;

function initializeStoryteller(): Promise<void> {
  if (!initialization) {
    initialization = StorytellerSdk.initialize('YOUR_API_KEY').catch(error => {
      initialization = undefined;
      throw error;
    });
  }
  return initialization;
}

function Stories() {
  const rowRef = useRef<StorytellerStoriesRowViewInterface>(null);
  const [loading, setLoading] = useState(true);
  const [message, setMessage] = useState('');

  useEffect(() => {
    rowRef.current?.reloadData();
  }, []);

  return (
    <View>
      {loading && <ActivityIndicator />}
      {message !== '' && <Text>{message}</Text>}
      <StorytellerStoriesRowView
        ref={rowRef}
        configuration={{ categories: ['YOUR_CATEGORY_ID'] }}
        style={{ height: 200 }}
        onDataLoadStarted={() => {
          setLoading(true);
          setMessage('');
        }}
        onDataLoadCompleted={({ success, error, dataCount }) => {
          setLoading(false);
          setMessage(success ? (dataCount === 0 ? 'No stories available.' : '') : error);
        }}
      />
      <Button title="Reload stories" onPress={() => rowRef.current?.reloadData()} />
    </View>
  );
}

export default function App() {
  const [ready, setReady] = useState(false);
  const [error, setError] = useState('');
  const [attempt, setAttempt] = useState(0);

  useEffect(() => {
    let active = true;
    initializeStoryteller().then(
      () => {
        if (active) setReady(true);
      },
      (failure: unknown) => {
        if (active) setError(String(failure));
      },
    );
    return () => {
      active = false;
    };
  }, [attempt]);

  if (error !== '') {
    return (
      <View style={{ flex: 1, justifyContent: 'center' }}>
        <Text>Storyteller initialization failed: {error}</Text>
        <Button
          title="Retry"
          onPress={() => {
            setError('');
            setAttempt(value => value + 1);
          }}
        />
      </View>
    );
  }

  return <View style={{ flex: 1 }}>{ready ? <Stories /> : <ActivityIndicator />}</View>;
}

The initialization Promise confirms SDK readiness. onDataLoadCompleted confirms the list’s content-load result; a successful load with dataCount: 0 is an empty response. These callbacks do not confirm video playback or player presentation. Give rows a height, scrollable grids a bounded height and non-scrollable grids a measurable width; see List Components.

For signed-in users, pass a stable externalId and serialize user changes as described in Working with Users. Subscribe to SDK events before opening content, and remove subscriptions when their owner unmounts.

Next Steps#

Support#