Events

Track product actions, browser pages, and native application screens.

Last reviewed

Use events to report product activity and locations to getuserfeedback.com. The client methods use the same properties and options shape, but each method describes a different kind of event:

  • track() records a product action, such as a checkout starting.
  • page() records a browser document or web location, with an optional name. The URL, path and query string are captured separately when you call it.
  • screen() records an application screen in a native app, with an optional name. An omitted page or screen name stays absent.

We recommend sending product events through a connected integration such as Segment when it already owns event delivery for your app. If client-side tracking fits your app better, call these methods directly.

page() and screen() are explicit calls. The SDKs do not automatically send these events when navigation changes unless you opt in to a React Native screen-tracking adapter below. Browser URL targeting still observes the current browser location automatically; that context is separate from a persisted page() event.

Examples

JavaScript SDK

TypeScriptevents.ts
import { createClient } from "@getuserfeedback/sdk";const client = createClient({ apiKey: "YOUR_API_KEY" });await client.track("Checkout Started", { plan: "pro" });await client.page(); // Record the current location without a page name.

React SDK

Call the methods from a component below GetUserFeedbackProvider:

TypeScriptevents.tsx
import { useEffect } from "react";import { useGetUserFeedback } from "@getuserfeedback/react";export function CheckoutButton() {const client = useGetUserFeedback();const recordCheckout = async () => {try {await client.track("Checkout Started", { plan: "pro" });} catch (error) {console.error("Unable to track event", error);}};return (<button type="button" onClick={() => void recordCheckout()}>Start checkout</button>);}function BillingPage() {const client = useGetUserFeedback();useEffect(() => {const recordPage = async () => {try {await client.page("Billing");} catch (error) {console.error("Unable to record page", error);}};void recordPage();}, [client]);return null;}

React Native SDK

Call screen() when your app navigation changes:

TypeScriptevents.tsx
import { useEffect } from "react";import { useGetUserFeedback } from "@getuserfeedback/react-native";export function CheckoutScreen() {const client = useGetUserFeedback();useEffect(() => {const recordScreen = async () => {try {await client.screen("Checkout");} catch (error) {console.error("Unable to record screen", error);}};void recordScreen();}, [client]);return null;}

Handle errors

Event methods can report failures in two ways. Some invalid arguments throw before the method returns. Other validation or command-processing failures reject the returned promise.

Call the method inside an async function with try/catch, as the React and React Native examples above do, when you need to handle both kinds of failure. A chained .catch() handles promise rejection but cannot catch an earlier synchronous error. A resolved event command also does not guarantee that best-effort analytics delivery succeeded downstream.

React Native screen tracking

Screen tracking is opt-in. Mount the tracking hook below GetUserFeedbackProvider, then choose one path for your app's navigation:

React Navigation

Use the shipped adapter with the same ref you pass to NavigationContainer:

TypeScriptapp-navigation.tsx
import {NavigationContainer,useNavigationContainerRef,} from "@react-navigation/native";import { useReactNavigationScreenTracking } from "@getuserfeedback/react-native/react-navigation";export function AppNavigation() {const navigationRef = useNavigationContainerRef();useReactNavigationScreenTracking(navigationRef);return (<NavigationContainer ref={navigationRef}><AppRoutes /></NavigationContainer>);}

Expo Router

Render a tracker below GetUserFeedbackProvider, for example from your root layout:

TypeScriptscreen-tracking.tsx
import { usePathname } from "expo-router";import { useExpoRouterScreenTracking } from "@getuserfeedback/react-native/expo-router";export function ScreenTracking() {const pathname = usePathname();useExpoRouterScreenTracking(pathname);return null;}

Expo Router records the pathname in properties.path, without a screen name. Use toScreen to add a name or other properties, or return null to skip a path. React Navigation uses the route's name. Both adapters accept options for mapping route data and handling tracking errors.

The Expo adapter also supplies its pathname for Current URL targeting. The React Navigation adapter does not currently supply a URL. Calling screen() directly records a visit without changing the current URL.

Any other router

Call client.screen() from your router's current-screen state. Pass a stable key for the active route occurrence so repeated notifications and React Strict Mode do not record the same occurrence twice:

TypeScriptscreen-tracker.tsx
import { useEffect, useRef } from "react";import { useGetUserFeedback } from "@getuserfeedback/react-native";export function ScreenTracker({routeKey,screenName,}: {routeKey: string;screenName: string;}) {const client = useGetUserFeedback();const lastRoute = useRef({ client, routeKey: null as string | null });useEffect(() => {if (lastRoute.current.client === client &&lastRoute.current.routeKey === routeKey) {return;}lastRoute.current = { client, routeKey };const reportScreen = async () => {try {await client.screen(screenName);} catch (error) {console.error("Unable to record screen", error);}};void reportScreen();}, [client, routeKey, screenName]);return null;}

Use one tracking path for a navigation tree. All three paths record a screen when the active route changes.

Shared call shape

MethodUse it forName argument
track(eventName, properties?, options?)A product actionRequired and trimmed to 1-255 characters.
page(name?, properties?, options?)A browser page or web locationOptional. A supplied name is trimmed to 1-255 characters.
screen(name?, properties?, options?)A native application screenOptional. A supplied name is trimmed to 1-255 characters.

Names reserved for getuserfeedback.com system events, such as Flow Viewed, cannot be used for customer events.

Use page() in the JavaScript and React SDKs. Use screen() in the React Native SDK. Call the method from your router or navigation integration when the location changes. This reference covers both direct calls and the opt-in React Native screen-tracking adapters.

Properties and options

The event methods accept the same optional properties and options values:

FieldRequiredShape
propertiesNoAn object with string keys and JSON-compatible values.
options.messageIdNoA caller-supplied, non-empty string up to 255 characters.
options.externalIdsNoUp to 20 Segment-compatible external user IDs.

Supported property values are strings, numbers, booleans, null, arrays of supported values, and nested objects with string keys. Send dates as ISO 8601 strings. Convert functions, class instances, DOM nodes, undefined, and circular objects before calling an event method.

Use externalIds for an identifier from another system. Each entry uses an ID, type, collection: "users", and encoding: "none":

client.track("Checkout Started",{ plan: "pro" },{externalIds: [{id: "gid://shopify/Customer/123",type: "shopify_customer_id",collection: "users",encoding: "none",},],});

External IDs help match profiles, but they are not traits or event properties. Do not put Segment-shaped external IDs inside properties.

The id must be nonblank. The type must start with a lowercase letter or number and can contain lowercase letters, numbers, underscores, dots, and hyphens.

messageId is the identity of one event occurrence. Generate a new value for each new occurrence and preserve it when that same occurrence is passed through another delivery path:

function reportCheckoutStarted(event: { messageId: string; orderId: string }) {return client.track("Checkout Started",{ orderId: event.orderId },{ messageId: event.messageId });}

getuserfeedback.com preserves messageId unchanged. It is not a command idempotency key and does not promise deduplication across delivery channels.

Event names

Name events after what happened or what location was reported:

  • track("Checkout Started") describes a product action.
  • page("Billing") describes a browser page or web location.
  • screen("Checkout") describes a native application screen.

You can call event methods before or after login. When the same person is later identified, Identity resolution can merge their events into a single profile.

When defaultConsent is "pending" or analytics consent is denied, client-side event delivery follows the widget consent state.

Flow Action Succeeded

For supported Widget actions, getuserfeedback.com records Flow Action Succeeded when a registered handler returns or resolves successfully, or when a supported navigation is accepted.

Flow Action Succeeded does not confirm that a destination loaded or that an external effect completed after the handler returned. Reporting is best effort, so a missing event does not prove that the action did not run or succeed.

See Actions for the shared custom action contract.

The event includes these getuserfeedback.com-owned properties:

PropertyMeaning
gx_event_schemaStable event identity: gx_flow_action_succeeded.
gx_event_schema_versionContract version. The current version is 1.
gx_flow_idFlow containing the action.
gx_flow_version_idExact Flow version containing the action.
gx_flow_version_numberPublished version number.
gx_flow_run_idFlow run that invoked the action.
gx_flow_surfaceSurface where the Flow ran.
gx_action_idStable placement of this action in the authored Flow.
gx_action_invocation_idLogical invocation that produced this success.
gx_action_keyAction definition key.
gx_action_versionAction definition version.
gx_action_kindAction kind, such as runtime-action or navigation-action.