/** * getuserfeedback widget SDK public API. * * {@link FlowState} lives in `./host-event-contract` (re-exported from the `@getuserfeedback/protocol/host` barrel). */ import type { AppEventOccurrenceType } from "../app-event.js"; import type { CaptureInstanceFeedbackRequest, ListInstanceFeedbackMineRequest } from "../instance-feedback.js"; import type { Scope } from "../scopes.js"; export type HostActionDefinition = import("../widget-config.js").HostActionDefinition; export type { AppEventOccurrenceType } from "../app-event.js"; /** * Identifier types supported by event tracking and identity resolution. * * Business-specific identifiers are sent as Segment-compatible * `context.externalIds` entries on app events or identify options. * * @see https://getuserfeedback.com/docs/guides/identity-resolution */ export type AppEventIdentityType = "anonymousId" | "userId" | "traits.email" | "traits.phone" | "context.device.id" | "context.device.advertisingId" | "context.device.token"; /** A single standard identifier, such as a user ID, anonymous ID, email, or device ID. */ export type AppEventIdentity = { type: AppEventIdentityType; value: string; }; /** * Segment-compatible external identifier. * * Only `collection: "users"` participates in person identity resolution today. * External IDs help match profiles, but they are not traits by themselves. * * @see https://getuserfeedback.com/docs/guides/identity-resolution */ export type AppEventExternalId = { id: string; type: string; collection: "users"; encoding: "none"; }; /** Page, feature flag, and capability context attached to an event. */ export type AppEventContext = { page?: { path?: string; referrer?: string; search?: string; }; locale?: string; userAgent?: string; externalIds?: AppEventExternalId[] | undefined; flags?: AppEventFlag[] | undefined; capabilities?: AppEventCapability[] | undefined; }; /** Supported feature flag value shape. */ export type AppEventFlagValue = string | number | boolean | null | AppEventFlagValue[] | { [key: string]: AppEventFlagValue; }; /** * Supported event property value shape. * * @see https://getuserfeedback.com/docs/reference/events */ export type AppEventJsonValue = AppEventFlagValue; /** Feature flag provider metadata. */ export type AppEventFlagProvider = { name: string; project?: string | undefined; environment?: string | undefined; }; /** Feature flag evaluation context attached to widget initialization or events. */ export type AppEventFlag = { key: string; target?: string | undefined; value: AppEventFlagValue; variant?: string | undefined; origin?: "runtime_config" | "trigger_context" | "provider_sync" | "api"; provider?: AppEventFlagProvider | undefined; status?: string | undefined; reason?: string | undefined; evaluatedAt?: string | undefined; }; /** * A host capability the current app version supports. * * Use capabilities when a survey should only display after the current app * version can support it, such as `checkout.drawer` or `messages.compose`. * * @see https://getuserfeedback.com/docs/guides/advanced/runtime-capabilities */ export type AppEventCapability = { key: string; source?: string | undefined; provider?: AppEventFlagProvider | undefined; }; /** Feature flag evaluations accepted by SDK initialization. */ export type FlagsInput = AppEventFlag[] | Record; /** Host capabilities accepted by SDK initialization and `client.configure()`. */ export type CapabilitiesInput = Array; /** Optional fields shared by event payloads. */ export type AppEventBase = { traits?: Record | undefined; identities?: AppEventIdentity[] | undefined; context?: AppEventContext | undefined; messageId?: string | undefined; timestamp?: number | undefined; }; /** Reference to a specific survey or flow. */ export type AppEventSurveyReference = { surveyId: string; }; export type LegacyFlowRunProperties = { gx_flow_run_id: string; }; /** Event payload emitted when a flow is shown. */ export type FlowViewedPayload = AppEventBase & { origin?: "system" | undefined; event: "Flow Viewed"; references: AppEventSurveyReference; properties?: LegacyFlowRunProperties | undefined; }; /** Event payload emitted when a user dismisses a flow. */ export type FlowDismissedPayload = AppEventBase & { origin?: "system" | undefined; event: "Flow Dismissed"; references: AppEventSurveyReference; properties?: LegacyFlowRunProperties | undefined; }; /** * Event payload sent with `client.track()`. * * @see https://getuserfeedback.com/docs/reference/events */ export type CustomerTrackPayload = AppEventBase & { origin: "customer"; type?: "track" | undefined; event: string; properties?: Record | undefined; }; /** Customer occurrence payload accepted by the source-neutral app-event wire contract. */ export type CustomerOccurrencePayload = AppEventBase & { origin: "customer"; type?: AppEventOccurrenceType | undefined; event: string; properties?: Record | undefined; }; /** * Event payload union. Use `origin` as the discriminator when handling the * union directly. */ export type AppEventPayload = FlowViewedPayload | FlowDismissedPayload | CustomerOccurrencePayload; /** How the widget was loaded, such as SDK, GTM, Segment, or a custom loader. */ export type ClientMetaLoader = "sdk" | "gtm" | "segment" | "rudderstack" | "tealium" | "custom"; /** Delivery method for the widget script. */ export type ClientMetaTransport = "script-tag" | "esm" | "loader" | "tag-manager" | "snippet"; /** Detected or configured front-end framework. */ export type ClientMetaRuntimeFramework = "next" | "vite" | "webpack" | "plain"; /** Runtime environment (browser or edge). */ export type ClientMetaRuntimeEnv = "browser" | "edge"; /** Metadata about the client integration, used for diagnostics and support. */ export type ClientMeta = { loader: ClientMetaLoader; clientName?: string | undefined; clientVersion?: string | undefined; protocolCapabilities?: string[] | undefined; integrator?: { name?: string | undefined; version?: string | undefined; } | undefined; transport?: ClientMetaTransport | undefined; runtime?: { framework?: ClientMetaRuntimeFramework | undefined; runtime?: ClientMetaRuntimeEnv | undefined; } | undefined; notes?: string | undefined; }; export type RuntimeEndpoints = { apiUrl?: string | undefined; coreUrl?: string | undefined; realtimeUrl?: string | undefined; }; /** A single response metadata tag value preserved with a submitted response. */ export type ResponseMetadataTagValue = string | string[]; /** Optional metadata tags the host can attach to a widget flow run. */ export type ResponseMetadataInput = { tags?: Record | undefined; }; /** * Use host attributes to auto-detect the color scheme ("light" by default). The widget observes these attributes on body and html elements, * * class="dark" or data-theme="dark" on html or body elements will set the widget to dark mode. * * class="light" or data-theme="light" will set the widget to light mode. * * class="system" or data-theme="system" will set the widget to follow the user's OS/browser preference (prefers-color-scheme). */ export type ColorSchemeAutoDetect = { /** List of host attribute names (html or body) to observe for color scheme. * * Default: ["class", "data-theme"] */ autoDetectColorScheme: string[]; }; /** * Color scheme: either auto-detect from host html and body attributes (default) or provide an explicit value. * - { autoDetectColorScheme: ["class", "data-theme"] } * - "light" | "dark" | "system" */ export type ColorSchemeConfig = ColorSchemeAutoDetect | "light" | "dark" | "system"; /** Whether telemetry is enabled. */ export type TelemetryConfig = { enabled?: boolean | undefined; }; /** When true, prints debug logs to console. Narrow down with a namespace string/array eg. `["loader", "handshake"]`. Default `false`. */ export type DebugConfig = boolean | string | string[]; /** Status of a consent decision (pending, granted, denied, revoked). */ export type ConsentStatus = "pending" | "granted" | "denied" | "revoked"; /** * Supported consent scope identifiers for explicit allow-list grants (full CMP-aligned set). * Alias for {@link Scope}; kept for backward-compatible imports. */ export type GrantScope = Scope; /** Consent configuration. Use a single decision for all scopes, or provide an explicit allow-list of granted scopes. */ export type ConsentConfig = ConsentStatus | Scope[]; /** Auth configuration, such as a JWT for authenticated flows. */ export type AuthConfig = { jwt?: { token: string; } | null | undefined; }; /** * Runtime configuration updates accepted by `client.configure()`. * * @see https://getuserfeedback.com/docs/security-and-privacy/compliance-and-consent */ export type ConfigureOptions = { colorScheme?: ColorSchemeConfig | undefined; consent?: ConsentConfig | undefined; auth?: AuthConfig | undefined; /** * Capabilities currently supported by the host app version. * * Updating capabilities makes the widget check again for surveys that are now * eligible to display. * * @see https://getuserfeedback.com/docs/guides/advanced/runtime-capabilities */ capabilities?: CapabilitiesInput | undefined; }; /** A grouped host-provided implementation for customer-defined widget actions. */ export type ActionsConfig = { /** Customer-defined action definitions available to the widget. */ definitions: HostActionDefinition[]; /** Handles the exact definition requested by the widget. */ handler: (definition: HostActionDefinition) => void | Promise; }; /** Authored HTTP(S) link request offered to the host router. */ export type LinkRequest = { url: string; target?: "self" | "blank"; }; /** Synchronously claims an authored HTTP(S) link for the host application. */ export type LinkRouter = (request: LinkRequest) => undefined; /** Host link integration for authored HTTP(S) destinations. */ export type LinksConfig = { router: LinkRouter; }; /** Legacy per-action registrations, including the current browser URL override. */ export type ActionRegistration = { /** A customer-defined, no-argument action selected in the survey editor. */ kind: "custom"; key: string; /** Positive integer identifying the handler contract. Exact matches only. */ version: number; handler: () => void | Promise; } | { /** Optional override for authored HTTP(S) webpage actions. */ kind: "open-url"; /** * Return `handled` only after synchronously accepting or committing the * navigation command. That is terminal navigation success for the * Flow Action Succeeded event; a later asynchronous route or destination * load failure does not retract it. Return `unhandled` when the handler did * not accept or commit the command so Loader browser navigation can run. * Throwing or returning an invalid result is failure and suppresses fallback. * Target is absent when its disposition is unavailable to this runtime. */ handler: (request: { url: string; target?: "self" | "blank"; }) => "handled" | "unhandled"; }; /** @internal Options when initializing the widget: API key, color scheme, disableTelemetry, enableDebug, defaultConsent, capabilities, and optional host targeting context. */ export type InitOptions = { apiKey: string; colorScheme?: ColorSchemeConfig | undefined; disableTelemetry?: boolean | undefined; enableDebug?: DebugConfig | undefined; defaultConsent?: ConsentConfig | undefined; clientMeta?: ClientMeta | undefined; capabilities?: string[] | undefined; flags?: AppEventFlag[] | undefined; hostCapabilities?: AppEventCapability[] | undefined; hostActions?: HostActionDefinition[] | undefined; runtimeEndpoints?: RuntimeEndpoints | undefined; }; export type ClientOptions = { /** Your project API key. */ apiKey: string; /** Color scheme config: host-driven (loader observes attributes) or explicit. */ colorScheme?: ColorSchemeConfig | undefined; /** * Initial consent state. * * Default: `granted` (all scopes). * * Accepts either a single decision (`granted` | `denied` | `pending` | `revoked`) * or an explicit allow-list of additional granted scopes (`Scope[]`). * * For strict privacy guarantees, use `pending` at init time and later call `client.configure({ consent })` after * the user makes a consent choice via your CMP or UI. * * In array form, listed scopes are granted and all other non-essential scopes are denied. * * Essential baseline scopes are always granted for core widget operation and cannot be denied: * - `functionality.storage` * - `security.storage` * * @see https://getuserfeedback.com/docs/security-and-privacy/compliance-and-consent */ defaultConsent?: ConsentConfig | undefined; /** When true, prints debug logs to console. Narrow down with a namespace string/array eg. ```["loader", "handshake"]```. Default `false`. */ enableDebug?: DebugConfig | undefined; /** * When true, the widget does not load automatically. Provide the initial * color scheme, default consent, and capabilities in these options, then call * `client.load()` before runtime `configure()` calls or commands. Configure * auth after `load()`. A `configure()` call made before `load()` resolves * without applying its update. Default `false`. */ disableAutoLoad?: boolean; /** Disable anonymous widget telemetry. * * When `true`, telemetry is not sent. * * This flag does not disable user targeting and reporting analytics. It's used (by us) for performance monitoring and error tracking. * * Included telemetry data when enabled: apiKey, ephemeral one-time session id, * execution flow, event timestamps, and page origin (domain name). * * Excluded by default: user identity and detailed page fields (path/referrer/search). */ disableTelemetry?: boolean | undefined; /** Feature flag evaluations collected with widget initialization. */ flags?: FlagsInput | undefined; /** * Capabilities supported by the current app version. Use this when a survey * should only display after that version can support it. * * @see https://getuserfeedback.com/docs/guides/advanced/runtime-capabilities */ capabilities?: CapabilitiesInput | undefined; /** Synchronously claims authored HTTP(S) links for the host application. */ links?: LinksConfig | undefined; /** * Widget actions available to this client. Definitions may change before * loading starts and become static once initialization begins. Calling * `createClient` again with the same canonical definitions refreshes their * handlers. Prefer the grouped configuration; the registration array remains * for compatibility. */ actions?: ActionsConfig | ActionRegistration[] | undefined; _loaderUrl?: string | undefined; _coreUrl?: string | undefined; _apiUrl?: string | undefined; _realtimeUrl?: string | undefined; }; /** Open a flow with a given instance. Omit flowHandleId for first open; core returns it in settlement. */ export type OpenCommandPayload = { kind: "open"; flowId: string; flowHandleId?: string | undefined; container?: HTMLElement | null | undefined; /** Optional metadata tags to persist with the eventual response submission. */ metadata?: ResponseMetadataInput | undefined; /** * When `true`, the flow view does not show a close button. * Useful for mobile or embedded contexts where the host handles dismissal (e.g. via a drawer or back gesture). */ hideCloseButton?: boolean | undefined; }; /** Prefetch a flow. Omit flowHandleId for first prefetch; core returns it in settlement. */ export type PrefetchCommandPayload = { kind: "prefetch"; flowId: string; flowHandleId?: string | undefined; }; /** Prerender a flow. Omit flowHandleId for first prerender; core returns it in settlement. */ export type PrerenderCommandPayload = { kind: "prerender"; flowId: string; flowHandleId?: string | undefined; /** * When `true`, the prerendered view does not show a close button. */ hideCloseButton?: boolean | undefined; }; /** Identify with traits only (`client.identify(traits)` or `client.identify(traits, options)`). */ export type IdentifyTraitsOnlyCommandPayload = { kind: "identify"; traits: Record; options?: IdentifyOptions | undefined; }; /** Identify with userId, optional traits, and optional external IDs (`client.identify(userId, traits?, options?)`). */ export type IdentifyUserCommandPayload = { kind: "identify"; userId: string; traits?: Record | undefined; options?: IdentifyOptions | undefined; }; /** Identify command payload: either traits-only or userId+traits shape. */ export type IdentifyCommandPayload = IdentifyTraitsOnlyCommandPayload | IdentifyUserCommandPayload; /** * Optional identity context accepted by `client.identify()`. * * Use `externalIds` for Segment-compatible identifiers from another system, * such as Shopify customer IDs or Salesforce contact IDs. Without a user ID, * pass options as `client.identify(traits, options)`, or use * `client.identify(traits, undefined, options)` when your call site needs the * explicit three-argument form. Do not put Segment-shaped `externalIds` in * traits. * * @see https://getuserfeedback.com/docs/guides/identity-resolution */ export type IdentifyOptions = { externalIds?: AppEventExternalId[] | undefined; }; /** * Optional context accepted by `client.track()`. * * `messageId` is caller-supplied identity, up to 255 characters, preserved for * ingestion and exact-ID-capable deduplication. It does not provide a * cross-lane guarantee. * Use `externalIds` when the event carries a Segment-compatible identifier * from another system. Do not put Segment-shaped `externalIds` in properties. * * @see docs/specs/2026-08-28-sdk-track-message-id.md * @see https://getuserfeedback.com/docs/reference/events */ export type TrackOptions = { messageId?: string | undefined; externalIds?: AppEventExternalId[] | undefined; }; /** * Command payload for `client.track()`. * * @see https://getuserfeedback.com/docs/reference/events */ export type AppEventCommandPayload = CustomerOccurrencePayload & { kind: "track"; }; /** Compatibility name for the release-compatible `track` command kind. */ export type TrackCommandPayload = AppEventCommandPayload; /** Attach or detach a resolved flow handle from a host container. */ export type SetContainerCommandPayload = { kind: "setContainer"; flowHandleId: string; container: HTMLElement | null; }; /** Default container behavior for flows in an instance. */ export type ContainerPolicy = { kind: "floating"; } | { kind: "hostContainer"; host: HTMLElement | null; sharing: "shared" | "perFlowRun"; }; /** Set the instance-level default container policy. */ export type SetDefaultContainerPolicyCommandPayload = { kind: "setDefaultContainerPolicy"; policy: ContainerPolicy; }; /** Update color scheme, consent, and auth. */ export type ConfigureCommandPayload = { kind: "configure"; opts: ConfigureOptions; }; /** Initialize the widget with options. */ export type InitCommandPayload = { kind: "init"; opts: InitOptions; }; /** Close a flow. */ export type CloseCommandPayload = { kind: "close"; flowHandleId?: string | undefined; }; /** Reset widget state. */ export type ResetCommandPayload = { kind: "reset"; }; /** @internal Capture feedback as an evaluation of an app or object. */ export type InstanceFeedbackCaptureCommandPayload = { kind: "instanceFeedback.capture"; payload: CaptureInstanceFeedbackRequest; }; /** @internal List the authenticated user's evaluations matching selectors. */ export type InstanceFeedbackListMineCommandPayload = { kind: "instanceFeedback.listMine"; payload: ListInstanceFeedbackMineRequest; }; /** Host navigation and environment context for embedded runtimes. */ export type HostContext = { url: string; env?: Record | undefined; storage?: Record | undefined; page?: { path?: string | undefined; referrer?: string | undefined; search?: string | undefined; } | undefined; }; /** Update host navigation context for embedded runtimes. */ export type UpdateHostContextCommandPayload = { kind: "updateHostContext"; context: HostContext; }; /** Emit a host-specific signal into the widget runtime. */ export type EmitHostSignalCommandPayload = { kind: "emitHostSignal"; name: string; data?: unknown; }; /** Union of widget action payloads such as open, prefetch, identify, configure, and track. */ export type PublicCommandPayload = OpenCommandPayload | PrefetchCommandPayload | PrerenderCommandPayload | IdentifyCommandPayload | UpdateHostContextCommandPayload | EmitHostSignalCommandPayload | SetContainerCommandPayload | SetDefaultContainerPolicyCommandPayload | ConfigureCommandPayload | InitCommandPayload | CloseCommandPayload | ResetCommandPayload | InstanceFeedbackCaptureCommandPayload | InstanceFeedbackListMineCommandPayload | TrackCommandPayload; /** Input for a single widget action; same shape as {@link PublicCommandPayload}. */ export type Command = PublicCommandPayload; /** Wrapper for a widget action (version, request id, idempotency key, optional client metadata, and the action payload). */ export type CommandEnvelope = { version: "1"; instanceId?: string | undefined; requestId: string; idempotencyKey: string; clientMeta?: ClientMeta | undefined; command: PublicCommandPayload; }; /** Public command envelope with a required instance id for loader dispatch. */ export type CommandEnvelopeWithInstanceId = CommandEnvelope & { instanceId: string; }; /** Identity kind for telemetry events; same as {@link AppEventIdentityType}. */ export type TelemetryIdentityType = AppEventIdentityType; /** * Event passed to the `beforeSend` hook in {@link Client.use}. * When `debug` is true, identities and full page context are included; when false, no identities and page is origin-only. * * TODO(migration): Rename this SDK-facing type to WidgetTelemetryEvent in the * same change that updates SDK imports, so the generic TelemetryEvent name can * retire here without colliding with shared telemetry. * [from=TelemetryEvent-widget-surface] [to=WidgetTelemetryEvent] [scope=slice] [priority=low] */ export type TelemetryEvent = { type: string; timestamp: number; apiKey: string; /** When true, identities and full page context are present; when false, no identities and page.origin only. */ debug: boolean; identities: Array<{ type: TelemetryIdentityType; value: string; }>; context: { page: { path?: string | null | undefined; referrer?: string | null | undefined; search?: string | null | undefined; origin?: string | null | undefined; }; widgetVersion: string; clientMeta?: ClientMeta | undefined; }; properties?: Record | undefined; }; //# sourceMappingURL=sdk-types.d.ts.map