One script and your people can talk, draw and go live without leaving your page — a notch-style bar that unfolds into the whole product. Your users never make a Huddles account: you vouch for them, or they walk in as visitors.
Who this is for: products with a community already on them — a course with classmates, a stream with viewers, a workspace with a team. The bar stays out of the way (your users drag it to any edge); the island holds the conversation at notch size; the full product is one press away, and only if you allow it.
Two lines on your page.
<script src="https://huddles.space/embed.js"></script>
<script>
Huddles.init({
embedder: 'your-app-id',
// Minted by YOUR server — see Auth. Or omit entirely for walk-ins.
getToken: () => fetch('/api/huddles-token').then(r => r.text()),
});
</script>Huddles.init also takes position: 'top-left' … 'bottom-right' (people can drag it anyway) and exposes Huddles.open(), Huddles.pop(), Huddles.close(), Huddles.move().
Your user already logged in — to you. Making them log in again would be absurd, so your server mints a short-lived token that says who they are, signed with your app's secret. You never call our API to do it, and we never see your user database.
import { SignJWT } from 'jose';
const token = await new SignJWT({ name: user.displayName })
.setProtectedHeader({ alg: 'HS256' })
.setSubject(user.id) // your id for them — any stable string
.setIssuedAt()
.setExpirationTime('5m') // tokens are per page load, not per person
.sign(new TextEncoder().encode(process.env.HUDDLES_APP_SECRET));(appId, sub), so the same person keeps their avatar, huddles and boards across visits. Rename them on your side and they rename here.Partitioned — which is why this works in every browser that killed third-party cookies.No backend, no tokens, no accounts anywhere: omit the token and every visitor gets an identity on the fly — a numbered name and an avatar, renameable from the bar. The stream-chat shape.
<script src="https://huddles.space/embed.js"></script>
<script>Huddles.init({ embedder: 'your-app-id' });</script>anonymous on the app when that is what you want; requests are rate-limited per IP, visitor identities live in the (partitioned) cookie — same browser, same visitor tomorrow; cleared cookie, new person.The hybrid is the polished end state: start everyone as a walk-in, and once they log in to your platform, call Huddles.init with a real token — they become a stable person without losing the room they are standing in.
You choose what your people experience. A feature turned off is an affordance that is not there — never a disabled button advertising something you decided against. Absent keys mean allowed.
| Key | Off means |
|---|---|
camera | Voice only — no camera verb, no tiles. |
goLive | No broadcasting from the island. |
board / doc | No whiteboard / document entries. |
popOut | Island-only: voice and company, that is the room. |
anonymous | (Default) Only vouched-for users get in. |
Shaping is a Premium feature of the app's space — see Limits.
Three folds of one object. The bar (idle: your space, who is here, the visitor's own name; in a huddle: title and a speaking pulse; notices flash through it). The island — the huddle experience at notch size: tap a face and you are talking, mute, react, camera, leave, with the eq badge on whoever is speaking. The panel — the whole product, reached only by the person's press. One persistent iframe underneath, so folding never ends a conversation.
Your page can listen for nothing and send nothing: the widget is self-contained. State flows iframe → bar; the only inputs are the person's own presses.
| Endpoint | What it does |
|---|---|
GET /embed.js | The widget. Cacheable, self-contained, ~6 KB. |
GET /embed/:appId | The app document — framable only by your registered origins. |
POST /api/embed/session | { embedder, token } → partitioned session. 401 on a bad or expired token. |
POST /api/embed/anon | { embedder } → visitor session. 403 unless anonymous is on. Rate-limited. |
GET /api/embed/:appId/presence | { space, here, huddles } — counts, never a roster. |
GET /api/embed/:appId/config | The resolved feature shaping. |
| Claim | |
|---|---|
sub | Required. Your stable id for the user (≤128 chars). |
name | Required. Display name (≤40 chars). |
exp | Required, ≤15 minutes out. Tokens are per page load. |
avatar | Optional: { type: 'grad', i: 0–11 }. |
An embedded space is a space: the free limits exist here exactly as everywhere — huddles of 8 for 20 minutes, 3 boards and 3 documents, kept 7 days — until the app's space is on Premium, which lifts them for everyone in it and unlocks feature shaping. One plan, at the price you choose; billed to the space, never per seat and never per visitor.
An app is an id (public — it rides the iframe URL), a secret (shown once, signs your tokens), the origins allowed to frame it, and the space it opens into. Any admin of a space can create one; revoking deletes the id on the spot.
Loading…
huddles.space · For Mac · Premium · Terms · Privacy · © 2026 Huddles.Space