Embedding Dify web apps in websites and portals: when teams need it
Embed a Dify app when a team wants an existing assistant or workflow visible inside a customer, employee or partner portal, and the people using it should interact with the app's own chat or form interface rather than building one. Dify publishes an app as a web app with its own URL and interface, and that published app is what gets placed inside another site, through a chat bubble, an iframe or a custom front end that calls the same public web app endpoints. Embedding is a front-end decision: the portal page hosts the Dify interface, and the browser talks to Dify directly.
That model is separate from calling the Dify API from a backend. A backend integration uses a service API key held on your server, so your code decides who the caller is, what inputs are sent and what the response looks like to the user. An embedded web app has no such server in the middle. Users of the web app are web app users, and the portal page passes context into the app as inputs or as a user field, but Dify does not verify that the portal user is who the page says they are. Before choosing embedding over an API integration, confirm which identity the app will trust, whether the portal already has a sign-in that should carry through, and whether the app's access settings can be limited to the audience that should see it.
Embedding options and when each fits
This table compares the chat bubble script, iframe embedding and a custom front end built on the web app across effort, branding, user context and the host page's CSP and SSO requirements. Read each row as a question to answer before choosing a method. In short, the bubble is the quickest to add, while custom embedding gives the most control and carries the most build work. Confirm exact snippets and header behavior in the Dify docs for your version before you commit.
| Aspect | Chat bubble script | Iframe | Custom embedding on the web app |
|---|---|---|---|
| Effort | Low. Add a script to the host page and set the published app details. | Low to moderate. Add a frame with the app's published address and size it to the layout. | Highest. Your team builds the chat interface and calls the app's API from your front end. |
| Branding control | Limited to the options Dify exposes for the bubble. Confirm which settings your version supports. | Mostly the app's own web interface. The host controls frame size and placement only. | Full control over layout, styling and copy, within the limits of the app's API responses. |
| User context handling | Passes only what the script and app settings allow. Confirm how inputs and user identifiers are sent. | Context passes through the URL or app settings. Anything sensitive in a URL can be logged, so review it first. | Your backend sets the end-user identifier and inputs per request. Dify does not authenticate that user field. |
| CSP impact | Script and frame sources must allow the Dify host. Confirm the exact directives in the docs. | The frame source must allow the Dify web app origin, and Dify's own headers can block framing. Test both. | Only your own origins and the Dify API endpoint need allowances. Calls go from your front end or backend. |
| SSO impact | Visitors sign in to the app separately unless your identity setup extends to web app access. Confirm this. | A separate sign-in inside the frame is likely. Session cookies may not carry over between sites. Test in each browser you support. | Your site handles sign-in and passes identity to your backend. Dify web app access levels then depend on how you configure them. |
Setting up an embedded Dify web app step by step
This sequence takes a published Dify web app from access settings on your self-hosted instance to a tested embed on each target page, with a check at every stage so problems surface before users see them.
Publish the app and confirm its access level
The app owner publishes the app in the Dify console and confirms who can open the web app. Decide whether the embed serves anonymous visitors, people who sign in to Dify, or users identified through SSO, because that choice sets every later step. Confirm the access setting on the app's publish screen and open the public URL in a private browser window to see what an outside visitor gets. Done means the published URL loads as the audience you intended and nothing more. Check the app management documentation for the options your edition offers.
Set the allowed embedding origins
A platform or security engineer updates the self-hosted instance's configuration so that only the sites you name can frame or script the app. Record every production and staging origin, including scheme, host and port, and confirm which settings your version exposes for framing and cross-origin behavior in the environment variable reference. Restart the services with the new values, then request the app from a page on an approved origin. Done means the change is in a reviewed configuration file, not only in a running container, and the approved origin loads the app.
Configure the content security policy on the host page
The team that owns the portal or website adds the Dify instance to its frame-source and script-source directives, keeping the list as narrow as the chosen embed method allows. Work from the browser's reported violations rather than guessing, and copy the exact origin of the Dify instance. If the portal sets policy at a proxy or CDN, change it in the same change window as the page. Done means the host page loads with no policy violations logged in the browser console for the Dify origin.
Choose and add the embed method
The web team selects a chat bubble, an iframe or a custom integration based on how much control the page needs over layout, sizing and events. Copy the embed snippet from the app's publish or embed screen, replace placeholder values with the approved instance address, and place it on a staging page only. Keep the snippet in version control with the page template so it is reviewed like other code. Done means the staging page shows the app in the intended position and size on desktop and mobile widths.
Pass inputs and user context deliberately
Decide which values the host page may send to the app, such as a product name or a language code, and how they map to the app's declared inputs. Treat any user identifier as a label for conversation handling, not as proof of identity, because Dify does not authenticate that field on its own. Do not pass secrets, session tokens or personal data unless a documented need and a privacy review cover it. Test with two sample values and confirm each appears where the app expects it. Done means the inputs arrive as designed and a tester who changes the logged-in account on the host page gets the behavior the design specifies.
Test on staging in each target browser and page
QA runs the embed on every page and browser on the support matrix your organization defined, including the portal's login-protected pages if any. On each page, open the browser developer tools, reload, and confirm there are no blocked frames, scripts or fonts, and no policy errors. Also check the Dify console for errors tied to the requests from that page. Test a full conversation, a refresh mid-session and a sign-out. Done means every combination passes with a written record of the browser versions and pages tested.
Promote to production and watch the first sessions
The release owner applies the approved origin list and host page change to production in one controlled change, keeping the previous configuration available for rollback. Load the app from each production origin and repeat the console check. Watch the Dify logs and the host page's error reporting for the first sessions after launch. Done means production loads cleanly, the change record names who approved each origin, and the rollback steps have been written down and confirmed to work on staging.
Passing user context and inputs without trusting the browser
Values that arrive from the browser are input, not identity. When a portal embeds a published Dify web app, the page can pass a user label, a department, an account number or any other field that a form or script sets. Everything the visitor's browser sends can be edited by that visitor, including values the portal's own JavaScript writes into the embed. The portal should therefore treat these values as hints for the conversation, never as proof of who is asking. Before go-live, list every value the embed will send, mark each one as either a display label or a decision input, and remove any field that would grant access, change a record or select another customer's data if someone edited it.
Web app users and API users are different identities. A Dify web app assigns its own end-user session to each visitor, and that session is separate from the end-user field a backend sends when it calls the Dify API with a service API key. The API does not authenticate that field, so a value such as user in an API call is only a label Dify uses to group conversations and files. Confirm with your Dify version which identity mechanisms your web app access settings support, since Enterprise SSO for web app access is documented separately from Community login options. Do not assume that a signed-in portal user is the same person as the Dify end user inside the embedded chat.
Identity decisions belong in the portal's session and backend. The portal should authenticate the visitor in its own session, then decide what that visitor may ask and which records the conversation may reference. Where the portal needs Dify to know about a specific customer, have the backend call the Dify API with values it derived from the verified session, not values copied from the page. Keep the embed's inputs limited to content the user is allowed to supply, and validate them on the server before any workflow uses them. Ask your integration partner or internal team to document this boundary in the design, so reviewers can see which party is trusted for each decision.
Where SSO and CSP break embedded apps
Embedding a Dify web app inside another site moves it into a different browser context, and that context changes how cookies, redirects and security headers behave. The issues below tend to surface together during testing, so check them in one pass on the exact Dify and portal versions you run.
Third-party cookies blocked in frames
When the portal and the Dify app sit on different domains, browsers may treat the Dify session cookie as third-party inside the iframe. Sign-in can appear to succeed and then drop on the next request. Test the embedded flow in each target browser with third-party cookie controls at their defaults. Confirm whether your Dify version and login method need a cookie setting change or a same-site hostname arrangement.
Login redirects that cannot finish in frames
Identity provider sign-in pages often refuse to load inside an iframe, and some redirect back to a URL that the frame cannot complete. Enterprise SSO supports separate scopes for workspace access and web app access, so the app-level flow can be configured apart from console sign-in. Confirm which SSO scope your embedded app uses and whether the identity provider allows framing. Community login options are narrower, so verify them against your version before committing to a design.
Frame-ancestors on the Dify side
The Content Security Policy frame-ancestors directive decides which sites may place a page in a frame. If Dify's responses or the Nginx layer in front of it do not allow your portal origin, the browser blocks the embed with no obvious error in the app. Set frame-ancestors to the exact portal origins you approve and nothing broader. Check the header on the web app URL, not only on the console.
Script-src and connect-src on the portal
The portal's own policy must allow the scripts, styles and API calls that the embed loads, including the chat bubble script if you use that method. A strict script-src on the portal blocks the bubble silently, and a tight connect-src blocks streaming calls back to Dify. List the Dify origin in each directive your embed method needs and test with the portal's policy in report-only mode first. Review the portal's policy whenever the Dify host or embed version changes.
Mixed content and insecure origins
A portal served over HTTPS that loads a Dify app over plain HTTP will have the frame or script blocked by the browser. The problem often appears only in one environment, such as a staging host left on HTTP behind a load balancer. Confirm that every Dify URL in the embed snippet uses HTTPS and that the Nginx or ingress layer forwards the original scheme correctly. Check redirects as well, since an HTTP redirect can reintroduce the problem.
Session cookie scope and SECRET_KEY
Session cookies set for one hostname do not travel to another, so a user signed in to the console or to a different app may appear signed out inside the embed. Dify uses SECRET_KEY to sign session cookies and JWTs, and changing it after deployment logs out all users. Decide the cookie domain and path with your portal team, keep SECRET_KEY stable across instances, and test a sign-out in one context against the other. Confirm current cookie attributes against the environment variable reference for your release.
Questions teams ask before embedding Dify apps
What drives the cost and effort of embedding a Dify app?
The main drivers are how many apps and portals are involved, how much user context must pass from the host site into Dify, and how many identity and security decisions the embed forces. A single chat bubble on one public site is a small job. Embedding several apps in an authenticated portal, with inputs prefilled from the signed-in user and a tightened Content Security Policy, adds design, testing and review work on both sides. Costs split into the implementation effort (planning, configuration, host page changes, testing) and the recurring work of keeping the embed working through Dify upgrades and portal releases. Ask any partner for a quote that lists these items separately, and for which items are one-time and which recur. Community and Enterprise licensing are separate decisions: the Dify pricing page lists the self-hosted Community edition as free and limited to a single workspace, and the self-hosted Enterprise edition as custom priced, adding SSO and multiple workspaces.
How long does a typical pilot embed take?
No duration figure is supplied for this work, so treat any number you hear as a claim to verify. The time is set by a few factors: whether the Dify app is already published and stable, whether the portal team has a staging environment that matches production, whether the identity team has settled how signed-in users will reach the app, and how many browsers, portal templates and content security rules must be tested. A pilot with one app, anonymous visitors and a standard iframe moves quickly. A pilot that needs signed-in users, prefilled inputs and approval from security review takes longer because each dependency waits on another team. Ask for a written plan with named milestones and the dependencies that could stall them.
What must the portal team and identity team provide?
The portal team must supply the pages that will host the embed, the template or CMS details that control headers and scripts, a staging copy of the site, and an owner who can approve changes to the Content Security Policy. The identity team must confirm how users sign in to the portal, which identity provider issues their tokens, and whether those users should reach Dify as anonymous visitors, as members of a workspace, or as external users. Dify Enterprise documents separate SSO scopes for workspace access and web app access, so a decision on which scope applies is needed before build starts. Dify's own secrets and key settings, such as SECRET_KEY, are operated by the platform team, so that owner should be included early.
Can an internal team embed Dify apps without a partner?
Yes, if the team has someone who knows the Dify deployment, the portal platform and browser security well enough to change headers and host scripts safely. The Dify docs cover publishing and embedding, so a capable internal team can build a basic embed alone. The gaps usually appear in three places: testing across browsers and portal templates, reviewing how the Content Security Policy and cookie behavior affect the embed, and confirming that identity and user context are passed without exposing data. A partner is most useful when those areas are unclear or when the embed must be ready for an audit. Whichever route you take, ask for the scope in writing and check it covers testing and handover, not only configuration.
What breaks when a Dify embed meets a Content Security Policy?
Browsers block frames, scripts and connections that the page's Content Security Policy does not allow, so an embed that worked in staging can fail silently in production. The usual fixes involve allowing the Dify web app origin in frame and connection directives, and checking that the portal does not forbid framing by its own response headers. Each change widens what the page may load, so each one needs a security review. Cookie settings also matter: when the Dify app and the portal sit on different sites, browsers may refuse third-party cookies that the session depends on. Test in every browser your users run, and keep a record of every directive you changed.
What changes when the Dify version is upgraded?
Each Dify upgrade can change the embed, so it should be part of the upgrade plan rather than an afterthought. Dify ships minor releases roughly monthly, based on the release dates in the GitHub releases page, and the Docker Compose docs advise a backup before every upgrade and a check of .env.example for new variables. Re-test the embed after each upgrade, because web app behavior, script locations, sandboxing and authentication between services can change. Keep the portal's Content Security Policy and embed snippet under version control so a regression can be traced and reverted. Confirm the upgrade path and any breaking changes against the release notes for the target version before scheduling it.
Should we use a chat bubble, an iframe or a custom embed?
Choose by how much control the portal needs over layout, user context and the look of the app. A chat bubble is the fastest to add and gives the least control over placement and data passed in. An iframe keeps the app isolated from the host page and is easier to reason about for security, but it limits styling and makes cross-frame communication harder. A custom embed built on the published app's endpoints gives the most control over inputs and identity, and adds the most code to maintain and test. Write down the user context you need to pass, then pick the lowest-effort option that carries it safely. Confirm the options your Dify version supports in the Dify docs for web apps before you decide.
Does embedding change the Dify license or edition needed?
Embedding a published app on your own site does not by itself change the license terms, but the Dify Open Source License restricts operating the source code as a multi-tenant environment without written authorization and restricts removing logo or copyright information from the console. Those terms should be read in full with your legal team before you expose apps to outside users. Licensing decisions also affect what identity features you can use: the Dify pricing page lists SSO and multiple workspaces under the self-hosted Enterprise edition, not the Community edition. Confirm these points with Dify and your counsel before the embed goes live.
Choosing between an embed and a backend API call
Choose an embedded web app when the assistant is a public-facing experience that Dify should own end to end, and choose a backend call to the service API when the portal itself must own the experience, the identity and the logs. An embed means the visitor interacts with Dify's own interface inside a frame or bubble, so the look, the conversation handling and most of the audit trail stay with Dify. A backend call means your server sends requests with a service API key, receives the answer and renders it in your own components. The key question is who must be accountable for what the user sees and what gets recorded, because that answer determines which path you can defend to your security and compliance reviewers.
Use an embed when the audience is broad, anonymous or external, the assistant needs little customization beyond the published app settings, and a separate sign-in layer is acceptable. Web apps have their own access model, so confirm whether the app is public, requires sign-in, or is restricted to specific users in your edition before you promise that boundary to a business owner. Use a backend call when the portal already knows who the user is, when answers must be merged with your own data before display, or when you need to block or rewrite requests before they reach Dify. In that case the service API key must stay on your server, because any key shipped to a browser can be copied and used outside your portal.
The trade-off also shows up in logging. With an embed, conversations are recorded under the web app's own user context, which is convenient but may not map to your customer identifiers. With a backend call, you decide what the user field carries and you can correlate Dify records with your own session IDs, but you now own the proxy, rate limits and error handling. Before you commit, write down three things: who owns the interface, which identity Dify will record, and who answers when a request fails. Confirm the exact access settings for your Dify edition and version with your own test instance, since the options differ between Community and Enterprise.
How DeployOpen scopes and supports Dify embeds
DeployOpen plans, implements, integrates, hardens, documents and supports self-hosted open-source platforms inside your own infrastructure. For Dify web app embeds, we start from the sites that will host the app, the identity model and the browser policies those sites already enforce, then build and hand over the embed in your environment.
How we scope
- Inventory every host page, portal and domain that will embed a published Dify app, with its framework and authentication model.
- Record which user context, inputs and conversation behavior each embed needs, and which must stay out of the browser.
- Agree the written scope, deliverables and timeline in advance, since most engagements are fixed-scope.
How we build
- Configure the Dify web app access settings, embed method and allowed origins in your own Dify instance and sign-in setup.
- Set and test the Content Security Policy and frame-ancestors rules on each host site against the Dify domain.
- Test sign-in, session expiry and identity handoff across the chosen browsers and each host site before release.
How we hand over
- Provide written documentation of the embed method, configuration keys, allowed domains and the reasons behind each browser policy.
- Walk your engineers through the change process for adding a host site, rotating a secret or updating the Dify version.
- Deliver a checklist to confirm embed behavior after each Dify upgrade, since minor releases arrive roughly monthly.
How we support
- Offer ongoing support, upgrades and testing as a retainer if you want DeployOpen to keep embeds working across Dify releases.
- Re-test embeds when a host site changes its framework, login provider or security headers.
- Confirm with your team which support hours, response expectations and escalation contacts a retainer would include before signing.

