Where the widget runs
Your public website
Your authenticated web app
iOS and Android
Your help center
A standalone support route
/support.Before you create your widget
You’ll need:- At least one bot already created in Fini and trained on your knowledge. Each widget is tied to one bot; the bot can’t be changed after creation. Create the bot first from the home page.
- The domain(s) where the widget will live (for example,
https://yourcompany.com,app.yourcompany.com, or wildcards like*.yourcompany.com). Each widget can serve multiple domains. - (Optional) A connected helpdesk integration if you want widget conversations to escalate to a human ticket. Today the supported destinations are Zendesk, Front, and Salesforce. Connect the destination integration first under Deploy.
Create your widget
Open Deploy → Widget in Fini. If no widget exists yet, the creation form opens directly; if one or more widgets already exist, pick Create new from the top-right.
Pick the bot
Fill in the basics
- Domain: the URL(s) where the widget will be embedded. Multi-domain widgets are supported, enter one domain per line. Wildcards work (e.g.,
*.yourcompany.comto cover every subdomain). - Widget title: the name shown in the widget header.
Click Create
Embed it on your site
The Embed Script tab gives you a JavaScript snippet to paste into your site’s HTML.
Click Copy
Paste it into your site
</body> tag of every page where you want the widget. Most teams put it in a global layout template or footer partial so it shows up site-wide.Preview before going live
localhost without a domain match, you can test locally before configuring the production domain. For production, the live domain you embed on must match one of the entries in the widget’s Domain field.Widget modes
Themode option in the embed snippet controls how the widget renders:
mode: "widget"
mode: "standalone"
mode, the widget uses the floating bubble behavior.
Opening, closing, and starting again
Inwidget mode, Fini renders a floating button in the bottom-right corner of the page.
- When the widget is closed, the button shows your brand logo.
- When the widget is open, the button switches to a close icon.
- Clicking the button toggles the panel open or closed.
- The open and close transition scales the panel in and out from the button.
standalone mode, there is no floating launcher. The chat panel renders inline where the snippet is mounted, so the host page controls where the panel appears.
SDK controls
The widget exposes a small customer-side SDK throughwindow.fini. The embed snippet creates a queue so you can call SDK commands before the widget bundle has fully loaded.
Use SDK commands when your product UI needs to control the widget directly:
message as the customer’s next question. Use this when a button, search result, or in-product prompt should start a conversation automatically.Answer rendering
Widget answers render Markdown. The same answer renderer is used in the floating widget, standalone widget, and main embedded widget surfaces. The widget supports common Markdown patterns including paragraphs, links, bulleted and numbered lists, inline code, fenced code blocks, and GitHub-flavored Markdown tables. This lets the agent return structured troubleshooting steps, comparison tables, and code snippets without losing formatting in the chat UI.Loading and notification states
While the agent is responding, the widget shows a loading state:- The send button switches from the send icon to a spinner.
- The assistant message area shows a pulsing skeleton loader.
- The bot logo pulses while the answer is being generated.
- The input is guarded so customers cannot submit another message while a response is in progress.
- Browser notifications show a native browser notification when supported and allowed by the customer.
- Sound notifications play an audio cue for new widget activity when enabled.
- Pulse notifications visually pulse the launcher so the customer can see that a new message is waiting.
Customer implementation checklist
Customers do not need to build their own loading UI. Loading states are handled by the widget bundle after the embed script is installed:- Paste the widget snippet on the page.
- Pass the correct
widgetId. - Set
modetowidgetorstandalone. - Configure notification behavior in
finiWidgetOptions.notifications.
- Serve the page over HTTPS. Browser notifications generally require a secure origin.
- Set
notifications.browserto"ask"or"always". - Let the widget request notification permission when the customer interacts with it.
- If the customer blocks browser notifications, ask them to re-enable notifications from their browser’s site settings.
- Set
notifications.soundtotrue. - Make sure the widget is loaded on pages where sound is acceptable for your customer experience.
- Remember that browsers may block sound until the customer has interacted with the page.
- Set
notifications.pulsetotrue. - Use
mode: "widget"if you want the floating launcher to pulse for new activity. - Use
mode: "standalone"when the chat is always visible; in that mode, the page itself controls where the panel appears.
storage.googleapis.com and any browser APIs required by your notification policy. Overly strict script, media, or notification policies can prevent sound or browser notifications from working.Page URL tracking
Fini can record the URL of the page where each widget message is sent. This helps your team understand where a customer was when they asked a question, and gives the agent more page context when reviewing the conversation. Customers do not pass the page URL manually in the embed snippet. Turn it on from Widget Settings → Advanced → Track current page URL. When enabled, the widget captures the current browser URL automatically for messages sent from that page. Use this when the same widget appears across product pages, account pages, help center articles, or checkout flows and you want analytics or conversation review to include the page source.Identify logged-in users
When you’re embedding the widget inside an authenticated experience (your web app, your mobile app, your customer portal), you can tell the bot who the user is by passing a signed JWT as thecustomerToken. The bot then has access to the user’s email, name, and any custom attributes you include, so it can answer questions like “what plan am I on?” without asking the user to repeat themselves.
Payload shape
Sign a JWT on your server with this payload structure:false when you already have a verified email from your auth system; set true when you want a confirmation step regardless."web" for browser-based widgets (your public site or authenticated web app) and "mobile" for your native iOS and Android apps. Fini uses this to distinguish where a conversation originated, so you can segment analytics and tailor agent behavior by surface. Optional, omit it if you don’t need to differentiate surfaces.Signing the token
Sign with the HS256 algorithm using your widget’s Signing Key, find it in the Settings tab under the Signing Key section. Node.js example:customerToken in finiWidgetOptions, the same place where widgetId and mode live.
Configure your widget
All configuration lives on the Settings tab.
Connection details
Read-only metadata about the widget, set at creation time:General setup
*.yourcompany.com are supported.Branding

#1D84FF).Thinking messages
Thinking messages are the short phrases shown while the bot is preparing a reply. Configure them from Widget Settings → Branding → Thinking messages.Pulling up the information...Double checking the details...Putting it all together...
Welcome text
The welcome text appears before the customer starts a conversation. In the floating widget, it appears under the header and brand logo. In standalone mode, it appears at the top of the empty chat panel. Use one short sentence that tells customers what to ask. For example:Ask us about orders, returns, account settings, or billing.
Predefined questions
Surface suggested prompts on the widget’s greeting screen so visitors know what they can ask. Predefined questions appear as tappable chips before the conversation starts. When a customer clicks one, the widget submits that question immediately. Choose 3-5 high-leverage questions that cover your top tickets, for example:How do I reset my password?Where is my order?Cancel my subscription
Reference links
When reference links are enabled, the widget can show a collapsible Learn more via… section under an assistant answer. The widget deduplicates links before showing them:- Public source links can appear as clickable reference chips.
- Private Google Cloud Storage references are counted as private links but are not exposed as clickable customer links.
- If no public links are available, the widget can still tell the customer that private references were used.
Notifications
Notification settings are controlled from the customer-sidenotifications object in finiWidgetOptions.
true to play a sound when there is new widget activity. Set to false to keep the widget silent."never" to disable browser notifications, "ask" to request permission when needed, or "always" to show notifications whenever browser permission is already available.true to pulse the floating widget launcher when the widget is closed and there is new activity. This is most useful with mode: "widget".Advanced
Advanced settings control conversation metadata and visitor identity behavior.Signing Key
The secret used to sign JWTs for authenticated widget conversations. See Identify logged-in users for the JWT flow. The key is read-only in the UI, you can copy it but not regenerate or edit it from this page. Contact your Fini contact if you need a rotation.Track current page URL
Off by default. When enabled, Fini records the URL of the page each message is sent from, useful for analytics and bot context when reviewing conversations. Turn it on when the widget appears across multiple pages and you want each message to carry its source page URL automatically.Collect visitor email
Off by default. When enabled, the widget asks visitors for their email before starting a chat. Leave it off when your authenticated app already passes a verified email through the widget token.Escalate to your helpdesk
When the agent in the widget can’t resolve a conversation, the conversation can hand off to a human agent as a real ticket in your existing helpdesk. Widget escalation is configured through Business Rules, not from the widget settings panel. Today, five integrations work as widget escalation destinations:Zendesk
Front
Gorgias
Salesforce
HubSpot
Connect the destination helpdesk first
Open Rulebook → Business Rules
Create a default or custom Business Rule
Map the integration fields
Test and save the Business Rule
Destination-specific notes
Zendesk, Front, Gorgias, Salesforce, and HubSpot each need a connected integration before Business Rules can hand off to them.- Zendesk: connect Zendesk first on the Zendesk deploy page. For Chat escalations, customer-uploaded files from the widget are forwarded into the Zendesk conversation as native attachments when Zendesk accepts the file. The transcript still includes download links as a fallback.
- Front: connect Front first on the Front deploy page. Front escalations use email channels.
- Gorgias: connect Gorgias first on the Gorgias deploy page. Fini creates a Gorgias ticket from the widget escalation and suppresses the integration webhook for that ticket, so Fini does not treat its own escalation as a new Gorgias conversation to answer.
- Salesforce: connect Salesforce first on the Salesforce deploy page. Fini creates a Salesforce Case with the connected integration credentials; case ownership and queueing follow your Salesforce assignment rules.
- HubSpot: connect HubSpot first on the HubSpot deploy page. Fini can create a HubSpot ticket directly or submit a published HubSpot support form, depending on the Business Rule template. Direct ticket creation uses the first active open ticket stage unless your rule maps a specific pipeline stage.
Verify it’s working
Preview the widget
Ask a question the bot should answer
(If escalation is configured) Test the escalation path
Common questions
How does the widget know who a logged-in user is?
How does the widget know who a logged-in user is?
customerToken in finiWidgetOptions. The payload carries email, name, collectEmail, platform, and any user_attributes you want the agent to use. Never sign tokens in browser code. See Identify logged-in users.Where can widget conversations escalate?
Where can widget conversations escalate?
Can I match the widget to my brand?
Can I match the widget to my brand?
Does the widget work in mobile apps?
Does the widget work in mobile apps?
platform: "mobile" in the JWT so analytics and agent behavior can distinguish mobile conversations from web.Can one widget run on several domains?
Can one widget run on several domains?
*.yourcompany.com cover every subdomain. localhost works for testing without a domain match.What languages does the widget answer in?
What languages does the widget answer in?
Can my product open the widget or start a conversation?
Can my product open the widget or start a conversation?
window.fini: fini("open"), fini("close"), and fini("sendMessage", message), and subscribe to open, close, and sendMessage events for analytics. See SDK controls.Do customers see the sources behind an answer?
Do customers see the sources behind an answer?
Troubleshooting
The widget doesn't appear on my site
The widget doesn't appear on my site
- The script snippet is pasted inside or after the closing
</body>tag. - Your live domain matches one of the entries in the widget’s Domain field (including any wildcards). Trailing slashes and protocols matter,
https://app.acme.comandapp.acme.comare different entries. - There’s no Content Security Policy on your site blocking external scripts. The widget script is served from
storage.googleapis.com/fini-widget/assets/fini-widget-prod.min.js. - Open the browser console: any errors mentioning “widget”, “fini”, or CORS usually point at the cause.
The widget shows but the bot doesn't know who the user is
The widget shows but the bot doesn't know who the user is
customerToken is either missing, malformed, or signed with the wrong key. Confirm:- The token is being signed server-side with the correct Signing Key from this widget’s settings.
- The algorithm is HS256.
- The token is being passed to
finiWidgetOptions.customerTokenas a string (not the parsed JSON payload). - Inspect the token at
jwt.io(against the signing key) to confirm the payload shape matches what’s documented above.
The widget shows but escalation doesn't work
The widget shows but escalation doesn't work
- The destination integration is connected and authorized on its own deploy page.
- A published Business Rule is assigned to this bot with source Widget and trigger On Escalation.
- The Business Rule template fields or Tool inputs are mapped to the right destination fields.
- The rule passes Test Rule with representative widget escalation context.
- For Salesforce: widget escalation does not require the manual Salesforce setup. If escalation is failing, verify the Salesforce credentials on the Salesforce deploy page are still valid (tokens expire and may need to be refreshed).

