JavaScript API

Methods and events for driving the widget from your code.

Two surfaces, one runtime:

  • SDK: mount() returns a typed handle. Methods are namespaced: widget.chat.open(), widget.user.identify(...), widget.events.on(...).
  • Script tag: the runtime installs itself on window.Assistify once the loader script runs. Methods are flat: window.Assistify.open(), window.Assistify.identify(...), window.Assistify.reset().

Both surfaces share the same behaviour and the same event names. Examples below use the namespaced form; the flat equivalent is shown when it differs.

Lifecycle

load()

widget.load(): Promise<void>

Inject the loader script if not already injected, and resolve once the runtime fires ready. Idempotent: repeat calls return the same promise. Rejects on script-load failure (network, CSP, adblocker) or after a 30-second timeout.

You rarely need to call this directly. The default behaviour of mount() (or the <script> install) loads the runtime immediately. Call load() only when you mounted with autoload: false and want to trigger boot explicitly, for example after a consent banner. See Deferred boot.

reset()

widget.reset(): void

Flat: window.Assistify.reset()

Call this on logout. It wipes the session server-side and locally, then boots again as a fresh anonymous visitor, clearing:

  • The server-side session (DELETE /api/widget/session).
  • The assistify.<widgetId>.vid cookie, plus the localStorage and sessionStorage mirrors.
  • window.ASSISTIFY_USER and window.ASSISTIFY_CONFIG.identity if present.
  • Every data-user-* attribute the loader left on the <script> element.
  • The persisted UI state.

Host-registered event listeners survive the reset. The call returns immediately; listen for ready to know the post-reset boot completed.

If the widget has not loaded yet (autoload: false with no boot-triggering call), reset() only clears the visitor's local storage and does not load the widget, so a logout on a deferred page stays free of widget network activity.

destroy()

widget.destroy(): void

Flat: window.Assistify.destroy()

Tears the widget down: it removes the UI, releases listeners, and stops the runtime. Unlike reset() it leaves visitor storage on the host origin intact, which makes it the right call when an SPA route drops the chat; use reset() for logout.

Teardown is reversible within the same page session: calling mount() again, or any boot-triggering method on the handle (chat.open(), chat.toggle(), reset()), boots the widget back up and the returning visitor is recognized. Calls made between destroy() and the re-boot are buffered and replayed.

isReady()

widget.isReady(): boolean

true once the widget has booted and acquired a session token.

Chat

chat.open() / chat.close() / chat.toggle()

widget.chat.open();

Flat: window.Assistify.open(), Assistify.close(), Assistify.toggle().

Each emits the corresponding event with source: 'api'.

User

user.identify(identity)

widget.user.identify({
  email:    '[email protected]',
  userHash: 'HMAC_SHA256_OF_EMAIL',
});

Flat: window.Assistify.identify({ email, userHash }).

At least one of email, externalId, or discordId is required: that's the anchor the backend uses to look up or create the contact. userHash is the proof, not the identifier; sending only { userHash } is rejected.

The call returns immediately. Listen for identified to learn whether the identity was recorded as verified (verified: true) and whether the session was attached to a contact that already existed (merged: true). See Identity verification.

An unverified identify() never causes Assistify to email the visitor. Verification magic-links are sent only when the visitor asks for one inside the chat (typing their email in the identity form, or the resend action on the verification banner).

Successive calls merge top-level fields onto the last-known identity. Calling identify twice with different anchors creates separate contacts; for true user-switch see Lifecycle.

FieldType
emailstring
externalIdstringYour system's user ID
displayNamestringShown to your team as the contact's name. Latest identify wins, unless an agent set the name from the dashboard.
avatarUrlstringContact avatar. Latest identify wins.
discordIdstring
discordUsernamestring
discordAvatarstring
customAttributesRecord<string, JsonValue>Shallow-merged onto the contact on each identify; shown to your team in the dashboard and usable in proactive trigger conditions.
userHashstringHMAC-SHA256 of the anchor

Scalar customAttributes (string, number, boolean) can be targeted by proactive triggers: in the dashboard trigger builder, pick the Custom attribute field, type the attribute name (for example plan or cartTotal), choose an operator, and set a value. Numeric operators (>, <, …) coerce both sides to numbers, so cartTotal > 200 works whether you send 200 or "200". Nested objects and arrays are not matchable. Trigger targeting reads the identified contact's attributes, so the visitor must have called identify() first.

user.getVisitorId()

widget.user.getVisitorId(): string | null

The visitor's anonymous ID (anon_ plus 22 characters; see Visitor recognition), or null when no ID has been minted yet (the runtime mints one on first boot) or storage is unavailable.

Events

const unsubscribe = widget.events.on('ready', () => { /* ... */ });
unsubscribe();

Flat: window.Assistify.on('ready', cb) and Assistify.off('ready', cb).

EventPayload
ready{ widgetId }Fires once per boot, including after reset().
open{ source: 'api' | 'launcher' }
close{ source: 'api' | 'ui' | 'escape' }
identified{ verified, merged }Fires after identify() calls and when the visitor identifies themselves inside the chat (boot-time identity is reported by the boot itself). verified: true when the userHash supplied on that call matched the tenant secret; it reports each call's own verdict, so a broken signing setup shows up immediately. merged: true when the session was attached to a contact that already existed.
verified{ verifiedVia: 'HMAC' | 'MAGIC_LINK' | 'OAUTH', merged }Fires when a claimed email is proved: the visitor clicks the magic link or completes Discord OAuth. verifiedVia reports the contact's strongest proof, so it reads HMAC if the contact was already HMAC-verified. Distinct from identified: that fires on claim, this fires on proof.
message:sent{ conversationId, messageId, senderType: 'visitor' }
message:received{ conversationId, messageId, senderType: 'agent' | 'ai' | 'system' }
unread:change{ unreadCount }

Listeners can be registered at any time, including before the widget has booted; the returned unsubscribe works either way.

Available on window.Assistify:

window.Assistify.setConsent(true);   // grant
window.Assistify.setConsent(false);  // withdraw
window.Assistify.getConsent();       // 'granted' | 'denied' | 'unknown'

The visitor ID is a strictly-necessary functional cookie, persisted by default. setConsent(false) is the opt-out: it deletes the cookie and falls back to a session-only ID. setConsent(true) re-enables persistence after a prior opt-out. The widget also reads the host page's IAB TCF v2.2 signal (Purpose 1); the host CMP wins when present.

Both methods are safe to call before the runtime has booted: the loader records the decision immediately and boot honors it, so an early setConsent(false) means the persistent cookie is never written at all.

To gate all widget network activity behind consent (including the loader script), use autoload: false and call widget.load() from your CMP's grant callback. See Assistify SDK → Deferred boot.