Before you start
Once you've registered a channel, the agent console has two things for you under Channel settings → Installation: a channel key and an API secret. The channel key appears in your page source and is public; the API secret must stay on your server.
That page also has a test link with no parameters at all: paste it into a browser to confirm the channel works. Worth doing first.
Script embed
A bubble appears in the bottom-right corner of your site and opens into a chat window. Place it before </body>:
<script src="https://chat.jstosecret.com/embed.js"
data-channel="YOUR_CHANNEL_KEY"
defer></script>
The chat window runs in an iframe, so your page's CSS and ours never touch. The script only injects the bubble and creates the iframe; it doesn't touch anything else on your page.
Link installation
Opens straight into a chat page — good for in-app browsers, emails and ticket receipts, anywhere you can't insert a script.
https://chat.jstosecret.com/?c=YOUR_CHANNEL_KEY
Passing user identity
Send along the user details you already have and agents know who they're talking to the moment a chat opens — and returning visitors are routed back to the agent who helped them last. All three fields are optional; send whichever you have.
| Parameter | Script attributes | Maximum length | Notes |
|---|---|---|---|
c | data-channel | 32 | Channel key, required |
uid | data-uid | 64 | The user ID in your system; this is the main signal for recognising returning visitors |
email | data-email | 128 | User email |
account | data-account | 128 | Username or account |
lang | data-lang | 20 | A specific language; leave it blank to follow the browser |
extra | data-extra | 256 | Extra info: plain text, shown to the agent as-is, not used for matching |
Anything too long is truncated and still saved — no error, and the whole session isn't lost. Length counts characters, not bytes; one Chinese character or one emoji can take several character positions.
<!-- Script method: replace the placeholders server-side -->
<script src="https://chat.jstosecret.com/embed.js"
data-channel="YOUR_CHANNEL_KEY"
data-uid="10001"
data-email="[email protected]"
data-extra="VIP customer order#8823"
defer></script>
How visitors get matched
The three identity fields are a strict priority, not a chain of fallbacks:
| You sent | Matched by | When there's no match |
|---|---|---|
uid | By uid only | Treated as a new visitor; email is not tried as a fallback |
email only | By email | Treated as a new visitor |
account only | By account | Treated as a new visitor |
| Nothing sent | Local browser identifier | Treated as a new visitor |
If you send uid, only uid is used — this is the important one. Falling back crosses identities: if you migrate your user system and uid changes, or two staff members share one [email protected], the later person inherits the earlier one's record and can read their entire chat history. uid is an identity assertion you made deliberately; when it says "this is a new user", we shouldn't override that with a weaker field.
Two things to keep in mind when you install:
- Once you have a
uid, always send it. Sendinguidthis time and onlyemailthe next turns one person into two visitors, and their history no longer lines up. uidmust be stable. Use something that doesn't change, like a database primary key — not a phone number or email the user can edit themselves, because editing it makes them a different person.
Recognition is scoped to a single channel. The same person is two separate records across two of your channels, with no shared conversations or history; that's part of how channel isolation works.
Special characters in extra info
Extra info is the parameter most likely to cause trouble, because its contents are entirely up to your business — order numbers, addresses, customer requests, anything can end up in there. Three rules:
- Always run link parameters through
encodeURIComponent()instead of concatenating strings yourself. An unencoded&,#,?,+or space will truncate the link or leak into another parameter — theBinextra=A&Barrives as a separate parameter. - HTML-escape anything you write into the
data-extraattribute:"becomes",<becomes<. Otherwise a single quote mark closes the attribute early and takes the whole script tag down with it. Server-side, your template engine's built-in escaping is enough. - Line breaks and tabs are replaced with spaces — keeping them only breaks the layout on the agent side.
Emoji and any script work as-is; storage is utf8mb4.
// The correct way to build it
const url = 'https://chat.jstosecret.com/?c=YOUR_CHANNEL_KEY'
+ '&uid=' + encodeURIComponent(user.id)
+ '&extra=' + encodeURIComponent('VIP customer order#8823 note:urgent&rush')
// Wrong: & and # unencoded, so extra only receives "VIP customer order"
// and the trailing "rush" turns into a stray parameter named "rush"
const bad = base + '&extra=VIP customer order#8823 note:urgent&rush'
These parameters are in plain text
They appear in the page source and in the address bar, and anyone can change them. Which means identity passed this way can be forged — change the uid and you're someone else, reading their chat history. If your conversations touch orders or account details, use the ticket method below.
One-time tickets
Your server exchanges the API secret for a ticket, then puts that ticket in the link it hands the visitor. No user information appears in the URL, the ticket is single-use, and a forwarded link won't open a second time.
Step 1: exchange for a ticket on your server
curl -X POST https://chat.jstosecret.com/api/open/ticket \
-H 'Content-Type: application/json' \
-H 'X-Channel-Secret: YOUR_API_SECRET' \
-d '{"channelCode":"YOUR_CHANNEL_KEY","uid":"10001","extra":"VIP customer order#8823"}'
# Response
{ "ticket": "a1b2c3...", "expiresIn": 300 }
Step 2: hand the ticket to the visitor
# Link method
https://chat.jstosecret.com/?c=YOUR_CHANNEL_KEY&ticket=a1b2c3...
# Or script method
<script src="https://chat.jstosecret.com/embed.js"
data-channel="YOUR_CHANNEL_KEY"
data-ticket="a1b2c3..."
defer></script>
- The API secret must stay on your server. Put it in the front end and it's public — anyone can sign themselves in as anyone.
- Tickets are valid for 5 minutes by default; use
expiresInto set anything from 30 to 1800 seconds. - Visitors refreshing the page are unaffected: after the first load the ticket is swapped for a long-lived local token.
- Tickets carry identity; they don't store it. If a visitor comes back three months later, issue a new ticket — the history is all still there.
Appearance & position
The bubble's icon, position, margins and accent colour, plus the project name and icon at the top of the chat window, are all set under Channel settings in the console. Changes take effect as soon as the visitor reloads — no need to re-paste the code.
If a particular site needs the position adjusted (say the bottom-right corner is already taken), attributes can override it:
<script src="https://chat.jstosecret.com/embed.js"
data-channel="YOUR_CHANNEL_KEY"
data-position="left-bottom"
data-offset-x="24"
data-offset-y="90"
defer></script>
Note that these attributes take priority: once you add them, this site's position is fixed and later changes in the console won't apply. Use them only when you really need to.
Dedicated domain
Professional and above include a dedicated domain. The chat window and bubble run on a domain of yours, such as chat.yourdomain.com, so visitors see your brand in the address bar.
Why it's worth setting up
Beyond branding, the real benefit is isolating failures. By default every customer shares our chat domain — so if any one of them gets blocked by some network, some ISP or some corporate firewall, the domain stops loading for everyone on it. All you see is "visitors suddenly can't connect", and you'd be debugging entirely the wrong thing.
On your own domain, other people's outages never reach you — and when it is your turn to have a problem, one DNS change brings you back without queueing behind us. Flagship includes 5, so multiple brands or sites can each run their own without affecting each other.
How to set it up
- You add one CNAME record pointing at the address we give you
- We request and renew the certificate; nothing for you to track
- Once it's live, swap the address in your installation code for the new domain — nothing else changes
To enable it, contact [email protected] and tell us the domain you want to use.
Manual control
To open the chat window from a button on your own page instead of the default bubble:
// Available once the script has loaded
window.KefuWidget.open()
window.KefuWidget.close()
window.KefuWidget.toggle()
The bubble itself can't be hidden — if you only want to use your own button, move the bubble off screen with its offsets, for example data-offset-x="-100".
Trouble installing
Start with the error message your server returned. Most installation problems (wrong channel key, expired ticket, secret exposed on the front end) state the cause directly in the response.
- Technical support: Telegram @chatcocoaofficial, 24/7
- Sales and custom work: [email protected]