Dependency & Compatibility Guide
For client apps integrating @revrag-ai/embed-react · SDK 1.5.0
Which React, framework, router, bundler and TypeScript versions the web SDK works with, what the SDK installs into the host app, and what to do when the host is outside the supported ranges.
Everything here comes from the package's package.json, its build config and the example apps in the SDK repository (examples/*).
| Status | Meaning |
|---|---|
| Exercised | An example app in the SDK repository builds and runs on that stack |
| In range | The peer ranges allow it, but no example covers it |
Treat "exercised" as strong evidence, not a release certification.
The examples build against the SDK's source through bundler aliases, not the published tarball.
Table of contents
- Known-good stacks — pick one, and pick the right entry
- Peer dependencies
- What the SDK installs into the host
- Frameworks, routers and bundlers
- Outside the ranges: workarounds
- TypeScript
- Browsers and runtime
- Package managers
- Out of scope
1. Known-good stacks
Pin to one of these when you can. Each row is an example app in the SDK repository.
| Stack | React | Framework / bundler | Router | TypeScript | SDK entry | Example |
|---|---|---|---|---|---|---|
| A. React 19 SPA | react/react-dom 19.2.x | Vite 7.3 + @vitejs/plugin-react 5.1 | react-router-dom 7.x (7.13.1) | 5.9 (bundler) | default | examples/react |
| B. Next.js App Router | 19.2.3 | Next.js 16.1.6 | Next (App Router) | 5.x (bundler) | default | examples/nextjs |
| C. React 17 SPA | 17.0.2 | Vite 7.3 | none / any | — | default (works on Vite) | examples/react17-smoke |
| D. React 17 + Next.js | 17.0.2 | Next.js 12.3.4 (webpack 5) | Next (Pages Router) | 4.9.5 (node + paths) | /react17 | examples/next17-smoke |
| E. Preact | preact 10.29.x via preact/compat | Vite 7.3 + @preact/preset-vite 2.10 | preact-router 4.1.2 | (bundler) | default | examples/preact-poc |
Pick the entry by the host's React version and bundler:
| Host | Entry to import from |
|---|---|
| React 18 / 19, any bundler | @revrag-ai/embed-react |
| React 17 on Vite (Rollup) | @revrag-ai/embed-react |
| React 17 on webpack (CRA, Next.js 12, custom webpack) | @revrag-ai/embed-react/react17 |
| Preact 10 (Vite preset, or webpack with aliases) | @revrag-ai/embed-react |
Why webpack + React 17 needs its own entry.
- The default entry imports
framer-motion12, which statically importsuseId/useInsertionEffectfromreact. Those hooks only exist in React 18+. - Webpack checks named imports at build time and fails with
Attempted import error; Rollup/Vite only warns. - The
/react17entry is the same code withframer-motionswapped for a built-in stub, so it never touches those imports.
2. Peer dependencies
| Package | Declared range | Required | Status |
|---|---|---|---|
react | >=17.0.0 | yes | 17 (A/C/D), 19 (A/B) exercised; 18 in range |
react-dom | >=17.0.0 | yes | same as react; must be the same version |
next | >=14.0.0 | optional | 16 exercised; 14, 15 in range; 12 exercised but out of range (see §5) |
react-router-dom | >=6.0.0 | optional | 7 exercised; 6 in range; 5 out of range (see §5) |
nextandreact-router-domare optional peers. The published bundles never import either one: the host passes the current path toEmbedProvideras a string.- Any router works, including ones not listed (TanStack Router,
preact-iso,wouter, a hand-rolled state machine).
3. What the SDK installs into the host
These are runtime dependencies of @revrag-ai/embed-react, so npm installs them into the host.
Do not add any of them to the host's package.json for the SDK.
| Package | Range | Used by | If the host already has it |
|---|---|---|---|
livekit-client | ^2.6.0 | voice calls. Loaded with a dynamic import() only when a call starts | Host on 2.x ⇒ npm shares one copy (fine). Host on 1.x ⇒ the SDK gets its own nested 2.x copy (fine, larger install) |
framer-motion | ^12.23.9 | widget animations. Default entry only; the /react17 entry never imports it | Host on 12.x ⇒ shared. Host on ≤ 11 ⇒ a second nested copy, which costs bundle size but doesn't conflict. Host using the motion package ⇒ separate, no conflict |
zustand | ^4.5.5 | internal state | Host on zustand 5 ⇒ nested copy, independent stores, no conflict |
zod | ^3.24.1 | validating backend/agent messages | Host on zod 4 ⇒ nested copy, no conflict |
zod-to-json-schema | ^3.23.5 | schema helpers | — |
clsx | ^2.1.1 | class names | — |
tailwind-merge | ^2.5.4 | class names | Host on 3.x ⇒ nested copy, no conflict |
tailwindcss-animate | ^1.0.7 | listed, build-time only | The host does not need Tailwind |
tiny-invariant | ^1.3.3 | assertions | — |
Bundled inside the package (not installed, cannot conflict):
@revrag-ai/embed-core— shipped ininternal/core. Never install or import it.lottie-web(5.13) — bundled into its own chunk (lottie-*.js, ~420 KB).- The chunk is split out, but the default avatar animation itself is in the main bundle, so expect a noticeable first-load cost.
- A host's own
lottie-web/lottie-reactis unaffected.
Stylesheet. @revrag-ai/embed-react/style.css (~32 KB) is precompiled.
- Every rule is scoped to the widget's own
embed-*/ai-widget-*classes; there is no global reset. - It works with or without Tailwind, CSS Modules, styled-components, Emotion or MUI in the host.
Check the result after installing:
npm ls @revrag-ai/embed-react # 1.5.0
npm ls react react-dom # exactly ONE copy each
npm ls livekit-client --all # one 2.x copy is ideal; a nested second copy is acceptable
npm ls framer-motion --all # default entry onlyTwo copies of react / react-dom are never acceptable. They give Invalid hook call.
- This usually happens in monorepos, with linked packages, or with pnpm hoisting.
- Dedupe them:
npm dedupe,resolutions/overrides, or a bundler alias to the app's copy.
4. Frameworks, routers and bundlers
React
| Version | Status | Notes |
|---|---|---|
| 19.x | exercised (A, B) | |
| 18.x | in range | Same code path as 19 |
| 17.x | exercised (C, D) | useSyncExternalStore is polyfilled internally; animations are simpler (static styles instead of motion), which is expected. Add no polyfills. Webpack hosts must use /react17 |
| ≤ 16 | unsupported | Hooks-only SDK; peer range excludes it |
Next.js
| Version | Router | Status | Notes |
|---|---|---|---|
| 16 | App Router | exercised (B) | The package ships "use client"; useInitialize / usePathname still go in one client component |
| 14, 15 | App / Pages | in range | Same integration as 16 |
| 13 | App / Pages | out of peer range | Install with --legacy-peer-deps. The SDK never imports next, so this is safe |
| 12 | Pages | exercised (D), out of peer range | React 17 ⇒ /react17 entry; --legacy-peer-deps |
| ≤ 11 | — | untested | webpack 4 era; not supported |
For the Pages Router, pass router.pathname (the route pattern), never router.asPath.
Routers
| Router | Status | What to pass as currentPath |
|---|---|---|
react-router-dom 7 | exercised (A) | useLocation().pathname |
react-router-dom 6 | in range | useLocation().pathname |
react-router-dom 5 | out of peer range (--legacy-peer-deps); the SDK doesn't import it | useLocation().pathname / withRouter location.pathname |
| Next.js App Router | exercised (B) | usePathname() |
| Next.js Pages Router | exercised (D) | useRouter().pathname |
preact-router 4 | exercised (E) | current URL's pathname |
preact-iso | in range | useLocation().path (inside <LocationProvider>) |
| TanStack Router, wouter, others | works through the prop | the router's current pathname |
| No router | works through the prop | a synthetic path per screen, e.g. /onboarding/${step} |
Bundlers
| Bundler | Status | Notes |
|---|---|---|
| Vite 7 | exercised (A, C, E) | |
| Vite 5–6 | in range | |
| webpack 5 (Next.js 12+) | exercised (D) | React 17 ⇒ /react17 |
webpack 5 (CRA react-scripts 5, custom) | in range | React 17 ⇒ /react17 |
| Turbopack (Next.js 15/16 dev) | in range | |
| Rspack, Parcel, esbuild | untested | Should work: plain ESM + CJS, standard exports map. Report issues |
| webpack 4 | unsupported | Doesn't understand the package exports map |
The package publishes both ESM (index.js) and CJS (index.cjs) behind an exports map.
Any bundler that ignores exports can't resolve /react17, /diagnostics or /style.css.
Preact
preact 10 through preact/compat.
- Vite +
@preact/preset-vite: nothing to configure. - webpack: alias
react,react-dom,react-dom/test-utilsandreact/jsx-runtimetopreact/compat/preact/test-utils/preact/jsx-runtime. - npm may install
react/react-domto satisfy the peers. With the aliases in place they never reach the bundle.
5. Outside the ranges: workarounds
| Host | Symptom | Do |
|---|---|---|
| Next.js 12 or 13 | npm ERR! ERESOLVE on install | npm install --legacy-peer-deps (or an overrides entry). Safe: the SDK never imports next |
| React Router 5 | same ERESOLVE | same workaround |
| React 17 on webpack, default entry | Attempted import error: 'useId' is not exported from 'react' (from framer-motion) | Import everything from @revrag-ai/embed-react/react17 |
TS moduleResolution: "node" | Cannot find module '@revrag-ai/embed-react/react17' (or /diagnostics) | Switch to bundler / nodenext, or add compilerOptions.paths (below) |
| Two React copies | Invalid hook call | Dedupe (see §3) |
| yarn berry with PnP | resolution errors in SDK dependencies | nodeLinker: node-modules in .yarnrc.yml |
pnpm strict-peer-dependencies | install fails on optional peers | Leave it off, or use peerDependencyRules.allowedVersions |
The compilerOptions.paths entries for moduleResolution: "node":
{
"compilerOptions": {
"paths": {
"@revrag-ai/embed-react/react17": ["./node_modules/@revrag-ai/embed-react/index.d.ts"],
"@revrag-ai/embed-react/diagnostics": ["./node_modules/@revrag-ai/embed-react/diagnostics.d.ts"]
}
}
}Do not up- or downgrade the host's unrelated dependencies to fit the SDK.
Every mismatch above has a workaround that leaves the host's versions alone.
6. TypeScript
| Versions | 4.9 (D) and 5.x (A, B) exercised |
moduleResolution | bundler or nodenext recommended. node (node10) needs the paths entries in §5 for subpaths |
| Types | Bundled (index.d.ts, diagnostics.d.ts). No @types package to install |
@types/react | Use the one that matches the host's React (17.x types for React 17). The SDK doesn't force one |
7. Browsers and runtime
| Requirement | Detail |
|---|---|
| JavaScript | ES2020 output (Vite's default library target: Chrome 87, Edge 88, Firefox 78, Safari 14). Older browsers need the host to transpile node_modules, and are untested |
| Calls | WebRTC + getUserMedia, in a secure context (HTTPS, or localhost) |
| Storage | sessionStorage is required: the widget doesn't render without it. localStorage is optional. IndexedDB is optional (falls back to memory) |
| Test on | Desktop Chrome and iOS Safari, on the production build. iOS Safari only allows the mic and audio after a user gesture |
| SSR | Safe to import on the server: nothing touches window at import. Hooks must run in client components |
8. Package managers
| Manager | Notes |
|---|---|
| npm 7+ | Installs peers automatically. Expect ERESOLVE only in the §5 cases |
| yarn classic | Doesn't install peers: make sure react / react-dom are present (they are in any React app) |
| yarn berry | Use nodeLinker: node-modules |
| pnpm | Works; check pnpm why react for a single copy in workspaces |
9. Out of scope
- Angular has its own package,
@revrag-ai/embed-angular— see the Angular integration guide. - Vue isn't supported by this package.
- React Native has its own package,
@revrag-ai/embed-react-native— see the React Native integration guide. - Plain
<script>/ CDN usage without a bundler is untested.
Setup code: React integration guide.
Support
- Docs: https://docs.revrag.ai
- Email: contact@revrag.ai
- Dashboard: app.revrag.ai