Embed Widget
Add AI-powered knowledge search to any website with a single script tag. Streaming answers, source citations, and session management in an isolated iframe.
I wanted the embed integration to be one script tag. Not an npm package. Not a build step. Not a React wrapper with peer dependencies. One tag.
That constraint shaped everything. The Knowably embed widget delivers streaming, citation-backed RAG chat inside an iframe on any website you control. Customer support portals, documentation sites, internal tools, product pages. If it loads HTML, it can run the widget.
Most embed integrations I have seen require a developer to wire up components, handle authentication flows, manage state. I built this one so a marketing person can add it to a landing page in under a minute.
How It Works
You copy a <script> tag from the agent settings page. Paste it into your site's HTML. Done.
Behind the scenes, four things happen. The script loads a small loader file. The loader creates an isolated container using Shadow DOM and injects an iframe pointing to the Knowably embed page. A floating chat button appears in the corner. When a visitor clicks it, the chat panel opens and establishes a session.
The visitor types a question. The widget sends it through the full RAG pipeline - sanitization, hybrid search, reranking, filtering, generation - and streams the answer back with source citations. Same pipeline as the main app. No shortcuts.
Where It Fits
The embed widget turns any page into an interactive knowledge interface.
Customer support. Place an agent on your help center that searches your documentation and troubleshooting guides. Visitors get instant, sourced answers without submitting a ticket. Support teams handle fewer repetitive questions.
Documentation sites. A search bar finds pages. An embedded agent finds answers. Big difference. Users ask questions in natural language and get responses grounded in your actual docs, with citations pointing to the relevant pages.
Internal tools. Add an agent to your intranet or internal portal. HR policies, IT procedures, onboarding guides - employees find answers without knowing which document to look in.
Product pages. Pre-sales questions answered by an agent that knows your product documentation. Visitors get specifics, not marketing copy.
Each use case gets its own agent with its own knowledge scope, tone, and rules. The widget is just the delivery mechanism.
Single Script Tag
This is the entire integration:
<script
defer
src="https://embed.knowably.ai/embed/loader.js"
data-agent-token="your-agent-token"
data-workspace="your-workspace"
data-position="right"
></script>
No npm packages. No build step. No framework compatibility to worry about.
The loader auto-detects its base URL from the script source. data-agent-token identifies which AI agent powers the widget. data-workspace resolves the correct tenant. data-position controls left or right placement - right by default.
Shadow DOM encapsulation prevents CSS conflicts with the host site. Your CSS does not leak in. The widget's CSS does not leak out. This is why it works reliably on WordPress themes, Webflow sites, static HTML, React SPAs, and anything else without modification.
I chose Shadow DOM over an iframe-only approach because it gives full control over the chat button styling while keeping the actual chat content in an iframe for security isolation. Best of both worlds.
Responsive by default. On desktop, the chat panel floats as a 400x600 pixel panel. On mobile (below 480px viewport width), it goes full-screen. Users can maximize and minimize with a single click.
Agent-Powered Chat
Every embed widget is tied to a specific Knowably AI agent. The agent controls everything about the conversation: which knowledge bases to search, the system prompt, temperature, model selection, active guardrails.
This is important. You do not get a generic chatbot. You get a purpose-built assistant with specific knowledge, a specific tone, and specific rules. An HR agent on your careers page. A product support agent in your docs. A sales FAQ on your pricing page. Each one configured independently.
Streaming responses arrive as the model generates them. Users see the answer forming immediately. No spinner, no waiting for the full response to complete.
Extended thinking is supported. When the model reasons through a complex question, the reasoning displays separately from the response text. Useful when the path to the answer matters as much as the answer itself.
Source citations link every answer back to original documents. Users can verify claims and read further. This is a retrieval system that shows its work. For customer-facing widgets, that transparency builds trust.
Suggested queries give visitors a starting point. Up to four per agent. Helpful for customer-facing widgets where users may not know what to ask. Good suggested queries demonstrate what the agent can do better than any description paragraph.
The full guardrail stack runs on embed traffic. PII filtering strips personally identifiable information from responses. Prompt injection detection scores incoming messages and blocks suspicious patterns. Input sanitization handles the edge cases. Same protections as the main app, no exceptions.
I built the guardrails while working on a government RAG project. When citizens are sending queries to a public widget, you cannot afford shortcuts on safety. That mindset carried over to every embed deployment.
Security
An embeddable widget is a public-facing attack surface. I treat it that way.
Four security layers protect the widget. Each catches something the others miss. Remove any layer and you open a gap.
Origin validation controls which domains can load your agent. You configure an allowed origins list per agent - explicit domains like https://docs.example.com. If a domain is not on the list, the session is denied. Empty list means all sessions denied. Secure by default.
This is not just a one-time check. On every request, the system re-validates the session's origin against the agent's current allowed origins. Remove a domain from the list and existing sessions from that domain stop working immediately. No waiting for expiration.
Session authentication means visitors do not need user accounts. The widget creates a secure session token automatically on first visit. Every API request is authenticated against this token. The token is hashed server-side using the same pattern as Laravel Sanctum - proven and well-understood.
Returning visitors reuse their session. Chat history survives page reloads and return visits. The session token persists in the browser's localStorage.
Content Security Policy headers tell the browser which domains may frame the embed page. Even if someone bypasses the API layer, the browser itself refuses to render the widget on unauthorized domains. This is a browser-enforced security boundary - independent of application logic.
Per-agent CORS ensures each agent controls exactly which domains can make cross-origin requests to its API. No wildcards. No configuration leaking between agents.
The result: only domains you authorize can load your agent. For implementation details on how these layers work together, see the developer setup guide.
Rate Limiting
Two rate limiters protect the embed API.
Session creation is limited to 10 requests per minute per IP address. Invisible to real visitors, stops automated flooding.
Chat streaming is limited to 20 requests per minute per session. Generous for conversation, stops runaway scripts.
On top of rate limiting, plan-level limits enforce quotas on chat creation and message counts. These are business-level controls tied to the tenant's subscription, not just abuse prevention. When a customer exceeds their plan's message quota, the widget handles it gracefully.
Production Deployment
In production, the embed widget runs on a dedicated subdomain: embed.knowably.ai. This subdomain points to the same Laravel application but makes all API calls same-origin from the iframe's perspective.
Same-origin means no CORS preflight on standard requests. Faster. Simpler. The CORS layer still handles cross-origin cases when needed, but the default production path avoids it entirely.
In local development, the embed page redirects to the Vite dev server for hot module reloading. Same developer experience as the rest of the frontend.
Token Rotation and Controls
Embed tokens can be rotated from agent settings. Rotating a token immediately invalidates the old script tag. Any site using the old token stops working until updated.
That is intentional. If a token is compromised, you rotate it and the exposure ends immediately. No waiting for sessions to expire. No manual revocation.
A test page is available per agent via a secret URL. Preview the widget before deploying to production. I use this to verify behavior after configuration changes before they hit a customer-facing site.
Embed functionality can be enabled or disabled per agent. Disabling embed immediately blocks all sessions on every subsequent request. Instant kill switch when you need one.
Session Cleanup
Inactive sessions are pruned automatically. The default threshold is 30 days, configurable per your needs. The cleanup runs across all tenants in a single scheduled call - no per-tenant maintenance.
Sessions track message count and last activity. Useful for understanding usage patterns per agent without additional analytics tooling.
Related Features
- AI Agents - configure the assistant behind each widget
- Chat Interface - the full in-app chat experience
- Knowledge Bases - build the document collections your agents search
- RAG Pipeline - how retrieval and generation work under the hood
Get Started
One script tag. Session-based auth. No user accounts for your visitors.
Set up your first embed widget in the developer setup guide. Or see how it works for customer support.