Skip to main content

Table of Contents

  1. Overview
  2. Basic Setup
  3. Screen-Based Visibility
  4. Global Delay
  5. Advanced: Visibility Groups
  6. Insets (Button Position)
  7. Complete Examples
  8. Field Reference
  9. Practical Scenarios
  10. Troubleshooting
  11. Summary

Overview

EmbedProvider wraps your app and:
  • Listens to React Navigation state and shows/hides the EmbedButton by screen.
  • Supports visibility groups: per-group delay, continuity, and inset.
  • Enriches analytics with screen context (current screen, path, depth).
Requirements:
  • Use React Navigation (e.g. @react-navigation/native).
  • EmbedProvider must wrap NavigationContainer and receive the same ref you pass to NavigationContainer.

Basic Setup

Minimal

import { useRef } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { EmbedProvider } from '@revrag-ai/embed-react-native';
import { RootNavigator } from './navigation/RootNavigator';

export default function App() {
  const navigationRef = useRef(null);

  return (
    <EmbedProvider navigationRef={navigationRef} appVersion="1.0.0">
      <NavigationContainer ref={navigationRef}>
        <RootNavigator />
      </NavigationContainer>
    </EmbedProvider>
  );
}
  • appVersion (required): Your app version string (e.g. from package.json). Used in analytics.
  • navigationRef: Ref attached to NavigationContainer. Without it, the provider cannot detect screen changes and will not show the button by screen.

With screen allowlist

Restrict the button to specific screens:
<EmbedProvider
  navigationRef={navigationRef}
  appVersion="1.0.0"
  includeScreens={['ScreenA', 'ScreenB', 'ScreenC']}

>
  <NavigationContainer ref={navigationRef}>
    <RootNavigator />
  </NavigationContainer>
</EmbedProvider>
  • includeScreens: Array of route names where the button may appear. If omitted or empty, the button can appear on all screens (subject to backend). Names must match your navigator’s name (e.g. Stack.Screen name="ScreenA").

Screen-Based Visibility

How it works

  1. You pass a ref from your root to both EmbedProvider and NavigationContainer.
  2. The provider subscribes to navigation state and reads the current route (deepest active screen).
  3. If the current screen is in includeScreens (or in any visibility group when using groups), the button is shown; otherwise it is hidden.

Important

  • EmbedProvider must wrap NavigationContainer so it can attach a listener to the same ref.
  • Route names are case-sensitive and must match exactly (e.g. 'Screen1' not 'screen1').

Global Delay

You can delay the first appearance of the button after entering an included screen:
<EmbedProvider
  navigationRef={navigationRef}
  appVersion="1.0.0"
  includeScreens={['ScreenA', 'ScreenB']}
  embedButtonDelayMs={1500}
>
  <NavigationContainer ref={navigationRef}>
    <RootNavigator />
  </NavigationContainer>
</EmbedProvider>
  • embedButtonDelayMs: Delay in milliseconds before showing the button on an included screen. Default is 0 (show immediately). This is the global default; groups can override it per group.

Advanced: Visibility Groups

For finer control (different delays, “stay visible” across screens, per-group position), use visibility groups.

Concepts

ConceptMeaning
GroupA set of screens that share delay/continuity/inset rules.
ContinuityWhether the button stays visible when moving between screens in the same group.
Delay policyWhen the delay is applied: every screen, once per group entry, or once per app session.
InsetDistance from screen edges (right, bottom, etc.) for the button.

Types (import from package)

import type {
  EmbedButtonVisibilityConfig,
  EmbedButtonGroupConfig,
  EmbedButtonContinuity,
  EmbedButtonDelayPolicy,
  EmbedButtonInset,
} from '@revrag-ai/embed-react-native';

EmbedButtonVisibilityConfig

interface EmbedButtonVisibilityConfig {
  defaultDelayMs?: number;   // Optional fallback when a group doesn't set delayMs
  defaultInset?: EmbedButtonInset;
  groups?: EmbedButtonGroupConfig[];
}
When do you need defaultDelayMs? You don’t need it if every group sets its own delayMs. It’s only used as a fallback when:
  • A group does not set delayMs – that group will use defaultDelayMs, then the top-level embedButtonDelayMs.
  • A screen is included (e.g. via includeScreens) but doesn’t belong to any group – the provider uses defaultDelayMs (or embedButtonDelayMs) for that screen.
So you can omit defaultDelayMs and defaultInset when every group defines its own delayMs and inset.

EmbedButtonGroupConfig

interface EmbedButtonGroupConfig {
  id: string;                    // Unique ID for this group
  screens: string[];             // Route names in this group
  continuity: EmbedButtonContinuity;
  inset?: EmbedButtonInset;
  delayMs?: number;
  delayPolicy?: EmbedButtonDelayPolicy;
}

EmbedButtonContinuity

  • 'continuous' – When the user moves between screens in the same group, the button stays visible and the delay is not re-applied.
  • 'perScreen' – Each screen in the group is treated independently (delay can re-run per screen if policy allows).

EmbedButtonDelayPolicy

  • 'perScreen' – Delay runs on every included screen in the group when you land on it.
  • 'oncePerGroupEntry' – Delay runs only when entering the group (first screen of that group in this “visit”). Moving to another screen in the same group does not re-trigger the delay (especially useful with continuity: 'continuous').
  • 'oncePerAppSession' – Delay runs only once per app session for that group. After the button has been shown once for that group, it shows immediately when returning to any screen in the group.

Including screens via groups

Screens listed in any group’s screens array are treated as included even if you don’t list them in includeScreens. So you can:
  • Rely only on groups (e.g. includeScreens={[]} and define all included screens inside groups), or
  • Use both: includeScreens + groups; the final set of included screens is the union of both.

Insets (Button Position)

EmbedButtonInset controls how far the button sits from the edges of the screen:
type EmbedButtonInset = {
  top?: number | string;
  right?: number | string;
  bottom?: number | string;
  left?: number | string;
};
  • Values are typically numbers (e.g. 16, 54).
  • You can set per-group inset in EmbedButtonGroupConfig, or a default in EmbedButtonVisibilityConfig.defaultInset.
  • If nothing is set, the SDK uses an internal default (e.g. right: 16, bottom: 20).
Example:
const flowGroup: EmbedButtonGroupConfig = {
  id: 'mainFlow',
  screens: ['Screen1', 'Screen2', 'Screen3'],
  continuity: 'continuous',
  inset: { right: 16, bottom: 54 },
  delayMs: 1500,
  delayPolicy: 'oncePerGroupEntry',
};

Complete Examples

Example 1: Multi-screen flow + confirmation screen

  • Main flow: Screen1 → Screen2 → Screen3. Button appears after 1.5s when entering the flow and stays visible while moving between these screens. Inset right: 16, bottom: 54.
  • Screen4: Single screen. Button appears after 1.5s once per app session. Inset right: 24, bottom: 32.
  • Other screens: No button.
import {
  EmbedProvider,
  type EmbedButtonContinuity,
  type EmbedButtonDelayPolicy,
  type EmbedButtonGroupConfig,
  type EmbedButtonVisibilityConfig,
} from '@revrag-ai/embed-react-native';
import { NavigationContainer } from '@react-navigation/native';
import { useRef } from 'react';

const flowGroup: EmbedButtonGroupConfig = {
  id: 'mainFlow',
  screens: ['Screen1', 'Screen2', 'Screen3'],
  continuity: 'continuous' as EmbedButtonContinuity,
  inset: { right: 16, bottom: 54 },
  delayMs: 1500,
  delayPolicy: 'oncePerGroupEntry' as EmbedButtonDelayPolicy,
};

const confirmationGroup: EmbedButtonGroupConfig = {
  id: 'confirmationScreen',
  screens: ['Screen4'],
  continuity: 'perScreen' as EmbedButtonContinuity,
  inset: { right: 24, bottom: 32 },
  delayMs: 1500,
  delayPolicy: 'oncePerAppSession' as EmbedButtonDelayPolicy,
};

const embedButtonVisibilityConfig: EmbedButtonVisibilityConfig = {
  defaultDelayMs: 1200,
  defaultInset: { right: 16, bottom: 20 },
  groups: [flowGroup, confirmationGroup],
};

export default function App() {
  const navigationRef = useRef(null);

  return (
    <EmbedProvider
      navigationRef={navigationRef}
      includeScreens={['Screen1', 'Screen2', 'Screen3', 'Screen4']}
      appVersion="1.0.0"
      embedButtonDelayMs={1200}
      embedButtonVisibilityConfig={embedButtonVisibilityConfig}
    >
      <NavigationContainer ref={navigationRef}>
        <RootNavigator />
      </NavigationContainer>
    </EmbedProvider>
  );
}

Example 2: Two screens with different delays

  • ScreenA: Single screen, delay 1.5s every time you land on it, inset right: 16, bottom: 24.
  • ScreenB: Single screen, delay 3s every time, inset right: 16, bottom: 24.
const screenAGroup: EmbedButtonGroupConfig = {
  id: 'groupA',
  screens: ['ScreenA'],
  continuity: 'perScreen',
  inset: { right: 16, bottom: 24 },
  delayMs: 1500,
  delayPolicy: 'perScreen',
};

const screenBGroup: EmbedButtonGroupConfig = {
  id: 'groupB',
  screens: ['ScreenB'],
  continuity: 'perScreen',
  inset: { right: 16, bottom: 24 },
  delayMs: 3000,
  delayPolicy: 'perScreen',
};

const embedButtonVisibilityConfig: EmbedButtonVisibilityConfig = {
  defaultDelayMs: 1200,
  defaultInset: { right: 16, bottom: 20 },
  groups: [screenAGroup, screenBGroup],
};

<EmbedProvider
  navigationRef={navigationRef}
  includeScreens={['ScreenA', 'ScreenB']}
  appVersion="1.0.0"
  embedButtonVisibilityConfig={embedButtonVisibilityConfig}
>
  <NavigationContainer ref={navigationRef}>
    <RootNavigator />
  </NavigationContainer>
</EmbedProvider>

Example 3: Include screens only via groups

No includeScreens; only group membership decides visibility:
<EmbedProvider
  navigationRef={navigationRef}
  appVersion="1.0.0"
  embedButtonVisibilityConfig={embedButtonVisibilityConfig}
>
  <NavigationContainer ref={navigationRef}>
    <RootNavigator />
  </NavigationContainer>
</EmbedProvider>
Screens that appear in at least one group’s screens array will get the button; all others will not.

Field Reference

EmbedProvider props

PropDescription
childrenThe wrapped app or navigation container.
navigationRefA NavigationContainerRef passed to the provider so it can observe route changes. If omitted, the provider can create an internal ref.
includeScreensArray of screen names to allow button visibility. If empty or omitted, all screens are eligible.
appVersionRequired. App version string, used in analytics.
embedButtonDelayMsDefault delay (ms) applied per screen when no group config overrides it.
embedButtonVisibilityConfigAdvanced configuration for grouping, continuity, and per-group delays/insets.

EmbedButtonVisibilityConfig

FieldDescription
defaultDelayMsUsed when a matched group does not specify delayMs.
defaultInsetDefault inset applied when a group does not specify an inset.
groupsArray of EmbedButtonGroupConfig.

EmbedButtonGroupConfig

FieldDescription
idUnique identifier for the group.
screensScreen names that belong to this group.
continuity'continuous' – keep button visible across screens in this group; 'perScreen' – treat each screen as independent.
delayMsDelay (ms) before showing the button for this group.
delayPolicy'perScreen' | 'oncePerGroupEntry' | 'oncePerAppSession'.
insetOffsets from edges: { top, right, bottom, left } (number or string).

Practical Scenarios

Multi-step form flow (single delay)

Goal: Show delay once, then keep visible across steps.
const flowGroup: EmbedButtonGroupConfig = {
  id: 'formFlow',
  screens: ['Step1', 'Step2', 'Step3', 'Step4', 'Step5'],
  continuity: 'continuous' as EmbedButtonContinuity,
  delayMs: 1500,
  delayPolicy: 'oncePerGroupEntry' as EmbedButtonDelayPolicy,
};

Same flow with extra standalone screens

Goal: Delay once for the flow, delay per screen for other screens.
const flowGroup: EmbedButtonGroupConfig = {
  id: 'formFlow',
  screens: ['Step1', 'Step2', 'Step3', 'Step4', 'Step5'],
  continuity: 'continuous' as EmbedButtonContinuity,
  delayMs: 1500,
  delayPolicy: 'oncePerGroupEntry' as EmbedButtonDelayPolicy,
};

const otherGroup: EmbedButtonGroupConfig = {
  id: 'otherScreens',
  screens: ['ScreenX', 'ScreenY'],
  continuity: 'perScreen' as EmbedButtonContinuity,
  delayMs: 1200,
  delayPolicy: 'perScreen' as EmbedButtonDelayPolicy,
};

Avoid overlapping bottom UI

Goal: Push the button above a bottom tab bar.
const flowGroup: EmbedButtonGroupConfig = {
  id: 'formFlow',
  screens: ['Step1', 'Step2', 'Step3'],
  continuity: 'continuous' as EmbedButtonContinuity,
  inset: { right: 16, bottom: 64 },
  delayMs: 1200,
  delayPolicy: 'oncePerGroupEntry' as EmbedButtonDelayPolicy,
};

Troubleshooting

IssueWhat to check
Button never appears1) navigationRef is the same ref as on NavigationContainer. 2) EmbedProvider wraps NavigationContainer. 3) Current route name is in includeScreens or in a group’s screens.
Button on wrong screensRoute names in includeScreens / screens must match exactly (case-sensitive) the name prop of your screens.
Screen not interactive when button is visibleThe overlay uses pointerEvents="box-none" so only the button receives touches; the rest should pass through. If not, ensure you’re on a version that includes this fix.
Button position wrongSet inset per group or in defaultInset. The provider uses a full-screen overlay; insets are applied inside the EmbedButton container.
Delay not as expectedCheck delayPolicy and continuity: oncePerGroupEntry + continuous keeps the button visible in the group and delays only on first entry; perScreen re-applies delay on every screen.
Types not foundImport from @revrag-ai/embed-react-native: EmbedButtonVisibilityConfig, EmbedButtonGroupConfig, EmbedButtonContinuity, EmbedButtonDelayPolicy, EmbedButtonInset.

Summary

  • EmbedProvider wraps NavigationContainer and receives the same navigationRef.
  • Use includeScreens to allowlist screens, and/or embedButtonVisibilityConfig.groups for per-group delay, continuity, and inset.
  • continuity: ‘continuous’ + delayPolicy: ‘oncePerGroupEntry’ gives a “one delay when entering the flow, then stay visible” behavior.
  • embedButtonDelayMs and defaultDelayMs are fallbacks when a group doesn’t set delayMs.
See also: Back to React Native integration