Skip to content
UpVoiced Docs

UpVoiced Docs · Widget

JavaScript API reference

w.js replaces window.UpVoiced with the API below. Calls made earlier through the queue stub run in order as soon as it loads. The API never throws into your page and never exposes the session token.

Methods

identify

UpVoiced.identify({ token }) / UpVoiced.identify(null)

Signs in the person signed in to your app with a token from your server, or signs out with null. Returns a promise that never rejects: { ok: true, user } or { ok: false, error }. See Identify signed-in users.

open

UpVoiced.open(tab?)

Opens the panel, on 'feedback', 'roadmap' or 'whats-new' when that tab is enabled (otherwise the first tab).

close

UpVoiced.close()

Closes the panel and returns focus to where it was. Does nothing for an inline (data-mount) widget.

config

UpVoiced.config({ position, launcher, theme, accent, radius, offset, tabs })

Overrides your settings and the script attributes on this page. Each call merges with the previous ones; invalid values are ignored. tabs narrows the enabled tabs, never adds one.

on

UpVoiced.on(event, listener)

Listens to ready, open, close, identify and unread. A listener added after ready has fired is called once right away. Errors thrown by listeners are caught.

track

UpVoiced.track(event, properties?)

Reserved for in-app surveys; accepted and recorded, but it sends nothing yet.

Precedence, lowest first: your dashboard settings, thescript tag attributes, then config().

Properties

  • UpVoiced.user: the identified user (id, name, email, avatarUrl) or null.
  • UpVoiced.workspace: the slug from data-workspace.
  • UpVoiced.version: the loader version.
  • UpVoiced.calls: the commands received so far, for debugging; identify arguments are shown as [redacted].

Events

EventPayloadWhen
readynoneThe launcher (or inline panel) is on the page. Fires once.
open{ tab }The panel opened (tab is the requested tab or null).
closenoneThe panel closed.
identify{ ok, user } or { ok, error }An identify settled, or the session expired (error: "session_expired").
unread{ changelog, statusChanges }Unread state for the signed-in user changed (launcher dot).

Examples

// Your own "Feedback" button instead of the launcher (script tag: data-launcher="none").
document.querySelector('#feedback-button').addEventListener('click', function () {
  UpVoiced.open();
});

// Jump to the roadmap from a "What's planned?" link.
UpVoiced.open('roadmap');

// Dark pages: follow your app's theme switch.
UpVoiced.config({ theme: 'dark' });

// Only the Feedback tab on the checkout page (never adds a tab you turned off).
UpVoiced.config({ tabs: ['feedback'] });

// Show your own badge when there is news for the signed-in user.
UpVoiced.on('unread', function (unread) {
  badge.hidden = !(unread.changelog || unread.statusChanges > 0);
});

TypeScript

// upvoiced.d.ts: types for window.UpVoiced (copy into your project).
export type UpVoicedTab = 'feedback' | 'roadmap' | 'whats-new';

export interface UpVoicedUser {
  id: string;
  name: string | null;
  email: string | null;
  avatarUrl: string | null;
}

export type UpVoicedIdentifyResult =
  | { ok: true; user: UpVoicedUser | null }
  | { ok: false; error: string };

export interface UpVoicedConfig {
  position?: 'bottom-right' | 'bottom-left' | 'right-middle' | 'left-middle';
  launcher?: 'icon' | 'pill' | 'tab' | 'none';
  theme?: 'light' | 'dark' | 'auto';
  accent?: string; // #rrggbb
  radius?: 'none' | 'sm' | 'md' | 'lg' | 'full';
  offset?: number | string | { x: number; y: number }; // px, 0–200
  tabs?: UpVoicedTab[];
}

export interface UpVoicedEvents {
  ready: undefined;
  open: { tab: UpVoicedTab | null };
  close: undefined;
  identify: UpVoicedIdentifyResult;
  unread: { changelog: boolean; statusChanges: number };
}

export interface UpVoicedApi {
  readonly version: string;
  readonly workspace: string;
  readonly user: UpVoicedUser | null;
  identify(input: { token: string } | null): Promise<UpVoicedIdentifyResult>;
  config(options: UpVoicedConfig): void;
  open(tab?: UpVoicedTab): void;
  close(): void;
  on<E extends keyof UpVoicedEvents>(event: E, listener: (payload: UpVoicedEvents[E]) => void): void;
  track(event: string, properties?: Record<string, unknown>): void;
}

declare global {
  interface Window {
    UpVoiced?: UpVoicedApi;
  }
}