How Spelo works
Spelo is a hosted SaaS with four surfaces:
| Surface | Role | Runtime |
|---|---|---|
| Widget | The orb that runs on your website | User’s browser |
| API | Auth, site config, token minting, query proxy | api.spelo.ai (Hono/Node) |
| Dashboard | Where you configure your site | app.spelo.ai (Next.js) |
| Docs | This site | docs.spelo.ai (Starlight) |
The data flow of a single voice query
Your website │ <script src="spelo.ai/spelo.js" data-site-id="abc123" async></script> │┌───────────────┼──────────────────┐│ │ │▼ ▼ ▼CDN Edge User's Browser Spelo API(spelo.js) (widget) (api.spelo.ai) │ │ │ GET /v1/abc123/config │ ────────────────►│ │ │ ←── Supabase (site_configs) │ ◄────────────────│ │ │ │ POST /v1/abc123/token │ ────────────────►│ │ │ ←── decrypt OpenAI key │ │ + OpenAI /realtime │ ◄────────────────│ │ │ │ WebRTC direct to OpenAI Realtime │ ◄──────────────────────────────────► │ │ │ POST /v1/abc123/query │ (search_database function call) │ ────────────────►│ │ │ ←── Your DB (via adapter) │ ◄────────────────│Three key properties fall out of this shape:
- Audio never touches our servers. Browser and OpenAI speak WebRTC directly. We only hand out short-lived session tokens.
- Your database credentials never reach the browser. The widget asks our API, our API asks your database (with your read-only user), and the results come back through us.
- Every call is scoped to your
site_id. Origin is verified server-side against the domains you registered. A stolen snippet does not work from another domain.
What the AI can do
The widget registers a small set of function tools with OpenAI. When the model decides to call one, it arrives over the WebRTC data channel and the widget executes it locally (or proxies to our API).
| Tool | What it does | Runs in |
|---|---|---|
navigate | Changes the URL via history.pushState or location.assign | Browser |
scroll_to | Smooth-scrolls to a DOM element or section id | Browser |
click_element | Clicks a button, link, or accordion the user asked about | Browser |
fill_field | Fills a form input the user dictated | Browser |
| Image analysis | Disabled for now; the agent says it cannot see or analyze images | N/A |
search_database | Queries your data through an adapter | API proxy |
The widget announces which tools are available at session start, pulled from your site’s site-intelligence payload.
Multi-tenancy
Every resource is scoped by site_id. When a request comes in:
- The API looks up the site config (cached 60s)
- It validates the request
Originmatches a registered domain - It decrypts your OpenAI key (or uses ours on the managed plan)
- It routes the request
The widget never knows your OpenAI key, database credentials, or OAuth tokens. Those only exist in the API server.
Session lifecycle
- A session begins when a visitor clicks the orb and grants mic access.
- The widget POSTs to
/v1/:siteId/tokenand receives an ephemeral token (TTL 2 hours, signing secret included). - WebRTC connects browser → OpenAI Realtime. Audio streams both ways.
- The session survives client-side navigation: the widget rehydrates from
sessionStorage, so SPA route changes do not drop the call. - The session ends when the visitor closes the tab, clicks the orb again to hang up, or two hours pass.
Where state lives
| Data | Where | Retention |
|---|---|---|
| Audio (both directions) | Browser ↔ OpenAI | Not stored |
| Transcripts | Spelo Supabase | Default 30 days, configurable 0–90 |
| Session metadata (duration, function calls) | Spelo Supabase | 12 months |
| Your database contents | Your database | We never copy it |
| Site config (colors, personality, pronunciations) | Spelo Supabase | Until you delete the site |
Security summary
- CORS per registered domain (no wildcards)
- AES-256-GCM encryption for all customer secrets at rest
- HMAC-SHA256 request signing on
/query - Read-only enforcement at three layers: DB user, adapter code, field whitelist
- Ephemeral tokens scoped to ~2 hours
Full detail in Resources → Security.
Deployment targets
| Component | Host |
|---|---|
| API | Railway / Fly.io (Node) or Cloudflare Workers |
| Dashboard | Vercel |
| Marketing | Vercel |
| Docs | Vercel |
| Widget CDN | Cloudflare (spelo.js) + S3 origin |
| Database | Supabase Postgres |
| Redis (rate limits) | Upstash |
Further reading
- Quickstart — the 5-minute path
- Install guides — one per platform
- Connect your data → Overview — adapters
- API reference — every endpoint