The snippet
</body> tag of every page that should have the bubble. Your
data-website-id is on the channel’s Install tab.
That is the whole installation. Everything below is optional.
The website id is public and meant to be. It sits in a page anyone can read the source
of. What makes it safe is the domain allowlist on the channel: the widget refuses to boot
on any origin the channel’s owner hasn’t listed, so a copied id is useless elsewhere.Never put an API key in a page. A Linkiasoft API key carries workspace-wide access — see
Authentication.
What it costs your page
- The script is
asyncand boots when the browser is idle, so it is never on the critical path to your first paint. - The chat UI itself is an iframe on our origin, and it is not fetched until somebody opens the panel — or until a reply arrives for a visitor who has one waiting.
- The live connection is a single
EventSource. No polling, no WebSocket upgrade to be mangled by a corporate proxy, no client library.
Calling it before it loads
If you need to talk to the widget from your own code — identify a signed-in user, open it from your own button, listen for events — add the queue stub above the script tag:onload. The full command list is in
the JavaScript API.
Overriding settings on one page
The dashboard holds the defaults. A single page can override the look, the launcher and the greeting before boot:Linkia('init', …).
Copy other than the greeting stays server-side deliberately: support can fix a typo in the
offline message without a customer redeploying their site.
Your own launcher
Any element carryingdata-linkia-open opens the widget, and any element carrying
data-linkia-unread receives the unread count as its text:
hideLauncher: true if you don’t also want our bubble.
Single-page apps
The widget survives client-side navigation on its own — it is not tied to a route, and the loader ignores a second injection. So:- Inject the script once, in your root layout or
index.html, not in a page component. - Don’t remount it per route. If you must remove it entirely, call
Linkia('destroy'). - Re-identify only when the user changes, not on every navigation.
Content Security Policy
If your site sends a CSP, allow our origin in four directives:connect-src covers both the widget’s requests and its EventSource stream. img-src
needs whatever host serves your logo and any images your visitors send, which is our media
CDN unless you set your own.
A blocked directive shows up in the browser console as a CSP violation naming the
directive that refused. That message is the fastest route to the fix — read it before
changing anything else.
What the widget stores
The token lives in your page’s storage rather than the iframe’s on purpose: Safari and
Firefox partition storage inside a cross-origin iframe, so a token kept there would be
discarded on every reload and every returning visitor would look new.
No cookies are set, and nothing is shared with any other site.
Limits
Exceeding one gets a
429; the widget shows the message as unsent with a retry rather
than losing it.
When it doesn’t appear
Work down in order — the first four cover almost everything:- Console. The widget logs one line beginning
[Linkia chat]when it refuses to start, and it names the reason. - The domain allowlist.
403from/bootmeans this origin isn’t listed.acme.comcoverswww.acme.com; a subdomain needs*.acme.com. - The website id.
401means unknown or paused — check the channel is connected and the id matches the Install tab. - CSP. A violation in the console names the directive to add.
- Ad blockers. Several block chat widgets by hostname. Test in a clean profile.
Next
JavaScript API
Open and close it, identify visitors, listen for events.
Identity verification
Sign the user id on your server so a browser cannot claim someone else’s.

