@userz-ai/react
v2.0.5
Published
React bindings for the Userz feedback widget.
Readme
@userz-ai/react
Idiomatic React bindings for the Userz feedback widget. A provider, a hook, and a component-targeting wrapper around @userz-ai/browser.
Install
pnpm add @userz-ai/react @userz-ai/browserScreenshot capture (modern-screenshot) ships as a transitive dependency of @userz-ai/browser — no extra install step required.
React 18 and 19 are both supported.
Quick start
// app/Userz.tsx — client component
'use client';
import { UserzProvider } from '@userz-ai/react';
export function Userz({ children }: { children: React.ReactNode }) {
return (
<UserzProvider
publicKey="pub_..."
// Private mode: return a JWT minted by your backend (see @userz-ai/node).
getUserToken={async () => sessionStore.getUserzToken()}
>
{children}
</UserzProvider>
);
}// Anywhere underneath the provider:
import { useUserz } from '@userz-ai/react';
function Header() {
const userz = useUserz();
return <button onClick={() => userz.open()}>Send feedback</button>;
}The provider accepts every UserzConfig field from @userz-ai/browser (publicKey, apiUrl, getUserToken, bubble, showEmailField, consoleCapacity, captureErrors, targetingChord, initialUser). It owns one Userz instance for the lifetime of the component and tears it down on unmount.
Like Sentry / Datadog SDKs, config changes after the first render are ignored. Use
setUser()andsetMetadata()via the hook for runtime updates.
useUserz()
Access the instance imperatively:
function IdentityBridge({ user }: { user: User | null }) {
const userz = useUserz();
useEffect(() => {
userz.setUser(
user ? { externalUserId: user.id, email: user.email } : null,
);
}, [user, userz]);
return null;
}<UserzTarget>
Mark a child as a "feedback target" the end-user can click while the targeting overlay is active (Ctrl+Shift+U by default). On click, the panel opens pre-filled with the target's name, your meta payload, and a cropped screenshot of just that element.
import { UserzTarget } from '@userz-ai/react';
<UserzTarget name="CheckoutButton" meta={{ variant, plan: 'pro' }}>
<button onClick={onCheckout}>Checkout</button>
</UserzTarget>| Prop | Required | Notes |
|---|---|---|
| name | yes | Display name surfaced as the targeted-component label in feedback. |
| meta | no | Opt-in metadata shipped with the report. Keep it small + non-sensitive — it lands in our backend in plaintext. |
| children | yes | A single child element. We clone it and attach a ref — no wrapper div, layout is unchanged. |
The child must accept a ref. DOM elements (<button>, <div>) and forwardRef components are fine. Plain function components without forwardRef get a display: contents wrapper — your layout still works, but forwardRef is preferred.
SSR / Next.js
The widget is browser-only. Mount the provider in a client component and render it from a server component:
// app/layout.tsx — server component
import { Userz } from './Userz';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<Userz>{children}</Userz>
</body>
</html>
);
}Docs
Full reference at userz.ai/docs/sdk/react. Source on GitHub.
License
MIT
