# React (Web) Copilot Integration
> Master prompt for an AI coding agent (Copilot / Cursor / Claude Code) to integrate @revrag-ai/embed-react end-to-end.
URL: /embed/llmText/react-copilotintegration
Markdown: /embed/llmText/react-copilotintegration.md
# RevRag React (Web) SDK — AI Agent Integration Master Prompt [#revrag-react-web-sdk--ai-agent-integration-master-prompt]
> **How to use:** paste this entire document into your AI coding agent (Copilot, Cursor,
> Claude Code, etc.) inside the web app you want to integrate — React SPA, Next.js,
> React 17 or Preact. The agent will inspect your app, install and wire
> `@revrag-ai/embed-react`, ask you the few decisions only you can make, then validate
> the integration end-to-end and report.
>
> Every rule below is derived from the SDK's source (v1.5.0). Where this prompt and a
> generic React tutorial disagree, this prompt is correct for **this** SDK. Versions up
> to 1.4.4 predate most of it — do not apply it to them.
***
You are an **expert web integration agent**. Take this application from
**zero → working → validated** RevRag SDK integration with minimal manual work.
**Prime directives**
1. **Inspect first, modify second.** Never assume the framework, router, React version,
bundler, package manager, or hosting setup. Read the project.
2. **Preserve host behavior.** Merge into the existing root, layout, providers, bundler
config and CSP; never overwrite `main.tsx`, `app/layout.tsx`, `_app.tsx`,
`vite.config`, `next.config` or `tsconfig` blindly.
3. **Never claim success without running the validation** in §16–§21 and observing the
log lines and the `verifyIntegration()` result named there.
4. **Ask the developer** for the decisions in §13 — do not guess them.
5. **Never hide an error.** Report SDK-side issues you cannot fix.
6. **Use only the public API.** Never import from `@revrag-ai/embed-core`,
`@revrag-ai/embed-react/dist/...` or any internal path. Do not add dependencies,
polyfills or config the SDK does not require.
***
## 1. Inspect the existing application [#1-inspect-the-existing-application]
Record each of these before changing anything:
| What | How to find it |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| React / React DOM version | `package.json`; `npm ls react react-dom` |
| Preact? | `preact` in deps; `@preact/preset-vite` in `vite.config.*`; `react` aliased to `preact/compat` |
| Framework | `next.config.*` ⇒ Next.js. Then: `app/layout.tsx` ⇒ **App Router**; `pages/_app.tsx` ⇒ **Pages Router** (both ⇒ App Router is primary). `angular.json` ⇒ **stop**, use the Angular SDK |
| Next.js version | `npm ls next` (12/13 need `--legacy-peer-deps`) |
| Bundler | Vite, webpack (CRA, Next ≤ 12, custom), Rspack, Parcel — decides the React 17 entry (§2) |
| Router | `react-router-dom` (version; `BrowserRouter` / `HashRouter` / `createBrowserRouter`; `basename`?), Next router, `preact-iso`, `preact-router`, TanStack Router, or none / state-driven |
| Where the router mounts | Is it conditional (auth gate, suspense, feature flag)? Is there a persistent layout/shell that never unmounts? |
| Root component / entry | `src/main.tsx` / `src/index.tsx`, `app/layout.tsx`, `pages/_app.tsx` |
| React roots | `grep -rn "createRoot\|ReactDOM.render\|hydrateRoot"` — more than one ⇒ micro-frontends (§22) |
| `StrictMode` | in the entry file (affects §19 in dev only) |
| TypeScript | `tsconfig.json` `compilerOptions.moduleResolution` (`node` needs a `paths` entry for `/react17`) |
| Package manager | `package-lock.json` / `yarn.lock` (+ `.yarnrc.yml` ⇒ berry) / `pnpm-lock.yaml` |
| Env/config system | `import.meta.env.VITE_*`, `process.env.NEXT_PUBLIC_*`, `process.env.REACT_APP_*`, runtime config |
| App version source | `package.json` `version`, a build id, CI env var, `next.config` `env` |
| Auth flow | where login completes (user id becomes known) and where sign-out happens |
| CSP / headers | ``, `next.config` `headers()`, server/CDN config, `Permissions-Policy` |
| Hosting | HTTPS everywhere? Served inside an iframe? |
| Existing overlays / widgets | chat widgets, toasts, cookie banners, sticky footers, other fixed-position floating buttons |
| Existing LiveKit / WebRTC | `npm ls livekit-client` |
| Component library | MUI, Radix, shadcn, Chakra, Ant, Headless UI, Ionic / Shoelace / Stencil (web components) |
| Sensitive screens / fields | login, OTP, PIN, payment, KYC, account numbers |
***
## 2. Determine compatibility [#2-determine-compatibility]
**Supported:** React **17, 18, 19**; **Preact 10** via `preact/compat`; Next.js **App
Router and Pages Router**; any current browser with WebRTC and `getUserMedia`; a
**secure context** (HTTPS, or `localhost` in development).
**Pick the entry point** — the API is identical; only the import path changes:
| Host | Import from |
| ----------------------------------------------------------------- | -------------------------------- |
| React 18 / 19, any bundler | `@revrag-ai/embed-react` |
| React 17 on **Vite** | `@revrag-ai/embed-react` |
| React 17 on **webpack** (CRA, Next.js 12, custom) | `@revrag-ai/embed-react/react17` |
| Preact (Vite with `@preact/preset-vite`, or webpack with aliases) | `@revrag-ai/embed-react` |
Use **one** entry consistently across the whole app. Diagnostics always come from
`@revrag-ai/embed-react/diagnostics`.
**Peer ranges:**
| Package | Range | Notes |
| -------------------- | ---------- | --------------------------------------------------------------------------------------------------- |
| `react`, `react-dom` | `>=17.0.0` | required |
| `next` | `>=14.0.0` | optional; the SDK never imports it. Next **12/13** ⇒ `ERESOLVE` — install with `--legacy-peer-deps` |
| `react-router-dom` | `>=6.0.0` | optional; the SDK never imports it. React Router **5** ⇒ same `ERESOLVE` workaround |
**TypeScript:** `moduleResolution: "bundler"` or `"nodenext"`. With `"node"`, the
`/react17` subpath needs a `paths` entry (§7).
**Do not upgrade or downgrade unrelated dependencies** to make the SDK fit. If something
is incompatible, explain it, apply the workaround above, and re-validate.
***
## 3. Install the SDK [#3-install-the-sdk]
```bash
npm install @revrag-ai/embed-react@^1.5.0
# yarn add @revrag-ai/embed-react@^1.5.0 / pnpm add @revrag-ai/embed-react@^1.5.0
# Next.js 12–13 or React Router 5: add --legacy-peer-deps
```
If given a **local tarball**, install that path instead. Then verify:
```bash
npm ls @revrag-ai/embed-react # 1.5.0 or later
ls node_modules/@revrag-ai/embed-react/{index.js,index.react17.js,diagnostics.js,style.css}
npm ls react react-dom # exactly ONE copy each (monorepo / pnpm hoisting!)
npm ls livekit-client --all # the SDK brings its own; note any second copy from the host
```
**Never add `livekit-client`, `framer-motion` or `lottie-web` to the app for the SDK** —
they are the SDK's own dependencies. `livekit-client` loads only when a call starts.
***
## 4. Configure the bundler and stylesheet [#4-configure-the-bundler-and-stylesheet]
### Stylesheet (required) [#stylesheet-required]
Import once, at the app's entry point:
```ts
import '@revrag-ai/embed-react/style.css';
```
| Framework | File |
| ----------------- | --------------------------------------------------- |
| React SPA | `src/main.tsx` / `src/index.tsx` |
| Next App Router | `app/layout.tsx` (a Server Component may import it) |
| Next Pages Router | `pages/_app.tsx` |
The path is exactly `@revrag-ai/embed-react/style.css`. **`…/dist/style.css` does not
resolve** from the published package. Without the stylesheet the button gets only a
minimal fallback and looks broken.
### Preact [#preact]
* **Vite + `@preact/preset-vite`**: nothing to do; the preset aliases `react`,
`react-dom` and `react/jsx-runtime` to `preact/compat`.
* **webpack / others**: add to `resolve.alias`:
```js
react: 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react-dom': 'preact/compat',
'react/jsx-runtime': 'preact/jsx-runtime',
```
* npm may install `react`/`react-dom` to satisfy peers. Harmless — the alias keeps them
out of the bundle. Do not "fix" it.
### Package-manager notes [#package-manager-notes]
* **yarn berry with PnP**: if resolution of the SDK's dependencies fails, switch to
`nodeLinker: node-modules` and tell the developer.
* **pnpm**: do not enable `strict-peer-dependencies` for this; pin the SDK version.
* **Monorepos**: the app must resolve **one** `react`/`react-dom`. Two copies give
"Invalid hook call".
***
## 5. Mount: framework-specific integration [#5-mount-framework-specific-integration]
Three steps for everyone: **initialize** once (`useInitialize`), **mount** one provider
(`EmbedProvider`), **identify** the user after login (§11). Pick the block that matches §1.
### 5A. React SPA with React Router (Vite / CRA) [#5a-react-spa-with-react-router-vite--cra]
```tsx
// src/main.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter, useLocation } from 'react-router-dom';
import { EmbedProvider, useInitialize } from '@revrag-ai/embed-react';
import '@revrag-ai/embed-react/style.css';
const API_KEY = import.meta.env.VITE_REVRAG_API_KEY as string;
const APP_VERSION = import.meta.env.VITE_APP_VERSION as string;
// Module scope — never inline visibility config in JSX (§14).
const EXCLUDED = ['/login', '/otp'];
// The provider lives INSIDE the router so it can read the path.
function RevragShell({ children }: { children: React.ReactNode }) {
const { pathname } = useLocation();
return (