Websites
One script tag puts the copilot on any website — plain HTML, React, Vue, Angular, Next.js or a CMS theme.
The web SDK is one JavaScript file with no dependencies. It does not care what your site is built with, and it speaks the same protocol as the Flutter SDK: the same components, the same actions from the console, the same persona. One app in the console can serve your mobile app and your website with the same key.
1. Add the tag
Create an app in the console and copy its test key: Settings → API keys, Copy beside Test. Then:
<!-- Inside <head>, on every page. Swap in the live key when the site goes live.
data-app-key: your app's key — Rendel console → Settings → API keys → Copy.
data-languages: "tr" Turkish only, "tr,en" Turkish or English,
"en" English only. Leave it out to answer in whatever the visitor writes. -->
<script
src="https://rendel.ai/sdk/web/0.10.0/rendel.js"
data-app-key="rd_pk_test_…"
data-languages="tr"
></script>That is the whole installation. A button appears in the corner and opens the copilot. Where the tag goes depends on the site:
| Your site | File |
|---|---|
| Plain HTML | every page, inside <head> |
| React (Vite), Vue, Svelte | index.html, inside <head> |
| Angular | src/index.html, inside <head> |
| Next.js | app/layout.tsx, as a <Script> (below) |
| WordPress | your theme's header.php, before </head> |
In Next.js a bare <script> is not the idiom; the root layout loads it:
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="tr">
<body>
{children}
{/* data-app-key: your app's key — Rendel console → Settings → API keys → Copy. */}
<Script
src="https://rendel.ai/sdk/web/0.10.0/rendel.js"
data-app-key="rd_pk_test_…"
data-languages="tr"
strategy="beforeInteractive"
/>
</body>
</html>
);
}Pin the version in the address. 0.10.0 stays 0.10.0 after the next release
ships, so your site changes only when you change it.
2. Tell it who is signed in
In your own sign-in code:
// Right after your sign-in succeeds:
Rendel.identify({ userId: user.id });
// On every page: the signed-in person's current token, or null, so the
// copilot can reach your API as them — no API key.
Rendel.setUserToken(() => getAccessToken());
// When the user signs out:
Rendel.reset();setUserToken is how the copilot answers from your own API — "my order", "my
routine" — as the person asking, with no API key to issue: in the console, set
those endpoints to the signed-in user's token. The function is asked before
every question, so return the current token (refresh it there if it has run
out), or null when nobody is signed in. It goes on to your endpoints as
Authorization: Bearer, is never stored, and each person reaches only what
their own token opens. Call it on every page, since a function cannot be
remembered across loads.
An endpoint that changes something — "book me in on Tuesday" — is asked on a confirmation card first. Once the person confirms, Rendel makes the call as them and answers with what happened; there is no handler to write on the page.
userId is the id your own backend knows the person by — the same one your
mobile app passes, so a person has one history across both. The SDK remembers
them across page loads and visits, so a returning visitor needs no second call.
Pass traits ({ plan: "pro" }) for anything the copilot should know about them, and userHmac when
identity verification is on.
Without these, every visitor is anonymous and their conversations belong to the browser. That is the right default for a site with no sign-in.
The conversation follows the visitor from page to page within the tab: a link to another page of your site does not start it over.
3. Allow your domain
The test key works on localhost and 127.0.0.1, on any port, straight away.
Before the site goes live, add its domain in the console under Settings →
Keys → Allowed domains. A key in a web page can be read by anyone who opens
its source; the list is what stops it working on their site. Until the domain
is listed, the live key answers that site with origin_not_allowed.
musteri.com means https://musteri.com. www.musteri.com is a separate
entry, and *.musteri.com covers every subdomain. Your mobile apps send no
domain and are not affected by the list.
Permissions
Nothing to add to any file. The "+" offers Photos and Files, which open the browser's own file picker (pictures; PDFs and text files), and Camera, which the browser asks the visitor for the first time it is used. The microphone uses the browser's speech recognition — the browser asks the visitor for the microphone the first time it is pressed. It opens voice mode: what the visitor says is written in the middle of the panel as they say it, and sent on its own when they stop.
- The microphone needs https (
localhostcounts). Firefox has no speech recognition, so it is not shown there; everything else works. - Inside an
<iframe>, the frame needsallow="microphone; camera". - If your site sends a Content-Security-Policy, allow the SDK and the API:
script-src https://rendel.ai;
connect-src https://api.rendel.ai;
img-src https:;Actions
Actions you connect in the console run on our servers and work on the website with no code. An action that should run in the page, as the signed-in visitor, is registered the way the Flutter SDK registers one:
Rendel.registerAction({
name: "get_order_status",
description: "Fetch the delivery status of an order",
params: {
type: "object",
properties: { order_id: { type: "string" } },
required: ["order_id"],
},
risk: "read",
handler: async ({ order_id }) => {
const response = await fetch(`/api/orders/${order_id}`);
return response.json();
},
});params is JSON Schema. Return what the copilot should know, or throw to say it
failed; keep the result under 16 KB. write and destructive actions get the
same server-built confirmation card as on a phone, and confirmTemplate words
it.
Options
The data attributes cover the common case. For the rest, leave data-app-key
off the tag and call init yourself:
Rendel.init({
appKey: "rd_pk_test_…",
languages: ["tr"],
assistantName: "Pati",
suggestions: ["Milo bugün nasıl?", "Aşı takvimini göster"],
launcher: false, // your own button: Rendel.open()
});| Option | |
|---|---|
languages, locale | What it answers in; locale is your site's language picker. |
assistantName, launcherLabel, suggestions, emptyStateTitle, emptyStateBody, composerHint | The words on screen. |
theme | surface, onSurface, accent, onAccent and the rest of the console's appearance roles. |
launcher | false hides the corner button. Open it with Rendel.open(), close() or toggle(). |
actions | The same as registerAction, all at once. |
onLog | Receives the SDK's warnings instead of the browser console. |
Appearance and the opening surface published from the console override these, on the website and the app alike, without a release.
Rendel.on("opened" | "closed" | "messageSent" | "actionExecuted", fn)
subscribes to what happens; Rendel.deviceId is the anonymous id to quote
in a support ticket.
TypeScript
Types are published beside the file. Save
rendel.d.ts
into your sources and window.Rendel is typed.