# EmbedProvider advanced > Advanced EmbedProvider patterns for React Native: screen visibility, route groups, delays, continuity, and FAB insets. URL: /embed/integration/embed-provider-advanced Markdown: /embed/integration/embed-provider-advanced.md # EmbedProvider advanced (FAB visibility) [#embedprovider-advanced-fab-visibility] Use this guide after you have a working **`EmbedProvider`** + **`NavigationContainer`** setup from the [React Native integration guide](/embed/integration/react-native). Here you tune **where** the FAB appears, **when** it shows, and **how** it is positioned using **`includeScreens`**, **`embedButtonDelayMs`**, and **`embedButtonVisibilityConfig`**. *** ## Introduction [#introduction] **EmbedProvider** wraps your app and: * Listens to **React Navigation** state and shows or hides **`EmbedButton`** by screen. * Supports **visibility groups**: per-group delay, continuity, and inset. * Enriches analytics with **screen context** (current screen, path, depth). **What this guide covers** * **`includeScreens`** - allowlist route names where the FAB may appear. * **`embedButtonDelayMs`** - default delay before the FAB appears on an eligible screen. * **`embedButtonVisibilityConfig`** - **groups**, **continuity**, **delay policies**, and **insets** for production-grade UX. **Requirements** * **React Navigation** (for example `@react-navigation/native`). * **`EmbedProvider` must wrap `NavigationContainer`** and use the **same `ref`** you pass to **`NavigationContainer`**. *** ## Prerequisites [#prerequisites] Before you use advanced visibility rules, confirm the following: | Requirement | Notes | | -------------------- | ------------------------------------------------------------------------------------------------------------------------- | | **React Native** | 0.70 or higher (same as main integration guide) | | **React Navigation** | Root **`NavigationContainer`** with a shared **`navigationRef`** | | **Base embed setup** | **`useInitialize`**, **`GestureHandlerRootView`**, and **`EmbedProvider`** wired as in the main guide | **You will also need:** * Route **`name`** values that match your navigators exactly (**case-sensitive**). * A clear idea of which flows should show the FAB (tabs, stacks, auth exclusions, etc.). If **`navigationRef`** is missing or not the same ref as on **`NavigationContainer`**, the provider cannot detect screen changes and FAB visibility will not match your rules. *** ## Before you continue: base integration [#before-you-continue-base-integration] Complete **installation**, **native LiveKit setup**, and the **Basic setup** steps in the React Native guide first. Advanced props build on that tree. Start here if you have not finished **`useInitialize`**, peer dependencies, **`GestureHandlerRootView`**, and a minimal **`EmbedProvider`** around **`NavigationContainer`**. *** ## Basic setup (step-by-step) [#basic-setup-step-by-step] Follow these in order. You can stop after Step 2 for a simple allowlist-only integration. ### Step 1 - Minimal provider and ref [#step-1---minimal-provider-and-ref] ```tsx 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 ( ); } ``` * **`appVersion`** (required): Your app version string (for example from **`package.json`**). Used in analytics. * **`navigationRef`**: Must be the ref attached to **`NavigationContainer`**. Without it, the provider cannot reliably drive screen-based visibility. ### Step 2 - Restrict screens with includeScreens (optional) [#step-2---restrict-screens-with-includescreens-optional] ```tsx ``` * **`includeScreens`**: Route **names** where the button may appear. If omitted or empty, eligibility depends on backend and groups (see visibility groups). Names must match **`Stack.Screen name="..."`** exactly. ### Step 3 - Global delay (optional) [#step-3---global-delay-optional] Delay the first appearance of the FAB after entering an included screen: ```tsx ``` * **`embedButtonDelayMs`**: Delay in **milliseconds** before showing the FAB on an included screen. Default **`0`**. Groups can override per group. ### Step 4 - Visibility groups (optional, advanced) [#step-4---visibility-groups-optional-advanced] For different delays, continuity, or insets per flow, configure **`embedButtonVisibilityConfig`** (see [Visibility groups](#visibility-groups) and [Configuration options](#configuration-options)). *** ## How screen-based visibility works [#how-screen-based-visibility-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 FAB is shown; otherwise it is hidden. **Important** * **`EmbedProvider` must wrap `NavigationContainer`** so the listener uses the same ref. * Route names are **case-sensitive** and must match exactly (for example **`Screen1`**, not **`screen1`**). *** ## Global delay [#global-delay] See **Step 3** above. **`embedButtonDelayMs`** is the global default; **`embedButtonVisibilityConfig.defaultDelayMs`** and per-group **`delayMs`** override or refine behavior when you use groups. *** ## Visibility groups [#visibility-groups] For finer control (different delays, staying visible across screens, per-group position), use **visibility groups**. ### Concepts [#concepts] | Concept | Meaning | | ---------------- | --------------------------------------------------------------------------------- | | **Group** | A set of screens that share delay, continuity, and inset rules. | | **Continuity** | Whether the FAB stays visible when moving between screens in the same group. | | **Delay policy** | When the delay runs: every screen, once per group entry, or once per app session. | | **Inset** | Distance from screen edges (right, bottom, and so on) for the FAB. | ### Types (import from the package) [#types-import-from-the-package] ```ts import type { EmbedButtonVisibilityConfig, EmbedButtonGroupConfig, EmbedButtonContinuity, EmbedButtonDelayPolicy, EmbedButtonInset, } from '@revrag-ai/embed-react-native'; ``` ### `EmbedButtonVisibilityConfig` [#embedbuttonvisibilityconfig] ```ts interface EmbedButtonVisibilityConfig { defaultDelayMs?: number; // Optional fallback when a group does not set delayMs defaultInset?: EmbedButtonInset; groups?: EmbedButtonGroupConfig[]; } ``` **When do you need `defaultDelayMs`?** You do not need it if every group sets its own **`delayMs`**. It is a **fallback** when: * A **group omits `delayMs`** - that group falls back to **`defaultDelayMs`**, then top-level **`embedButtonDelayMs`**. * A screen is **included** (for example via **`includeScreens`**) but **does not belong to any group** - the provider uses **`defaultDelayMs`** (or **`embedButtonDelayMs`**) for that screen. You can omit **`defaultDelayMs`** and **`defaultInset`** when every group defines its own **`delayMs`** and **`inset`**. ### `EmbedButtonGroupConfig` [#embedbuttongroupconfig] ```ts 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` [#embedbuttoncontinuity] * **`continuous`** - Moving between screens **in the same group** keeps the FAB visible; delay is **not** re-applied in the way **`perScreen`** would. * **`perScreen`** - Each screen in the group is treated independently (delay can re-run per screen if the policy allows). ### `EmbedButtonDelayPolicy` [#embedbuttondelaypolicy] * **`perScreen`** - Delay runs on **every** included screen in the group when you land on it. * **`oncePerGroupEntry`** - Delay runs when **entering** the group (first screen of that visit). Moving within the group does not re-trigger the delay (pairs well with **`continuous`**). * **`oncePerAppSession`** - Delay runs **once per app session** for that group; later visits to the group show the FAB immediately per policy. ### Including screens via groups [#including-screens-via-groups] Screens listed in **any** group **`screens`** array count as **included** even if you omit them from **`includeScreens`**. You can: * Use **only groups** (for example omit the allowlist and define all included screens inside **groups**), or * Use **both** - the final included set is the **union** of **`includeScreens`** and all group screens. *** ## Insets (button position) [#insets-button-position] **`EmbedButtonInset`** controls distance from screen edges: ```ts type EmbedButtonInset = { top?: number | string; right?: number | string; bottom?: number | string; left?: number | string; }; ``` * Values are usually **numbers** (for example **`16`**, **`54`**). * Set **per group** in **`EmbedButtonGroupConfig.inset`**, or a default in **`EmbedButtonVisibilityConfig.defaultInset`**. * If unset, the SDK uses internal defaults (for example **right: 16**, **bottom: 20**). ```ts const flowGroup: EmbedButtonGroupConfig = { id: 'mainFlow', screens: ['Screen1', 'Screen2', 'Screen3'], continuity: 'continuous', inset: { right: 16, bottom: 54 }, delayMs: 1500, delayPolicy: 'oncePerGroupEntry', }; ``` *** ## Configuration options [#configuration-options] ### `EmbedProvider` props [#embedprovider-props] | Prop | Type | Required | Description | | --------------------------------- | ----------------------------- | ----------- | ------------------------------------------------------------------------------- | | **`children`** | `ReactNode` | Yes | Your app, usually **`NavigationContainer`** and below. | | **`navigationRef`** | ref | Recommended | Same ref as **`NavigationContainer`** so route changes are observed. | | **`appVersion`** | `string` | Yes | App version for analytics. | | **`includeScreens`** | `string[]` | No | Route names where the FAB may appear; union with group screens if both are set. | | **`embedButtonDelayMs`** | `number` | No | Default delay (ms) before showing the FAB when no group overrides apply. | | **`embedButtonVisibilityConfig`** | `EmbedButtonVisibilityConfig` | No | Groups, continuity, per-group delays, insets. | ### `EmbedButtonVisibilityConfig` [#embedbuttonvisibilityconfig-1] | Field | Description | | -------------------- | -------------------------------------------------------------- | | **`defaultDelayMs`** | Used when a matched group does not specify **`delayMs`**. | | **`defaultInset`** | Default inset when a group does not specify **`inset`**. | | **`groups`** | Array of **`EmbedButtonGroupConfig`**. | ### `EmbedButtonGroupConfig` [#embedbuttongroupconfig-1] | Field | Description | | ----------------- | ----------------------------------------------------------------------------------------- | | **`id`** | Unique string for the group. | | **`screens`** | Screen **names** in this group. | | **`continuity`** | **`continuous`** or **`perScreen`**. | | **`delayMs`** | Delay in ms for this group. | | **`delayPolicy`** | **`perScreen`**, **`oncePerGroupEntry`**, or **`oncePerAppSession`**. | | **`inset`** | Offsets from edges **`{ top, right, bottom, left }`**. | *** ## Usage examples [#usage-examples] ### Example 1: Multi-screen flow and confirmation screen [#example-1-multi-screen-flow-and-confirmation-screen] * **Main flow**: Screen1 to Screen3. FAB after 1.5s when entering the flow, **stays visible** within the flow. Inset **right: 16**, **bottom: 54**. * **Screen4**: Single screen. Delay 1.5s **once per app session**. Inset **right: 24**, **bottom: 32**. * **Other screens**: No FAB. ```tsx 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 ( ); } ``` ### Example 2: Two screens with different delays [#example-2-two-screens-with-different-delays] * **ScreenA**: Delay 1.5s every visit, inset **right: 16**, **bottom: 24**. * **ScreenB**: Delay 3s every visit, same inset. ```tsx 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], }; ``` ### Example 3: Screens included only via groups [#example-3-screens-included-only-via-groups] Omit **`includeScreens`**; only group membership decides visibility: ```tsx ``` Screens that appear in at least one group **`screens`** array get the FAB; all others do not. *** ## Practical scenarios [#practical-scenarios] ### Multi-step form flow (single delay) [#multi-step-form-flow-single-delay] Goal: Show delay once, then keep the FAB visible across steps. ```tsx 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 [#same-flow-with-extra-standalone-screens] Goal: Delay once for the flow, different behavior for other screens. ```tsx 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 [#avoid-overlapping-bottom-ui] Goal: Push the FAB above a bottom tab bar. ```tsx 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 [#troubleshooting] | Issue | What to check | | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | FAB never appears | 1) **`navigationRef`** matches **`NavigationContainer`**. 2) **`EmbedProvider`** wraps **`NavigationContainer`**. 3) Current route is in **`includeScreens`** or a group **`screens`** list. | | FAB on wrong screens | Route **`name`** values must match **exactly** (case-sensitive) your **`Stack.Screen`** (or equivalent) **`name`**. | | Screen not interactive when FAB is visible | Overlay uses **`pointerEvents="box-none"`** so touches pass through except on the FAB. Update the SDK if behavior differs. | | Wrong position | Set **`inset`** per group or **`defaultInset`**. Insets apply inside the FAB container on the full-screen overlay. | | Delay feels wrong | Check **`delayPolicy`** and **`continuity`**: **`oncePerGroupEntry`** + **`continuous`** delays once on group entry; **`perScreen`** can re-apply on each screen. | | Types not found | Import from **`@revrag-ai/embed-react-native`**: **`EmbedButtonVisibilityConfig`**, **`EmbedButtonGroupConfig`**, **`EmbedButtonContinuity`**, **`EmbedButtonDelayPolicy`**, **`EmbedButtonInset`**. | 1. Log the active route name and compare to **`includeScreens`** / group **`screens`**. 2. Confirm **`EmbedProvider`** is **outside** **`NavigationContainer`** and **`ref`** is the same object reference. 3. Temporarily set a broad **`includeScreens`** list to verify routing, then tighten. *** ## Best practices [#best-practices] * **Match route names in config to navigator `name` props** - typos and casing break visibility. * **Start with `includeScreens`**, then add **groups** when you need different delays or insets per flow. * **Prefer `oncePerGroupEntry` + `continuous`** for multi-step flows so users do not see the FAB pop in on every step. * **Tune `bottom` inset** when you have tab bars or bottom sheets so the FAB does not overlap primary UI. * **Keep `appVersion`** accurate for analytics when debugging screen context. * **Re-read delay policies** when QA reports "delay only happened once" - often **`oncePerAppSession`** or **`oncePerGroupEntry`** is working as designed. *** ## Support [#support] * **Docs:** [https://docs.revrag.ai](https://docs.revrag.ai/) * **Email:** [contact@revrag.ai](mailto:contact@revrag.ai) **Main integration:** [React Native integration](/embed/integration/react-native) (install, native setup, **`useInitialize`**, **`USER_DATA`**, events). *** ## Related documentation [#related-documentation] Installation, native LiveKit setup, **`GestureHandlerRootView`**, **`useInitialize`**, **`EmbedProvider`** basics, **`Embed.Event`**, and troubleshooting.