# 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';
```