Skip to content

Deeplinking#

In order to make deeplinks fully work, you will need to do some platform specific setup. You can find more information in iOS and Android native documents.

Additional iOS Setup#

After setup is complete on the native side, to properly receive and forward deeplinks to JS module you need to add the following lines to your AppDelegate.mm file:

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
 options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
 return [RCTLinkingManager application:app openURL:url options:options];
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
 restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}

For further assistance, please refer to the official React Native documentation on deeplinks.

Note: iOS uses only universal links so there is no need for specifying URL schemes in Info.plist file.

Handling Navigation to Your App#

When users tap action buttons in stories that link to your app's custom URL scheme, you'll receive the userNavigatedToApp event. This is different from onUserActivityOccurred - while that event provides analytics data about user interactions, userNavigatedToApp gives you the actual URL to navigate to within your app.

userNavigatedToApp Event#

userNavigatedToApp: EventEmitter<{ url: string }>;

This event fires when:

  • A user taps an action button configured with your app's custom URL scheme (e.g., myapp://...)
  • The story content triggers navigation back to your app

Event Listener Example#

import { useEffect } from 'react';
import StorytellerSdk, { type UserNavigatedToAppEvent } from '@getstoryteller/react-native-storyteller-sdk';

function App() {
  useEffect(() => {
    const subscription = StorytellerSdk.userNavigatedToApp((event: UserNavigatedToAppEvent) => {
      // Parse and handle your app's URL scheme
      // Example: myapp://product/123
    });

    return () => {
      subscription.remove();
    };
  }, []);

  // rest of your component
}

URL Scheme Configuration#

To receive userNavigatedToApp events, action buttons in your stories must be configured with your app's custom URL scheme. This is typically set up in the Storyteller CMS when creating story content.

Example URL schemes:

  • myapp://product/123
  • myapp://category/shoes?sort=price
  • myapp://profile/user456
isStorytellerDeeplink(url: string): boolean;
isStorytellerDeeplink(url: string, callback: (result: Boolean) => void): void;

Checks if the given URL is a Storyteller deeplink. Returns true if the URL is a Storyteller deeplink, false otherwise.

openDeeplink(url: string): Promise<void>;
openDeeplink(url: string, callback: (result: boolean) => void): void;

Opens the provided Storyteller deeplink (showing the requested Page / Story / Clip). Returns a Promise that resolves when the deeplink is successfully opened, or rejects if it fails.

Parameters:

  • url - The deeplink URL to open

You can handle deeplinks when your app is in the foreground or background using React Native's Linking API combined with the Storyteller SDK methods.

Example Implementation#

import { useEffect } from 'react';
import { Linking } from 'react-native';
import StorytellerSdk from '@getstoryteller/react-native-storyteller-sdk';

function App() {
  useEffect(() => {
    // Handle deeplink when app is already running
    const handleDeepLink = async (event: { url: string }) => {
      if (StorytellerSdk.isStorytellerDeeplink(event.url)) {
        try {
          await StorytellerSdk.openDeeplink(event.url);
          console.log('Deeplink opened successfully');
        } catch (error) {
          console.error('Failed to open deeplink:', error);
        }
      }
    };

    // Subscribe to URL events
    const subscription = Linking.addEventListener('url', handleDeepLink);

    // Check for initial URL when app launches
    Linking.getInitialURL().then((url) => {
      if (url && StorytellerSdk.isStorytellerDeeplink(url)) {
        StorytellerSdk.openDeeplink(url).catch(console.error);
      }
    });

    return () => {
      subscription.remove();
    };
  }, []);

  return (
    // Your app content
  );
}
private ref?: Storyteller;

...
componentDidMount() {
    //deep link when app is running
    Linking.addEventListener('url', this._handleDeepLink);
    //deep link when app is not running
    AppState.addEventListener('change', this._handleAppStateChange);
}

componentWillUnmount() {
    Linking.removeEventListener('url', this._handleDeepLink);
    AppState.removeEventListener('change', this._handleAppStateChange);
}

_handleAppStateChange = async (_nextAppState: any) => {
    const url = await Linking.getInitialURL();
    if (url !== null && !this.state.didInit) {
        this.setState({ didInit: true });
        this._handleDeepLink({ url });
    }
};

_handleDeepLink = (event: { url: string }) => {
    if (this.ref) {
        StorytellerSdk.isStorytellerDeeplink('url', (result: Boolean) => {
            if (result) {
                this.ref.openDeeplink(event.url, (success) => {
                    console.log(success ? 
                        "Deeplink opened successfully" : 
                        "Failed to open deeplink"
                    );
                });
            }
        });
    }
};

...
render() {
    return (
        <StorytellerStoriesRowView
            ...
            ref={(ref) => {
                if (ref) this.ref = ref;
            }}
        />
    );
}