What it is
The Authenticated Chat (Intranet) is a way to publish the agent inside a platform where users are already logged in, like an intranet, a customer portal, a web system or an ERP.
The chat automatically recognizes who the user is, without asking them to log in again, and keeps each person’s conversation history separate and secure.
1. When to use
| Publishing option | When to use |
|---|---|
| Public (link or website) | Open websites and landing pages. Any visitor can talk to the agent. |
| Intranet (authenticated access) | Systems where the user has already logged in to your platform. The chat inherits their identity (name, email and ID from your system). |
| Shared login and password | Restricted websites where you want to protect the chat with a shared password. |
Use Intranet mode when you want:
- The conversation to start already knowing who the user is (no identification form);
- The conversation history to be tied to the user’s ID in your system;
- No one to be able to impersonate another user or see someone else’s conversation.
2. Creating the connection
- Open the project, click AI Agent Robots in the side menu and open the agent.
- Click the Channels tab.
- Click Add channel. If the agent doesn’t have any connections yet, the list of channels shows up right away.
- In the Web group, choose Authenticated web (intranet) and click Select.
- In Destination and access, click Continue. The platform lets you know that an intranet connection will be created.
- In Configuration, fill in:
- Connection name: an internal name so you can recognize it later, like “Customer Portal”;
- Allowed domains (optional): the websites where the chat can run, one per line.
- Click Create connection.
On the “Connection created” screen, click Manage connection and complete instructions. Unlike the other modes, the intranet has no ready-to-paste code: the credentials and examples are on the connection page.
⚠️ Heads up: creating the connection doesn’t publish a version of the agent. Until a version is published, the chat answers with the current draft. See how to publish in Your First Agent.
3. What the platform shows in the connection
To get back to the connection later, open the Channels tab, find the connection under Your connections and click Manage.
3.1 Code examples
In Installation, choose what to copy:
- Backend (your server): the call your server makes to authenticate each user;
- Frontend (browser): the code that opens the chat on the page with the token returned by your backend.
Both already come with your project’s Project ID. They correspond to integration Mode A. There are two ways to put the chat on your platform, explained in section 5.
3.2 Integration secret
In Credentials and actions, the Integration secret (intranet) block holds the connection’s secret key. It’s what your platform’s server uses to authenticate users in the chat. The secret is hidden: click Reveal secret to see and copy it, and Hide when you’re done. In the code examples, it shows up as SEU_SECRET_TOKEN.
⚠️ Never put the secret in browser code (HTML or JavaScript). It should only live in your application’s backend. If it leaks, anyone could generate access on behalf of your users.
4. How everything connects
┌─────────────────────┐ 1. logged-in user ┌──────────────────────┐
│ User on your │ ─────────────────────▶ │ Your platform's │
│ platform │ │ backend │
└─────────────────────┘ └──────────┬───────────┘
│ 2. POST /intranet-auth
│ (secret + user data)
▼
┌──────────────────────┐
│ Caramelo API │
│ → checks the secret │
│ → creates or finds │
│ the contact │
│ → returns the token │
└──────────┬───────────┘
│ 3. real_time_access_token (24h)
▼
┌──────────────────────┐
│ Your HTML page │
│ gets the token and │
│ loads the script │
└──────────┬───────────┘
│ 4. chat opens already identified
▼
┌──────────────────────┐
│ Chat with that │
│ user's history │
└──────────────────────┘
In summary:
- The user logs in normally on your platform;
- Your backend calls the Caramelo API with the integration secret and the user’s data;
- The API returns a temporary token unique to that user (the
real_time_access_tokenfield); - Your page receives this token and passes it to the chat script (the
secure_connection_tokenparameter); - The chat opens already identified, with that person’s conversation history.
📌 Heads up: one token, two names.
Where it shows up Name used In the API response (your backend receives it) real_time_access_tokenIn the chat script (your page sends it) secure_connection_tokenIt’s the same value: your backend receives
real_time_access_tokenand your page passes it to the script assecure_connection_token. Throughout this guide, whenever you seesecure_connection_token, read it as “thereal_time_access_tokenthe API returned”.
💡 Tip: generate the token on every page load, because it expires in 24 hours. Don’t reuse old tokens or share the same token between different users.
5. The two integration modes
There are two ways to put the authenticated chat on your platform. Both use the same script (sdk/latest/client.js) and the same intranet-auth call on the backend. What changes is how the token reaches the chat:
| Mode A: injected token (SSR) | Mode B: on demand (async) | |
|---|---|---|
| Who fetches the token | Your backend, when rendering the page | The chat script itself, by calling an endpoint on your backend |
| When the chat opens | Automatically, when the page loads | When the page calls .start() |
| Does the token show up in the HTML? | Yes, injected into the page | No, it only travels in your endpoint’s response |
| Best for | Server-rendered websites (PHP, WordPress, templates, Next.js SSR) | React apps or SPAs, cached or CDN pages, opening the chat only when a button is clicked |
🤔 Not sure which to choose? If your page is generated on the server on every request, use Mode A (simpler). If your application runs in the browser (React, Vue, Angular) or you want to control when the chat opens, use Mode B.
5.1 Mode A: token injected by the server (SSR)
Step 1 (backend): when rendering the page, your server calls the Caramelo API with the logged-in user’s data:
curl -X POST https://api.carameloai.com/api/chatbox/project/SEU_PROJECT_ID/intranet-auth \
-H "Authorization: Bearer SEU_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"external_customer_id": "user-123",
"name": "User Name",
"email": "user@example.com"
}'
| Field | Description |
|---|---|
external_customer_id | Required. The user’s unique ID in your system. It’s what links the conversation history. |
name | The user’s name (shown to the support team). |
email | The user’s email. |
Step 2 (frontend): your server injects the returned token into the page’s HTML, along with the chat script:
<!-- Caramelo AI chatbot (intranet) -->
<script src="https://static.carameloai.com/sdk/latest/client.js"></script>
<script>
window.CarameloChatbot
.create({
secure_connection_token: 'TOKEN_RETORNADO_PELO_SEU_BACKEND',
project_id: 'SEU_PROJECT_ID'
})
.start();
</script>
The script loads and opens the chat automatically, already identified.
📌 Already installed with the old code? The previous format, with
var carameloaiChatbotand theprod/index.jsscript, keeps working.
5.2 Mode B: on demand (async)
┌──────────────────┐ 1. opens the page ┌───────────────────────────┐
│ Logged-in user │ ──────────────────▶ │ Page loads client.js │
└──────────────────┘ │ (nothing shows up yet) │
└────────────┬──────────────┘
│ 2. chat.start()
▼
┌───────────────────────────┐
│ SDK makes a POST to YOUR │
│ endpoint (same origin) │
└────────────┬──────────────┘
│ 3. your backend calls
│ intranet-auth (with the secret)
▼
┌───────────────────────────┐
│ Browser gets the token │
│ → chat opens identified │
└───────────────────────────┘
Step 1 (backend): create an endpoint on your domain, like /api/chatbot-token. It identifies the logged-in user through the session, calls intranet-auth and returns the token:
// Node.js / Express example
app.post('/api/chatbot-token', async (req, res) => {
const user = req.user; // user already authenticated on YOUR platform
if (!user) {
return res.status(401).json({ error: 'unauthenticated' });
}
const response = await fetch(
'https://api.carameloai.com/api/chatbox/project/SEU_PROJECT_ID/intranet-auth',
{
method: 'POST',
headers: {
'Authorization': 'Bearer SEU_SECRET_TOKEN', // never exposed to the browser
'Content-Type': 'application/json'
},
body: JSON.stringify({
external_customer_id: user.id,
name: user.name,
email: user.email
})
}
);
const data = await response.json();
res.json({ real_time_access_token: data.real_time_access_token });
});
Step 2 (frontend): create the chat pointing to your endpoint, with autoStart: false, and start it whenever you want:
<script src="https://static.carameloai.com/sdk/latest/client.js"></script>
<script>
var chat = window.CarameloChatbot.create(
{
project_id: 'SEU_PROJECT_ID',
auth_endpoint: '/api/chatbot-token', // endpoint on YOUR domain
on_error: function (err) {
console.error('Failed to start the chat', err);
}
},
{ autoStart: false }
);
// The chat only opens when you tell it to, for example on a button click:
document.getElementById('open-chat').addEventListener('click', function () {
chat.start();
});
</script>
If you already use the old format, with var carameloaiChatbot and CarameloChatbotClient.start(), it keeps working.
| Direction | Details |
|---|---|
| SDK → your endpoint | POST <auth_endpoint>, with no body. The user is identified by your system’s session |
| Your endpoint → Caramelo API | POST /api/chatbox/project/{PROJECT_ID}/intranet-auth with Bearer + user data |
| Your endpoint → SDK | JSON with at least { "real_time_access_token": "..." } |
6. Adjusting the appearance
In Manage, the Settings and Advanced sections have the same options as the Public Chat: balloon position, compact mode, keep chat open, fixed container, timing and allowed domains. See what each one does in the Public Chat guide. Click Save after making changes.
7. Frequently asked questions
Does the user need to log in again in the chat?
No. Their identity is passed securely by your backend, and the chat opens already knowing who they are.
My application is React/SPA. Which mode should I use?
Mode B. In the browser there's no way to hide the integration secret, so the chat calls an endpoint on your own backend, which handles the authentication securely.
Can I open the chat only when the user clicks a button?
Yes. Use Mode B and call chat.start() on the click.
What happens if the token expires?
The token lasts 24 hours. Just generate a new one on the next page load (Mode A) or on the next start() call (Mode B).
Can I use the same connection in several systems?
Yes, but we recommend creating one connection, with its own secret, for each system or environment. That makes it easier to control and revoke access.
What if the secret leaks?
Delete the connection in Manage > Danger zone > Delete connection and create a new one. The new connection comes with a different secret.