React SDK reference

The full API surface of @getuserfeedback/react — provider, hooks, events, and client options.

Last reviewed

React SDK reference

The React SDK wraps the same runtime as the JavaScript SDK in a provider plus hooks. If you haven't set up yet, start with the React SDK guide.

GetUserFeedbackProvider

Initializes the widget client and makes it available to all hooks below it.

TypeScriptapp.tsx
<GetUserFeedbackProvider clientOptions={{ apiKey: "YOUR_API_KEY" }}><App /></GetUserFeedbackProvider>

If the current app version supports a newly shipped feature, report that with capabilities:

TypeScriptapp.tsx
<GetUserFeedbackProviderclientOptions={{apiKey: "YOUR_API_KEY",capabilities: ["checkout.drawer"],}}><App /></GetUserFeedbackProvider>

clientOptions

OptionTypeDefaultDescription
apiKeystringrequiredYour project API key.
colorScheme"light" | "dark" | "system" | { autoDetectColorScheme: string[] }auto-detectColor scheme. See Dark mode.
defaultConsent"granted" | "pending" | "denied" | "revoked" | GrantScope[]"granted"Initial consent state. See Privacy & consent.
disableAutoLoadbooleanfalseWhen true, call client.load() manually before opening flows.
disableTelemetrybooleanfalseDisables anonymous performance telemetry. Does not affect user analytics.
flagsRecord<string, AppEventFlagValue> | AppEventFlag[]noneYour app's feature flag evaluations. Used by rolling theme updates.
capabilitiesArray<string | AppEventCapability>noneWhat the current app version can support. Used by capability conditions.
actionsActionRegistration[]noneStatic custom actions and an optional webpage-navigation override.

Actions (actions)

Use this when an Action button under End of flow should call code in your app. Action buttons are available for Widget flows, not hosted pages or embeds. They currently work only for surveys with one ending and are unavailable with conditional endings.

Register the action and mount the provider in your app. Discovery is best-effort; after the definition has been observed, open or refresh the survey editor to find it in the Action selector. Select the matching definition, set the button label, and save the flow. After the handler completes successfully, the Widget closes. The observed definition in the editor is only setup history—every live app still needs the exact registration.

<GetUserFeedbackProviderclientOptions={{apiKey: "YOUR_API_KEY",actions: [{ kind: "custom", key: "open-customer-workspace",version: 1,handler: () => openCustomerWorkspace(),}],}}><App /></GetUserFeedbackProvider>

Replace openCustomerWorkspace() with your app's function. The handler receives no arguments. Return or resolve within 10 seconds to report success. Throwing, rejecting, or taking longer reports failure. The response stays saved, the acknowledgment stays open, the button is disabled, and the Widget does not retry automatically.

Custom keys and versions must remain fixed for the provider's mounted lifetime; changing them throws during render. You may refresh handler functions while keeping the same definitions. Before display, automatic Widget flows that require a missing action are suppressed. An explicit useFlow({ flowId }).open() request rejects instead of rendering an incomplete flow.

version is a positive integer identifying the custom handler contract. Change it when the action's meaning changes incompatibly; authored flows require the exact key and version.

To let your app router handle webpage actions first, include one open-url registration in the same array:

actions: [{kind: "open-url",handler: ({ url, target }) => {if (target !== "self" || !canRouteInApp(url)) return "unhandled";void navigateInApp(url);return "handled";},}]

target is "self" for the current tab and "blank" for a new tab. It is undefined when the disposition is unavailable, such as for a targetless link or during a runtime rollout; return "unhandled" to preserve the existing browser behavior. The result is synchronous. Return "handled" only after your handler has synchronously accepted or committed the navigation command. That is terminal navigation success for the Flow Action Succeeded event; a later asynchronous router or destination load failure does not retract it. If your handler did not accept or commit the command, return "unhandled" so the Loader can use its browser fallback. A thrown handler or invalid result is treated as failure and claimed so it cannot cause an unexpected redirect.

useGetUserFeedback()

Returns the client instance with the same core methods as the JavaScript SDK.

  • identify(userId, traits?, options?) — associate a user ID, traits, and optional external IDs with the current user
  • identify(traits, options?) — associate traits with the current user
  • identify(traits, undefined, options?) — three-argument form for call sites that keep options separate
  • reset() — clear identity and auth state on logout
  • configure({ colorScheme?, consent?, auth?, capabilities? }) — update settings at runtime
  • track(eventName, properties?, options?) — track a product event with optional external IDs
  • graph.connect(relationship) — record that two product objects are connected
  • graph.disconnect(relationship) — record that the connection ended
  • load() — manually start the widget when disableAutoLoad is true
  • close() — close any open flow

Use capabilities when the supported capabilities become known or change after the widget has loaded:

import { useEffect } from "react";import { useGetUserFeedback } from "@getuserfeedback/react";function CheckoutRouteCapabilities() {const client = useGetUserFeedback();useEffect(() => {client.configure({capabilities: ["checkout.drawer", "messages.compose.v2"],});}, [client]);return null;}

The widget checks for newly eligible flows after capabilities change. See Capabilities.

Events

We recommend sending product events server-side through an integration such as Segment. If client-side tracking fits your app better, track(eventName, properties?, options?) records an event from the browser.

const client = useGetUserFeedback();client.track("Checkout Started", {plan: "pro",source: "billing_page",});

You can call track() before or after login. When the same person is later identified, Identity resolution merges their events into a single profile. See Events for reference.

Use options.externalIds when an identify or track call carries an identifier from another system, such as a Shopify customer ID. External IDs help match profiles, but they are not traits by themselves. Do not put Segment-shaped externalIds in traits or event properties.

await client.identify("user_123", { email: "jane@example.com" }, {externalIds: [{id: "gid://shopify/Customer/123",type: "shopify_customer_id",collection: "users",encoding: "none",},],});client.track("Checkout Started", { plan: "pro" }, {externalIds: [{id: "gid://shopify/Customer/123",type: "shopify_customer_id",collection: "users",encoding: "none",},],});

Relationships

The client also exposes graph.connect() and graph.disconnect() for ordinary relationship observations:

const relationship = {from: { collection: "user", id: "user_123" },to: { collection: "account", id: "acct_456" },};await client.graph.connect(relationship);await client.graph.disconnect(relationship);

See Groups for audience behavior and current limitations.

useFlow(options)

The main hook for working with a specific flow.

TypeScriptfeedback-button.tsx
const { open, prerender, isLoading } = useFlow({flowId: "YOUR_FLOW_ID",});

Options

OptionTypeDefaultDescription
flowIdstringrequiredThe flow ID to target.
prefetchOnMountbooleanfalsePrefetch flow resources when the component mounts.
hideCloseButtonbooleanfalseHide the default close button.
container"default" | "custom""default"Use "custom" to render inside your own element. See Containers.

Return value

  • open(options?) — open the flow (options include metadata)
  • prefetch() — load flow resources over the network
  • prerender() — warm up the UI before opening
  • close() — close the flow
  • setOpen(boolean) — declarative open/close
  • isLoadingtrue after open() is requested while the flow is not visible yet
  • shouldRenderContainertrue when using container: "custom" and the container should be in the DOM
  • containerRef — ref to attach to your container element
  • width / height — recommended dimensions for custom containers

These methods return promises, but both fire-and-forget and await are valid. See JavaScript SDK reference for the execution model.

Example:

TypeScriptfeedback-button.tsx
const { open } = useFlow({ flowId: "YOUR_FLOW_ID" });await open({metadata: {tags: {journey_stage: "onboarding",task_type: "report-export",},},});

For metadata examples and supported value shapes, see Response metadata.

useDefaultFlowContainer()

Returns the default container ref and dimensions. Useful when you want to customize the container wrapper but keep the default sizing behavior.