Skip to main content
Extensions let you add custom functionality to your chat widget. You can render interactive elements like file uploads, date pickers, or payment forms directly in the chat window, or trigger effects elsewhere on your site like updating a status icon or running custom scripts.

Extension types

There are two types of extensions: Response extensions render interactive widgets inside the chat window. Use these for file uploads, calendar pickers, custom forms, or any UI element users interact with during the conversation. Effect extensions don’t render anything in the chat, but trigger actions elsewhere on your site. Use these for deep-linking users, updating page elements, or running custom scripts based on conversation events.

How extensions work

Extensions are triggered by a Function step in a workflow. You define the extension in your site’s JavaScript, then register it in your chat.load() configuration. The action name must match across your extension code and your Voiceflow steps.

Response extension structure

Effect extension structure

Registering extensions

Register your extensions in the assistant.extensions array when loading the widget:
There’s no limit to the number of extensions you can register.

Example: building a form extension

Build a chat widget extension that renders a pre-filled form, triggered by a Voiceflow function. The function sends user data (name, email) via a custom trace, the extension renders the form and collects missing fields, and submits the completed data back to the function which routes based on the response.

Architecture

Form Trace Architecture

Step 1: The Voiceflow Function

Create a function in Voiceflow that accepts name and email as input variables, emits a custom trace to trigger the extension, and listens for the form submission.

Function Configuration

Function Code

What this does:
  1. Reads name and email from the function’s input variables (collected earlier in the flow).
  2. Emits a trace with type: 'user_form' — this is the custom trace type the chat widget extension will match against.
  3. Sets listen: true so the agent pauses and waits for the user to interact.
  4. Routes to the submitted path when it receives an event with type: 'form_submitted'.

Step 2: The chat widget extension

Register a response extension that matches the user_form trace, renders a form pre-filled with the payload data, and sends the completed form back via interact().

Extension Code

Register the Extension

Add it to your chat.load() call:

Step 3: Capture the Data in the Agent Flow

When the user submits the form, interact() sends an event with type: 'form_submitted' and a payload containing { name, email, phone, company }. The function’s listen picks this up and routes to the submitted path. To access the submitted data downstream, use a Code step (or a second function) connected to the submitted path:
Alternatively, if using the function’s output variables, create a second function on the submitted path that reads last_event and maps values to output variables:

Step 4: Wire the Agent Flow

The overall canvas layout:
  1. Before the function, collect name and email.
  2. Wire those variables into the function’s input variables.
  3. Connect the submitted output path to a Code step or a Function that reads last_event.payload.
  4. Use the extracted variables in subsequent steps or back in your agent.

Complete Working Example

Two files: form.js with the extension, and index.html that loads it.

form.js

index.html


How the Data Flows


Key Concepts

Why listen: true?

Setting listen: true in the function’s next command pauses the agent at the function step. Without it, the agent would immediately continue down the defaultTo path before the user has a chance to fill out the form.

Event Matching

The to array uses MongoDB-style queries (via sift.js) to match incoming events. { 'event.type': 'form_submitted' } matches any interact() call where type equals 'form_submitted'. You can also match on payload properties:

Accessing Submitted Data

After the listen resolves, the event that triggered it is available as last_event in downstream Code steps:

Extension Cleanup

The render function can return a cleanup function that runs when the message is removed from the chat (e.g., on session reset):

More examples

For additional extension examples including video embeds, maps, input field controls, and confetti animations, visit the sample extensions repository

Example: building a form extension

This example walks through creating a form that collects name, email, and phone number from users.

Step 1: Create the extension

Add this script above your chat widget snippet, before the closing </body> tag:

Step 2: Register the extension

Update your chat.load() configuration to include the extension:

Step 3: Trigger the extension from your workflow

Add a Custom action step to your workflow with the name Custom_Form. Create a path called complete and enable Stop on action so the agent waits for the form submission before continuing. When triggered, your widget receives a trace that activates the extension:

Step 4: Retrieve the submitted values

After the form is submitted, the values are stored in the last_event system variable. Access them in a JavaScript step:

More examples

For additional extension examples including video embeds, maps, input field controls, and confetti animations, visit the sample extensions repository.