Web chat widget
The web chat widget adds a floating chat button to your site. Visitors who open it talk to one of your Jelliu agents, by text or, if you enable it, by voice.
Two credentials, not interchangeable
Every widget has two identifiers. Keep them apart:
The widget API key is shown once, as plaintext_api_key in the response that creates the widget. Jelliu stores only a keyed hash of it, and no other response carries the key or its hash: listing, reading and updating a widget return no api_key field. If you lose the key, create a new widget. The standard embed does not need it.
The widget API key is not a workspace API key (jl_...), and neither one belongs in a web page. The only credential the embed snippet uses is the public widget ID.
Embed the widget
Create the widget
Create it in the dashboard under Widgets, or with the API (a write key is enough):
The widget’s id in the response is your widget ID.
What the script does
- Adds a round launcher button in the corner set by
branding.position, in yourprimary_color. - Loads the chat panel in an iframe the first time a visitor opens it, so pages where nobody chats only load the small loader.
- Shows a side panel on desktop and a full-screen panel on screens up to 520 px wide.
- Allows the chat panel to use the microphone, which voice conversations need. Browsers still ask the visitor before granting it.
- Runs once per page, even if the snippet is included twice.
- On Shopify storefronts, forwards the signed-in customer’s email, name and ID, and the shop domain, so conversations are linked to the right contact.
Allowed origins
A widget answers only on the sites listed in allowed_origins. The chat panel reports the origin of the page that embeds it, and Jelliu compares it with the list:
- The scheme and port must match exactly.
- The hostname must match, except that one leading
www.is ignored:https://example.comalso covershttps://www.example.com, and the reverse. - Other subdomains need their own entry.
https://shop.example.comis not covered byhttps://example.com. *is never accepted. At least one origin is required.
Requests from a page that is not allowed receive 403 with code FORBIDDEN and the message Origin not allowed.
Widget settings
The agent that answers visitors. It must be an agent of your workspace that has not been deleted. Any other ID, including an agent of another workspace, is refused on create and update with 404 AGENT_NOT_FOUND (El agente no existe en este espacio de trabajo.).
1 to 200 characters.
Full origins such as https://www.example.com. At least one.
primary_color (required inside branding, hex #RRGGBB), position (bottom-right or bottom-left), title (up to 100 characters), subtitle (up to 120), quick_replies (up to 4 short replies), agent_names (up to 8 display names), agent_avatars (up to 8 HTTPS image URLs aligned with agent_names), and i18n (per-language greeting and quick_replies, keyed by language such as es or en).
The object replaces the stored branding; it is not merged.
branding.logo_url was removed on 2026-09-15. It validated, stored and shipped to every visitor, and nothing ever drew it — the widget draws no logo. Sending it now returns 400 VALIDATION_FAILED with El campo branding.logo_url ya no existe: el widget no dibuja ningun logo. under error.details.fieldErrors.branding.
It is also stripped from every response — the admin reads, POST /widget/init and the embed script — so a client that reads a widget, changes one key and sends the object back will not trip over a stored value. Values already saved stay in the database untouched.
Up to 2000 characters.
Let visitors talk to the agent by voice.
Requests per minute allowed for this widget, per credential, on the public /widget/* endpoints. An integer of 1 or more; 30 when you do not send it. Settable on create and on PUT /api/widgets/{id}, and editable from the dashboard.
Raising it does not lift the per-workspace cap of 300 requests per minute across all of a workspace’s widgets, which still applies on top — a workspace with ten widgets at 300 rpm each is still capped at 300 rpm in total. The per-IP limit of 60 requests per minute applies as well.
Update a widget with PUT /api/widgets/{id} (send only the fields to change) and remove it with DELETE /api/widgets/{id}.
Limits
Public widget traffic is limited at several levels:
Exceeding a limit returns 429 with code RATE_LIMIT_EXCEEDED.
Calling the widget endpoints directly
The standard embed handles everything. If you build your own chat interface, the widget endpoints are served from https://api.jelliu.co:
Authenticate with the x-widget-api-key header and send x-widget-parent-origin set to one of the widget’s allowed origins. Keep the widget API key on a server you control.

