Customize without creating a second source of truth

Read current widget settings and the site's existing chat.load() options. Choose the smallest supported layer that owns the requested change.

NeedPreferred layer
Shared brand, title, icons, launcher, interface, placeholderSaved Voiceflow widget settings, using CLI/MCP or Widget UI
Appearance that intentionally differs on one site/pageDocumented browser assistant overrides
Open from a site button, persistence, visitor contextBrowser widget API
Styling beyond supported settingsassistant.stylesheet and documented CSS classes
Custom cards/forms/actions inside chatWidget extensions; read the current extension guide first

The settings API uses chat, voice, common, and security; browser options use a different shape. Read merge rules before patching. Browser overrides take priority over published settings, so a stale local override can hide a successful remote update. Prefer shared settings unless the user wants a site-specific difference.

Match the site

Inspect the site's actual colors, typography, assets, and mobile layout. Choose launcher placement that does not cover navigation, a cart control, or an existing consent banner. Check text contrast and focus visibility. Reuse a public image URL or the site's asset pipeline; a local filesystem path will not load for visitors. Do not hide Voiceflow branding or disable restrictions to work around an entitlement error.

For site-specific customization, merge a fragment like this into the existing load options; it is not a complete snippet:

assistant: {
  color: '#245D58',
  side: 'right',
  spacing: { side: '24', bottom: '24' }
}

These spacing values are pixel counts encoded as strings, without px. Keep unrelated options. For exact palette, header/banner, launcher, or font fields, read the current customization reference.

Floating, popover, or embedded

Use a floating launcher for ordinary site-wide support unless the user chose a different presentation. Embedded chat needs a real, mounted target with usable height and width. Get the current render configuration from Voiceflow's snippet or docs; do not guess an iframe URL or turn a floating widget into an embedded one by shrinking its parent. An embedded target must survive or be remounted correctly during client-side navigation. Overlay open()/close() methods do not control embedded mode.

For a custom site button, initialize the widget first and then call window.voiceflow.chat.open() from that button's interaction. Do not insert a second widget or call load() on every click. Account for a user clicking before the SDK is ready; keep one initialization path and a visible failure state if loading fails. Do not auto-open the conversation on every page visit unless requested.

Persistence and visitor context

Choose session behavior deliberately. Follow the current widget API for assistant.persistence, userID, launch.event.payload, and user metadata. Browser identity is user-controlled; it is not proof of authorization to fetch private records. Keep authorization checks server-side.

Launch payload values arrive in last_event; they do not automatically assign arbitrary project variables. Capture needed values early into existing declared variables. Transcript user metadata labels the conversation and is not input to agent logic. On account switch/logout, verify the next person cannot inherit the previous person's conversation. Do not reset every anonymous conversation merely to fix a mounting bug.

CSS and extensions

Prefer the documented assistant.stylesheet hook with a reachable HTTPS CSS file and supported .vfrc- selectors. Page CSS may not reach widget internals; avoid brittle generated class names. Test CSS in the widget itself on mobile and desktop, including long responses, focus, and loading/error states.

For custom UI/actions, use extensions. Do not enable allowDangerousHTML just to install or style the widget. Voice and file uploads are optional capabilities with their own configuration and usage effects; only enable them when requested and verify those features separately.