Multi-Tenant AI Chatbot Widget
A secure, embeddable AI chatbot for multi-tenant websites with strict domain validation and Shadow DOM isolation.
A reusable chatbot widget designed for external client websites, built around single-script deployment, tenant isolation, and a lightweight integration flow.
384 KB
Bundle size
< 1s
Initial load target
8s
Config fetch timeout
30s
Chat request timeout
Single script tag
Integration model
This project addresses a common product problem: businesses want to add an AI assistant to external websites without exposing internal prompts, configuration, or tenant data. The widget needed to be easy to embed, safe to operate across different merchant domains, and lightweight enough to feel like a native part of the host site. The result is a multi-tenant chatbot widget that can be dropped into a client site with a single script tag. It is designed around secure deployment, isolation between tenants, and a clear separation between public UI configuration and server-side business logic.
"Build a reusable AI chatbot component that can be embedded on third-party websites while preserving tenant isolation, validating allowed domains, preventing style leakage, and keeping sensitive backend logic and data out of the browser."
Architecture
- 1Single script-tag embed flow that loads the widget with a tenant-specific storeId
- 2Shadow DOM rendering to isolate styles from the host page
- 3Hono backend API for configuration and chat requests
- 4Supabase-backed data layer for tenant records and operational data
- 5Upstash Redis for caching, session handling, and rate limiting
- 6Strict origin and domain validation before allowing chat interactions
Key features
Merchants integrate the widget through a single script tag that passes a store identifier. On load, the widget fetches only the safe UI configuration it needs, which keeps the integration simple while preserving the server-side boundary for sensitive data.
The system is built to prevent cross-tenant leakage by validating the request origin against an allowlist of domains and by keeping system prompts and sensitive business rules on the backend. The widget also renders inside a Shadow DOM to minimize CSS collisions with the host site.
The backend is implemented with Hono and uses Supabase for persistent tenant data. Upstash Redis supports fast caching and operational controls such as session state and rate limiting, which helps keep the service responsive under normal widget traffic.
The architecture separates the frontend widget and backend API so they can be deployed independently. The widget is served from Cloudflare Pages, while the API runs on Railway, giving the project a straightforward production path with clear ownership of public assets versus server logic.
Technical challenges
Keeping the widget easy to embed without exposing sensitive tenant data — the solution was to move prompts, authorization checks, and server-side rules into the backend so the browser only receives safe configuration data.
Preventing cross-tenant access from unauthorized domains — the solution was to validate the request origin against each tenant’s allowed domain list before accepting chat traffic.
Avoiding CSS conflicts on arbitrary client websites — the solution was to render the widget in a Shadow DOM so its styles stay isolated from the host page.
Keeping the widget resilient under real-world network conditions — the solution was to add request timeouts, retry logic for config loading, runtime schema validation, and user-facing error handling.
What I learned
- Client-embedded products need security boundaries that are clear both in code and in deployment.
- A narrow public API and server-side validation make multi-tenant systems easier to reason about.
- Shadow DOM is an effective tool for preserving UI consistency on untrusted host pages.
Interested in working together?
I am open to an end-of-year internship opportunity starting February 2027.