Smart Answer: AI answer in your website search
How to embed Smart Answer – the suche.js script, the box in the markup, the public HTTP interface for server-rendered search pages and the answer stream via Server-Sent Events, styling via CSS variables and the handover to the chat.
Smart Answer shows a short answer to the visitor's question above or below the results of your website search – streamed, with sources from your knowledge base and a field for the next question. Smart Answer is a separate service; it uses the same knowledge base as your chat assistant. It is switched on and styled in your account under Project → Smart Answer for site search.
Embedding with suche.js
If the chat loader is already on the page, one line is enough:
<script src="https://cdn.reactive.chat/suche.js" async></script>
Without the chat widget, pass the site key:
<script src="https://cdn.reactive.chat/suche.js" data-site-key="SITE_KEY" async></script>
The script attaches itself to the search fields of your page (which ones, you define in your account as a CSS selector), waits for submission or a pause in typing, and shows the answer in a box at the configured place (before, after or inside a target element). By default, it only answers input that looks like a question.
Attributes on the script tag:
- data-site-key (optional) – otherwise taken over from the chat loader (
data-rc-site-key). - data-ws-url (optional) – chat address; otherwise derived as for the chat.
- data-api (optional) – base address of the interface, default
https://ws.reactive.chator your own domain. - data-locale (optional) – language; otherwise
<html lang>, then the browser.
The script sets no cookies and only stores data in sessionStorage. For the CSP it needs script-src https://cdn.reactive.chat and connect-src https://ws.reactive.chat (Security and CSP).
Handover to the chat
If the visitor asks a follow-up question in the box, then – depending on the Follow-up question setting – the conversation continues in the chat widget (ReactiveChat('continueConversation', id, text) or ReactiveChat('startConversation', text)) or is answered in the same box. Without the chat widget on the page, the follow-up question always stays in the box.
Styling
The box (.rc-ai) brings its own CSS and is protected against your page's resets. You can adjust it via variables with the lowest specificity:
.rc-ai {
--rc-ai-akzent: #0a7cff;
--rc-ai-hg: var(--karte, #fff);
--rc-ai-text: #1d1d1f;
--rc-ai-rand: #e3e3e8;
--rc-ai-radius: 10px;
--rc-ai-schrift: inherit;
--rc-ai-abstand: 20px;
--rc-ai-schriftgroesse: 16px;
--rc-ai-zeilenhoehe: 1.6;
}
You change individual parts with .rc-ai .rc-ai__teil { … } in the Custom CSS field in your account, e.g. .rc-ai .rc-ai__hinweis { display: none; }. The protective layer does not protect against rules of your page with #id or !important.
HTTP interface
For server-rendered search pages or your own interfaces, there is a public interface without authentication and without cookies at https://ws.reactive.chat/api/suche/SITE_KEY.
Common to all endpoints:
- CORS only for origins from your project's domains (subdomains included); calls from your server without
Originalways work. - Throttle: 60 requests per minute and visitor address across all endpoints → 429 with
Retry-AfterandX-RateLimit-*. If you call from your server, your server's address counts – so for many visitors usesuche.jsin the browser or the own domain with a proxy key. - Questions and answers are not written to access logs.
GET /api/suche/SITE_KEY?locale=de – configuration, CSS and empty template of the box (Cache-Control: public, max-age=60):
{"v":1,"aktiv":false}– off, blocked or unknown (404 for an unknown key).{"v":1,"aktiv":true,"sprache":"de","konfig":{…},"css":"…","vorlage":"<div class=\"rc-ai\" …>","skript":"https://cdn.reactive.chat/suche.js"}
POST /api/suche/SITE_KEY – finished HTML of the box for a question, body at most 4 KB:
curl -s -X POST "https://ws.reactive.chat/api/suche/SITE_KEY" \
-H "Content-Type: application/json" \
-d '{"q":"How long does shipping take?","locale":"en"}'
{"v":1,"aktiv":true,"frage":false,"html":""}– the input is not a question.{"v":1,"aktiv":true,"frage":true,"html":"…","css":"<style id=\"rc-ai-css\">…</style>","skript":"…","einbettung":"…"}– puteinbettunginto your search page;suche.jsthen fills the box with the answer.- 400
{"v":1,"error":"bad_request","field":"q"}–qis missing, empty or longer than 300 characters. - 413
payload_too_large, 405 for any other method.
POST /api/suche/SITE_KEY/antwort – the answer itself as a Server-Sent Events stream, body at most 8 KB:
{"q":"How long does shipping take?","locale":"en",
"visitor_id":"v_…",
"ctx":{"url":"https://shop.example/search","title":"Search"},
"folge":false,
"vorher":[{"q":"…","a":"…"}]}
- q (string, required, 1–300 characters)
- locale (string, optional)
- visitor_id (string, optional,
[A-Za-z0-9_-]{1,80}) – the chat visitor's ID, so that the handover to the chat matches. - ctx (object, optional) –
url,path,referrer,title; query and anchor are removed. - folge (
true, optional) – follow-up question; bypasses the question filter. - vorher (list, optional) – at most 3 earlier pairs (
q≤ 300,a≤ 1500 characters).
Response text/event-stream:
event: status
data: {"stufe":"denkt"}
event: text
data: {"text":"Shipping usually takes"}
event: fertig
data: {"text":"Shipping usually takes 2–3 working days.","quellen":[{"titel":"Shipping","url":"https://shop.example/shipping"}],"fortsetzung":{"art":"faden","id":"01J…"}}
- status –
{stufe}:denkt,sucht,schreibt,wartet. The first event is alwaysdenkt. - text –
{text}: the whole text visible so far (not a delta), at most every 150 ms. - fertig –
{text, quellen, fortsetzung};fortsetzungis{art:"faden", id}(stored as a conversation),{art:"neu"}ornull. - fehler –
{code, text?}withcode:aus,gesperrt,drossel,motor,zeit,einwilligung,ungueltig. Iffehlercomes aftertext, leave the text in place.
After fertig or fehler, the stream ends. Errors before the start also come as a stream with exactly one fehler (HTTP 404, 429, 400, 413, 503 or 200). Without text after 45 seconds or without an end after 90 seconds, fehler zeit follows. If you close the connection, the answer is aborted. A proxy along the way must pass the stream through unbuffered.
// read the stream in the browser (EventSource cannot POST)
const r = await fetch('https://ws.reactive.chat/api/suche/SITE_KEY/antwort', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ q: frage, locale: 'en' }), credentials: 'omit'
});
const leser = r.body.getReader(); const dec = new TextDecoder(); let puffer = '';
for (;;) {
const { value, done } = await leser.read(); if (done) break;
puffer += dec.decode(value, { stream: true });
let i; while ((i = puffer.indexOf('\n\n')) >= 0) {
const block = puffer.slice(0, i); puffer = puffer.slice(i + 2);
const ev = /^event: (.*)$/m.exec(block), da = /^data: (.*)$/m.exec(block);
if (ev && da) zeige(ev[1], JSON.parse(da[1]));
}
}
Next: Privacy integration
Zadnje ažuriranje: