Chatbot Widget Embedding#
Dify's embeddable chatbot widget lets you integrate a Dify chatbot application into any external website. The widget uses an iframe + bubble button model: a fixed bubble button appears on the host page; clicking it reveals an iframe that loads /chatbot/[token] from the Dify instance. You can also skip the bubble entirely and embed the iframe directly.
Key Files#
| Layer | Path |
|---|---|
| Embed script (public) | web/public/embed.js |
| Next.js page route | web/app/(shareLayout)/chatbot/[token]/page.tsx |
| React component | web/app/components/base/chat/embedded-chatbot/index.tsx |
| State hook | web/app/components/base/chat/embedded-chatbot/hooks.tsx |
| URL param helpers | web/app/components/base/chat/utils.ts |
Embedding via embed.js#
Include the script on any HTML page. The difyChatbotConfig object must be defined before the script tag, and the script must be placed after the <body> element :
<script>
window.difyChatbotConfig = {
token: 'YOUR_CHATBOT_TOKEN', // required
baseUrl: 'https://udify.app', // optional; defaults to https://udify.app
}
</script>
<script src="https://udify.app/embed.min.js" defer></script>
Config Reference#
| Key | Type | Default | Description |
|---|---|---|---|
token | string | — | Required. App token from chatbot settings. |
baseUrl | string | https://udify.app | Base URL of your Dify instance. |
routeSegment | string | chatbot | Route segment; change only for custom deployments. |
inputs | object | {} | Input variable values to pre-populate. |
systemVariables | object | {} | System variables (internally prefixed sys.*). |
userVariables | object | {} | User context variables (internally prefixed user.*). |
sendOnEnter | boolean | true | false disables Enter-to-send (useful for CJK IME). |
draggable | boolean | false | Allow the bubble button to be dragged. |
dragAxis | 'x' | 'y' | 'both' | 'both' | Constrain drag direction. |
containerProps | object | {} | DOM properties/styles applied to the button container. |
dynamicScript | boolean | false | Run immediately instead of waiting for body.onload. |
isDev | boolean | false | Uses dev.udify.app when true. |
URL Structure and Query Parameters#
The iframe loads {baseUrl}/{routeSegment}/{token}?{params} . The page component at /chatbot/[token]/page.tsx renders <EmbeddedChatbot> inside <AuthenticatedLayout>.
All variable values are gzip-compressed then base64-encoded before being appended as query params . The chatbot page decodes them via decodeBase64AndDecompress().
Query parameter namespacing:
| Prefix | Config source | Decoded by |
|---|---|---|
| (none) | config.inputs | getProcessedInputsFromUrlParams() |
sys. | config.systemVariables | getProcessedSystemVariablesFromUrlParams() |
user. | config.userVariables | getProcessedUserVariablesFromUrlParams() |
Additionally, sendOnEnter=false is passed as a plain (uncompressed) query param .
The redirect_url system parameter is special — the page will merge query strings from its decoded value into the system variable set .
URL length is validated; a console error is logged if it exceeds 2048 characters .
Cross-Origin (postMessage) Protocol#
The embed script and the iframe communicate via window.postMessage with strict origin validation :
- Iframe → Parent:
dify-chatbot-iframe-ready— signals the iframe has loaded. - Parent → Iframe:
dify-chatbot-config— sends{ isToggledByButton, isDraggable }. - Iframe → Parent:
dify-chatbot-expand-change— triggers the expand/collapse resize on the parent side.
The parent derives targetOrigin from config.baseUrl and validates all incoming messages against it .
CORS for Embedded Endpoints#
Before PR #30587, embedded bots failed cross-origin because CORS preflight requests were rejected. The fix in api/extensions/ext_blueprints.py introduces per-route CORS rules:
/chat-messagesand/chat-messages/*—supports_credentials=False, allows onlyContent-Typeand the app-code header, methodsGET / POST / OPTIONS.- All other routes — retain
supports_credentials=Truewith full authenticated headers.
This allows unauthenticated preflight for embedded chat endpoints while keeping authenticated CORS for the console and service API .
Direct iframe Embedding (No Script)#
Skip the bubble UI entirely by pointing a plain <iframe> at the chatbot URL:
<iframe
src="https://udify.app/chatbot/YOUR_TOKEN"
style="width: 100%; height: 100%; min-height: 700px"
allow="microphone;clipboard-write"
></iframe>
Variables can be appended as gzip+base64-encoded query parameters following the same namespacing rules described above.