Open Widget flows from code
Open a Widget flow (survey, form, or message) from your app when the moment is right.
- Last reviewed
Open Widget flows from code
Most flows can be sent automatically from the getuserfeedback.com dashboard. Use On-demand Widget delivery when your app should decide when to ask, like after setup, from a dedicated feedback button, or from an inline thumbs up/down control. A flow can be a survey, a form, or a question-less in-app message.
Set the flow delivery channel to Widget and the delivery method to On-demand, then use the flow ID for the flow you want to open. Find it in the getuserfeedback.com dashboard under your flow's settings.
React SDK
import { useFlow } from "@getuserfeedback/react";import { Loader2 } from "lucide-react";function FeedbackButton() {const { isLoading, open } = useFlow({ flowId: "YOUR_FLOW_ID" });return (<buttondisabled={isLoading}type="button"onClick={() =>void open().catch((error) =>console.error("Unable to open feedback", error),)}>{isLoading ? <Loader2 /> : null}Give feedback</button>);}Use useFlow inside any component under GetUserFeedbackProvider. Handle the
returned promise when opening a flow.
React Native SDK
Use useFlow inside any component under GetUserFeedbackProvider. React
Native command methods return promises and reject on failure. Await when
sequencing matters; otherwise handle the rejection explicitly, typically with
void operation.catch(...):
import { Button } from "react-native";import { useFlow } from "@getuserfeedback/react-native";export function FeedbackButton() {const { open } = useFlow({ flowId: "YOUR_FLOW_ID" });return (<Buttontitle="Give feedback"onPress={() =>void open().catch((error) =>console.error("Unable to open feedback", error),)}/>);}Use client.flow(flowId) from useGetUserFeedback() when you need the same
operations outside a flow-specific hook.
JavaScript SDK
void client.flow("YOUR_FLOW_ID").open().catch((error) => console.error("Unable to open feedback", error));See Handle command promises for the promise handling pattern.
Use the same flow handle for prefetch(), prerender(), open(), and
close() when you want to keep one flow lifecycle together.
If you want to preserve lightweight response metadata, pass it on open():
await client.flow("YOUR_FLOW_ID").open({metadata: {tags: {journey_stage: "onboarding",survey_moment: "post-action",},},});Google Tag Manager / loader
async function openFeedback() {await window.__getuserfeedback?.flow("YOUR_FLOW_ID").open();}void openFeedback().catch((error) =>console.error("Unable to open feedback", error),);Make opening feel instant
If you know an on-demand Widget flow is likely to open, for example from a help menu item, you can prefetch and prerender it ahead of time:
React SDK
import { useFlow } from "@getuserfeedback/react";import { Loader2 } from "lucide-react";function HelpMenuFeedbackItem() {const { isLoading, prerender, open } = useFlow({flowId: "YOUR_FLOW_ID",prefetchOnMount: true,});const prepare = () =>void prerender().catch((error) =>console.error("Unable to prepare feedback", error),);return (<buttondisabled={isLoading}type="button"onMouseEnter={prepare}onFocus={prepare}onClick={() =>void open().catch((error) =>console.error("Unable to open feedback", error),)}>{isLoading ? <Loader2 /> : null}Share feedback</button>);}JavaScript SDK
const flow = client.flow("YOUR_FLOW_ID");async function prepareFeedback() {await flow.prefetch();await flow.prerender();}void prepareFeedback().catch((error) =>console.error("Unable to prepare feedback", error),);// Later, from the menu item:void flow.open().catch((error) =>console.error("Unable to open feedback", error),);Await preparation steps when they depend on one another, and handle the rejection from the overall operation. See Handle command promises for the promise handling pattern.
React Native SDK
Keep one flow object when preparation and opening belong to the same flow lifecycle:
import { useEffect, useMemo } from "react";import { Button } from "react-native";import { useGetUserFeedback } from "@getuserfeedback/react-native";export function HelpMenuFeedbackItem() {const client = useGetUserFeedback();const flow = useMemo(() => client.flow("YOUR_FLOW_ID"), [client]);useEffect(() => {void flow.prerender().catch((error) => console.error("Unable to prepare feedback", error));}, [flow]);return (<Buttontitle="Share feedback"onPress={() =>void flow.open().catch((error) => console.error("Unable to open feedback", error))}/>);}Prefetching loads flow resources over the network. Prerendering warms up the UI before opening. Opening still handles the render step if you have not prerendered first.
Common mistake
Don't call open() before the widget is initialized. If you set
disableAutoLoad: true, make sure client.load() has run first.