Site assistant (AI)¶
The site assistant lets your visitors ask questions in plain language — "Do you have a vegetarian dish under €10?", "Are you open on Sunday?" — and get an answer built from your own data, with links to the pages it comes from.
It works directly on your tables: no plugin, no vector database to set up, no export. When you edit an entry, the next answer takes it into account within seconds.
Example
A restaurant site has a Dishes table (name, description, price, category). With the assistant turned on, a visitor asks "Which dishes contain saffron?" and gets: "The Saffron risotto (€18) [1]" — the [1] links to the page of that dish on the site.
The same assistant is also available:
- in the Studio, for your team: the ✦ button in the header opens Ask my project (see below);
- through the public API, for other websites and apps:
POST /api/v1/ask.
1. Choose what the assistant can read¶
Nothing is sent to the assistant until you decide to. For each table:
- Open the table settings (⚙️ next to the table name), then the Assistant section at the bottom.
- Turn on the switch: the list of fields appears, with suggested fields already checked (title, texts, categories, numbers, dates).
- Uncheck what the assistant does not need. Personal data (an email field, for example) is never checked by default.
- Click Turn on the assistant. Your entries are sent in the background; the progress is shown ("120 / 120 entries sent").
- To let website visitors (and the public API) use this table, check Searchable by website visitors and click Save changes.
A table can be available to your team in the Studio without being searchable by visitors: internal notes, prices, contacts… stay internal.
What is sent
Only the checked fields of the enabled tables, in the default language of the project. Categories and relations are sent as the name of the linked entry. Files, maps and colors are not sent.
2. Add the assistant to your site¶
Add one line to the layout of your site (or to a view):
A bubble appears in the bottom-right corner of every page. That's it.
| Option | Example | Effect |
|---|---|---|
mode |
mode="inline" |
bubble (default): floating bubble · inline: a block inside the page · none: no widget, only ekit.ask() |
title |
title="Any question about the menu?" |
Title of the panel. |
placeholder |
placeholder="Ask your question…" |
Text of the empty input. |
greeting |
greeting="Hello! Ask me about our dishes." |
First message shown to the visitor. |
tables |
tables="dishes,opening-hours" |
Only these tables (slugs). Without it: every table searchable by visitors. A table that is not searchable is never added. |
{{!-- a block on the menu page, limited to the dishes --}}
{{ekassistant mode="inline" title="Ask about our dishes" tables="dishes"}}
The texts of the widget (send button, messages) follow the language of the page (French or English).
Styling¶
The widget uses the font of your site. Its colors are CSS variables:
.ek-ask {
--ek-ask-accent: #b5442c; /* buttons, links, visitor messages */
--ek-ask-bg: #fffaf3; /* panel background */
--ek-ask-text: #2b2118; /* text */
--ek-ask-border: #ead8c4; /* borders */
}
Custom interface: ekit.ask()¶
To build your own interface, add {{ekassistant mode="none"}} to the page (it enables ekit.ask() without showing the widget), then:
{{ekassistant mode="none"}}
<script>
async function ask(question) {
const r = await ekit.ask(question); // never throws
if (!r.ok) return showError(r.error.message);
document.querySelector('#answer').innerHTML = r.html; // Markdown already converted, safe
// r.answer: raw text · r.sources: [{ n, title, url }]
}
</script>
ekit.ask(question, { tables: 'dishes' }) limits the question to some tables, like the tables option.
To show the answer word by word while it is written, pass onToken. It receives the text so far and its safe HTML;
the promise still resolves with the complete answer and its sources (links included):
const box = document.querySelector('#answer');
const r = await ekit.ask(question, {
onToken: (text, html) => { box.innerHTML = html; }, // called many times while the answer is written
});
if (r.ok) box.innerHTML = r.html; // final answer, with the links of the sources
If live answers are not available (old browser, proxy), onToken is simply not called and the answer arrives at the end.
How answers work¶
- Answers are written in the language of the question, even if your content is in another language.
- Each answer cites its sources as [1], [2]… A source links to the page of the entry on your site: the view that shows one entry of that table (a datasource with
slug: "{{params.slug}}", see Patterns), in the language of the page. If the table has no detail page, the source is shown without a link. - Answers appear word by word in the widget, as they are written.
- When the information is not in your data, the assistant says so instead of making something up.
- A visitor can ask follow-up questions: the conversation is kept for the duration of the visit.
Ask my project (in the Studio)¶
As soon as one table is sent to the assistant, a ✦ button appears in the Studio header. Ask my project lets every member of the project ask questions about the tables sent to the assistant — including the ones that are not searchable by visitors.
- Answers appear word by word; each citation opens the entry form.
- You can limit the question to some tables and start a new conversation (+).
- The energy used by each answer is shown (Wh).
Integration code¶
In the Assistant section of a table, the Integration button opens ready-to-copy code: the {{ekassistant}} line, a custom interface with ekit.ask(), the public API call (curl or server-side JavaScript) and an example of response.
Limits¶
| Limit | |
|---|---|
| Question length | 500 characters (website and API), 2,000 in the Studio |
| Per visitor | 12 questions per minute and 100 per day, for each site |
| Per site | 120 questions per minute |
| Per account and per month | Depends on the plan — Free: 50 in the Studio · 300 from websites and the public API; Pro: 500 · 5,000; Team: 2,000 · 20,000. See Plans & limits |
When the monthly limit is reached, the widget shows visitors a neutral "The assistant is unavailable right now" message. You receive an email at 80 % and at 100 % of the visitor quota.
Security and privacy¶
- No key in the page: the widget only talks to your own site, which checks a signed page token, the origin of the request and the rate limits.
- Visitors can only reach the tables marked Searchable by website visitors — this filter is applied by the server, never by the browser.
- Answers are displayed without raw HTML: content of your tables can never inject code into the page.
- The content you send to the assistant is processed by DeeperMind (Ekit's RAG engine) and its AI provider to answer questions about your project. Turning the assistant off for a table removes its content from the index.
Troubleshooting¶
| Symptom | Cause |
|---|---|
| The widget does not appear | The page does not contain {{ekassistant}}, or mode="none" is used. |
| "The assistant is unavailable right now" | No table is searchable by visitors yet, or the assistant is temporarily unavailable. |
| "Reload the page to continue" | The page was opened more than 48 hours ago. |
| Sources have no link | The table has no detail page on the site (no view with slug: "{{params.slug}}"). |
| The answer appears all at once instead of word by word | A proxy in front of your site keeps responses in a buffer. With nginx, Ekit already sends X-Accel-Buffering: no; check other proxies or CDNs. |
| A recent change is not in the answer | Entries are sent within a few seconds; check the progress in the Assistant section of the table. |