# EmbedProvider advanced (React) > Advanced EmbedProvider patterns for React: route visibility, delay policies, programmatic control, and production best practices. URL: /embed/integration/react/embed-react-provider-advanced Markdown: /embed/integration/react/embed-react-provider-advanced.md # EmbedProvider — Basic to Advanced Guide for React [#embedprovider--basic-to-advanced-guide-for-react] `EmbedProvider` is a React context provider that manages **where** and **when** the AI widget appears across your app. Instead of manually placing `` on every page, you wrap your app once and let the provider handle everything. *** ## How It Works (Internals Overview) [#how-it-works-internals-overview] ``` EmbedProvider ├── Detects current route (via usePathHook → currentPath prop → window.location fallback) ├── Checks if the route is in includeScreens ├── Applies delay logic (embedButtonDelayMs / group config) └── Renders when conditions are met ``` * If `includeScreens` is **empty** → widget shows on **every route** * If `includeScreens` has values → widget shows **only on those routes** * Path detection priority: `currentPath` prop > `usePathHook` > `window.location` *** ## Level 1 — Show Widget on Every Page [#level-1--show-widget-on-every-page] The simplest setup. No route filtering, no delays. ```tsx // app/layout.tsx (Next.js) or your root component "use client"; import { useInitialize, EmbedProvider } from '@revrag-ai/embed-react'; import '@revrag-ai/embed-react/dist/ai-assistant-widget.css'; export default function RootLayout({ children }) { useInitialize("your-api-key"); return ( {children} ); } ``` The widget appears on every route immediately. That's it. *** ## Level 2 — Show Widget Only on Specific Routes [#level-2--show-widget-only-on-specific-routes] Use `includeScreens` to whitelist which routes show the widget. ### Exact Match (default) [#exact-match-default] `/help` matches **only** `/help` — not `/help/faq`. ```tsx {children} ``` ### Prefix Match [#prefix-match] `/help` matches `/help`, `/help/faq`, `/help/contact`, etc. ```tsx {children} ``` ### Injecting the Router Hook [#injecting-the-router-hook] The provider needs to know the current path. Pass your router's hook so it updates on navigation. **Next.js App Router:** ```tsx import { usePathname } from 'next/navigation'; // Wrap in a named function — required because hooks must be // called unconditionally and stably inside the provider function useNextPathname() { return usePathname(); } ``` **React Router:** ```tsx import { useLocation } from 'react-router-dom'; function useReactRouterPath() { return useLocation().pathname; } ``` **Manual override (any framework):** ```tsx // Pass the path directly — highest priority, overrides everything ``` *** ## Level 3 — Delay the Widget Appearance [#level-3--delay-the-widget-appearance] Show the widget after the user has been on a screen for a few seconds, so it doesn't feel intrusive. ```tsx {children} ``` **What happens:** 1. User navigates to `/pricing` 2. Provider hides the widget and starts a 4-second timer 3. Timer fires → widget appears with animation 4. User navigates away → widget hides immediately, timer resets 5. User comes back to `/pricing` → 4-second timer starts again *** ## Level 4 — Customize the Button Position [#level-4--customize-the-button-position] Override where the floating button sits on the screen. ```tsx {children} ``` You can also pass CSS strings: ```tsx embedButtonPosition={{ bottom: '5rem', right: '1.5rem' }} ``` Pass any `EmbedButton` prop through `embedButtonProps`: ```tsx {children} ``` *** ## Level 5 — Group-Based Visibility [#level-5--group-based-visibility] This is the advanced visibility engine. Use it when different sections of your app need different delay or continuity behavior. ### The Problem It Solves [#the-problem-it-solves] Without groups, every navigation triggers the delay timer — so if a user moves between `/checkout` and `/payment` (both part of checkout), the widget keeps hiding and re-appearing. Groups prevent that. ### Core Concepts [#core-concepts] **`continuity`** — controls what happens when navigating *within* a group: | Value | Behavior | | -------------- | ------------------------------------------------------------------------------------ | | `"continuous"` | Widget stays visible — no re-animation when moving between screens in the same group | | `"perScreen"` | Widget re-applies delay on every screen, even within the group | **`delayPolicy`** — controls *when* the delay fires: | Value | Behavior | | --------------------- | ----------------------------------------------------------- | | `"perScreen"` | Delay fires on every screen in the group | | `"oncePerGroupEntry"` | Delay fires only the first time the user enters this group | | `"oncePerAppSession"` | Delay fires at most once per browser session for this group | ### Basic Groups Example [#basic-groups-example] ```tsx import { EmbedProvider } from '@revrag-ai/embed-react'; import type { EmbedButtonVisibilityConfig } from '@revrag-ai/embed-react'; const visibilityConfig: EmbedButtonVisibilityConfig = { groups: [ { id: 'checkout-flow', screens: ['/cart', '/checkout', '/payment', '/confirmation'], continuity: 'continuous', // no re-animation between checkout steps delayMs: 2000, delayPolicy: 'oncePerGroupEntry', // delay only on first entry to checkout }, ], }; {children} ``` **What happens:** 1. User is on `/home` → widget hidden (not in any group) 2. User goes to `/cart` → 2-second delay, then widget appears 3. User goes to `/checkout` → widget stays visible (same group, `continuous`) 4. User goes to `/payment` → widget stays visible (same group, `continuous`) 5. User leaves to `/home` → widget hidden 6. User comes back to `/cart` → **no delay** this time (`oncePerGroupEntry` — already triggered) ### Multiple Groups [#multiple-groups] ```tsx const visibilityConfig: EmbedButtonVisibilityConfig = { defaultDelayMs: 1000, // fallback delay for screens not in any group groups: [ { id: 'onboarding', screens: ['/welcome', '/setup', '/profile-setup'], continuity: 'continuous', delayMs: 5000, delayPolicy: 'oncePerAppSession', // only delays once per browser session }, { id: 'checkout', screens: ['/cart', '/checkout', '/payment'], continuity: 'continuous', delayMs: 2000, delayPolicy: 'oncePerGroupEntry', }, { id: 'support', screens: ['/help', '/faq', '/contact'], continuity: 'perScreen', // re-animate on every support page delayMs: 3000, delayPolicy: 'perScreen', }, ], }; ``` ### defaultDelayMs [#defaultdelayms] Applies to any screen that is **included** (via `includeScreens`) but **not in any group**: ```tsx {children} ``` *** ## Level 6 — Reading Current Path in Children [#level-6--reading-current-path-in-children] Any component inside `EmbedProvider` can access the current path via `useEmbed`: ```tsx import { useEmbed } from '@revrag-ai/embed-react'; function Breadcrumb() { const { currentPath } = useEmbed(); return ; } ``` > `useEmbed()` throws if called outside `EmbedProvider`. Always use it inside the provider tree. *** ## Complete Real-World Example [#complete-real-world-example] A Next.js app with multiple sections, each with their own widget behavior: ```tsx // app/layout.tsx "use client"; import { usePathname } from 'next/navigation'; import { useInitialize, EmbedProvider } from '@revrag-ai/embed-react'; import '@revrag-ai/embed-react/dist/ai-assistant-widget.css'; import type { EmbedButtonVisibilityConfig } from '@revrag-ai/embed-react'; function useNextPathname() { return usePathname(); } const visibilityConfig: EmbedButtonVisibilityConfig = { defaultDelayMs: 1500, groups: [ { // Onboarding: delay once per session, stay visible through all steps id: 'onboarding', screens: ['/welcome', '/setup', '/verify'], continuity: 'continuous', delayMs: 6000, delayPolicy: 'oncePerAppSession', }, { // Checkout: delay once per entry, no re-animation between steps id: 'checkout', screens: ['/cart', '/checkout', '/payment', '/order-confirmed'], continuity: 'continuous', delayMs: 3000, delayPolicy: 'oncePerGroupEntry', }, { // Support: always delay, re-animate on each page (high intent section) id: 'support', screens: ['/help', '/faq', '/contact'], continuity: 'perScreen', delayMs: 2000, delayPolicy: 'perScreen', }, ], }; export default function RootLayout({ children }: { children: React.ReactNode }) { const { error } = useInitialize("your-api-key"); if (error) console.error('[EmbedSDK] Init error:', error); return ( {children} ); } ``` *** ## Props Quick Reference [#props-quick-reference] | Prop | Type | Default | Purpose | | ----------------------------- | ----------------------------- | --------------------------- | ---------------------------------------- | | `children` | `ReactNode` | — | Your app content | | `currentPath` | `string` | — | Manual path override (highest priority) | | `usePathHook` | `() => string` | — | Router hook for automatic path detection | | `includeScreens` | `string[]` | `[]` (all) | Routes where the widget appears | | `matchMode` | `"exact" \| "startsWith"` | `"exact"` | How routes are matched | | `embedButtonDelayMs` | `number` | `0` | Global delay before widget appears (ms) | | `embedButtonVisibilityConfig` | `EmbedButtonVisibilityConfig` | — | Advanced group-based visibility | | `embedButtonProps` | `EmbedButtonProps` | — | Props forwarded to `` | | `embedButtonPosition` | `{ bottom?, right? }` | `{ bottom: 20, right: 16 }` | Fixed position of the floating button | *** ## Common Mistakes [#common-mistakes] **Passing the hook result instead of the hook itself:** ```tsx // ❌ Wrong — passes the path string, not the hook // ✅ Correct — passes the hook function function useNextPathname() { return usePathname(); } ``` **Using `useEmbed` outside the provider:** ```tsx // ❌ Throws an error function ComponentOutsideProvider() { const { currentPath } = useEmbed(); // Error! } // ✅ Must be inside EmbedProvider tree function ComponentInsideProvider() { const { currentPath } = useEmbed(); // Works } ``` **Expecting `includeScreens` + groups to be separate:** Screens listed in `groups[].screens` are **automatically added** to the include list — you don't need to repeat them in `includeScreens`. ```tsx // ✅ You don't need to list /help in includeScreens — it's already in the group ``` **Forgetting `"use client"` in Next.js App Router:** ```tsx // ✅ Required when using EmbedProvider in Next.js App Router "use client"; import { EmbedProvider } from '@revrag-ai/embed-react'; ```