Documentation Index
Fetch the complete documentation index at: https://docs.revrag.ai/llms.txt
Use this file to discover all available pages before exploring further.
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 <EmbedButton /> on every page, you wrap your app once and let the provider handle everything.
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 <EmbedButton /> 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
The simplest setup. No route filtering, no delays.
// 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 (
<html lang="en">
<body>
<EmbedProvider>
{children}
</EmbedProvider>
</body>
</html>
);
}
The widget appears on every route immediately. That’s it.
Use includeScreens to whitelist which routes show the widget.
Exact Match (default)
/help matches only /help — not /help/faq.
<EmbedProvider
usePathHook={useNextPathname}
includeScreens={['/help', '/support', '/contact']}
matchMode="exact"
>
{children}
</EmbedProvider>
Prefix Match
/help matches /help, /help/faq, /help/contact, etc.
<EmbedProvider
usePathHook={useNextPathname}
includeScreens={['/help', '/dashboard']}
matchMode="startsWith"
>
{children}
</EmbedProvider>
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:
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();
}
<EmbedProvider usePathHook={useNextPathname} includeScreens={['/help']} />
React Router:
import { useLocation } from 'react-router-dom';
function useReactRouterPath() {
return useLocation().pathname;
}
<EmbedProvider usePathHook={useReactRouterPath} includeScreens={['/help']} />
Manual override (any framework):
// Pass the path directly — highest priority, overrides everything
<EmbedProvider currentPath={myCurrentPath} includeScreens={['/help']} />
Show the widget after the user has been on a screen for a few seconds, so it doesn’t feel intrusive.
<EmbedProvider
usePathHook={useNextPathname}
includeScreens={['/pricing', '/checkout']}
embedButtonDelayMs={4000} // wait 4 seconds after arriving on the screen
>
{children}
</EmbedProvider>
What happens:
- User navigates to
/pricing
- Provider hides the widget and starts a 4-second timer
- Timer fires → widget appears with animation
- User navigates away → widget hides immediately, timer resets
- User comes back to
/pricing → 4-second timer starts again
Override where the floating button sits on the screen.
<EmbedProvider
usePathHook={useNextPathname}
embedButtonPosition={{ bottom: 80, right: 24 }} // numbers = px
>
{children}
</EmbedProvider>
You can also pass CSS strings:
embedButtonPosition={{ bottom: '5rem', right: '1.5rem' }}
Pass any EmbedButton prop through embedButtonProps:
<EmbedProvider
usePathHook={useNextPathname}
embedButtonProps={{
positioning: 'fixed',
bottomOffset: 60, // offset for a 60px bottom navbar
className: 'my-widget',
}}
>
{children}
</EmbedProvider>
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
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
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
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
},
],
};
<EmbedProvider
usePathHook={useNextPathname}
embedButtonVisibilityConfig={visibilityConfig}
>
{children}
</EmbedProvider>
What happens:
- User is on
/home → widget hidden (not in any group)
- User goes to
/cart → 2-second delay, then widget appears
- User goes to
/checkout → widget stays visible (same group, continuous)
- User goes to
/payment → widget stays visible (same group, continuous)
- User leaves to
/home → widget hidden
- User comes back to
/cart → no delay this time (oncePerGroupEntry — already triggered)
Multiple Groups
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
Applies to any screen that is included (via includeScreens) but not in any group:
<EmbedProvider
usePathHook={useNextPathname}
includeScreens={['/dashboard', '/settings', '/help']}
embedButtonVisibilityConfig={{
defaultDelayMs: 2000, // applies to /dashboard and /settings
groups: [
{
id: 'support',
screens: ['/help'], // /help gets its own group config
continuity: 'perScreen',
delayMs: 5000,
delayPolicy: 'perScreen',
},
],
}}
>
{children}
</EmbedProvider>
Level 6 — Reading Current Path in Children
Any component inside EmbedProvider can access the current path via useEmbed:
import { useEmbed } from '@revrag-ai/embed-react';
function Breadcrumb() {
const { currentPath } = useEmbed();
return <nav>You are at: {currentPath}</nav>;
}
useEmbed() throws if called outside EmbedProvider. Always use it inside the provider tree.
Complete Real-World Example
A Next.js app with multiple sections, each with their own widget behavior:
// 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 (
<html lang="en">
<body>
<EmbedProvider
usePathHook={useNextPathname}
matchMode="startsWith"
embedButtonVisibilityConfig={visibilityConfig}
embedButtonProps={{ positioning: 'fixed', bottomOffset: 0 }}
embedButtonPosition={{ bottom: 24, right: 24 }}
>
{children}
</EmbedProvider>
</body>
</html>
);
}
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 <EmbedButton /> |
embedButtonPosition | { bottom?, right? } | { bottom: 20, right: 16 } | Fixed position of the floating button |
Common Mistakes
Passing the hook result instead of the hook itself:
// ❌ Wrong — passes the path string, not the hook
<EmbedProvider usePathHook={usePathname()} />
// ✅ Correct — passes the hook function
function useNextPathname() { return usePathname(); }
<EmbedProvider usePathHook={useNextPathname} />
Using useEmbed outside the provider:
// ❌ 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.
// ✅ You don't need to list /help in includeScreens — it's already in the group
<EmbedProvider
embedButtonVisibilityConfig={{
groups: [{ id: 'support', screens: ['/help'], continuity: 'perScreen' }]
}}
/>
Forgetting "use client" in Next.js App Router:
// ✅ Required when using EmbedProvider in Next.js App Router
"use client";
import { EmbedProvider } from '@revrag-ai/embed-react';