---
url: /modules/ai-chatbot.md
---
# AI chatbot

A chat on the website that answers visitors from the site's own content. It runs on `laravel/ai`, takes its instructions from a block in the CMS, knows which page the visitor is on, keeps a conversation going, and logs the exchanges for review in the panel. Off by default.

::: glance

* **Module key** `ai-chatbot`
* **Default** **off**
* **Switch** `EVOLVE_MODULE_AI_CHATBOT=true` or `'ai-chatbot' => true` in `config/evolve.php`, then `php artisan migrate`; see [Modules](/modules/#switching-a-module-on-or-off)
* **Role access** `evolve.roles.modules.ai-chatbot`
* **Requires** `laravel/ai` in the project, see below
* **Since** 2.1
  :::

## Requirements

* `composer require laravel/ai` in the project (Laravel 12). Evolve only suggests the package. Before 2.21 it came with Evolve, so a project that ran the chatbot without requiring it loses the package on the first `composer update` to 2.21 and has to require it then. While the package is missing, the module stays off even with its switch on, the health endpoint reports it with `active: false` and `missing_packages: ["laravel/ai"]`, and the [module switches check](/site/health-checks) warns.
* An API key for the provider `laravel/ai` is configured to use. The default provider is OpenAI with `OPENAI_API_KEY`, the same key the [editor AI](/panel/editor-ai) uses. The model is the `laravel/ai` default for that provider unless the project publishes `config/ai.php` and sets one.
* A running Laravel scheduler on the host (`schedule:run` cron), otherwise logged conversations are never pruned.

## Configuration

| Variable | Default | Effect |
|---|---|---|
| `CHATBOT_RATE_LIMIT` | `10` | Questions per minute per IP address. The limiter keys on the IP in the cache only; no IP is stored. |
| `CHATBOT_SYSTEM_PROMPT` | empty | Fallback system prompt when the block has none. Empty means the built-in instructions. |
| `CHATBOT_CONTEXT_CACHE` | `300` | Seconds the site context is cached per locale. `0` rebuilds it on every question. |
| `CHATBOT_RETENTION_DAYS` | `90` | Days a logged conversation is kept. `0` keeps everything. Pruned daily by `model:prune`. |
| `CHATBOT_NOTICE` | German default text | Notice shown below the input; `:days` is replaced by the retention. |
| `CHATBOT_HISTORY_LIMIT` | `20` | Earlier messages a follow-up question may carry. A longer conversation keeps its opening question and answer and drops messages from the middle (since 2.21, before: 10). |
| `CHATBOT_WIDGET` | `false` | Show the floating chat button on every page. |
| `CHATBOT_WIDGET_BLOCK` | unset | ID of the chatbot block the widget takes its texts from. Unset uses the first published one. |

None of these are edited in the panel. `config/ai-chatbot.php` has more for developers: `agent` (a subclass of `ChatbotAgent` to change model, temperature or steps), `tools` (classes implementing `Laravel\Ai\Contracts\Tool` the agent may call, for live data), `context.sources` (what feeds the site context) and `context.posts_limit` (recent posts included, default 20).

## How it answers

The agent's instructions are the block's system prompt, or `CHATBOT_SYSTEM_PROMPT`, or the built-in default, which tells the model to answer from the site content, admit when it cannot, respond in the visitor's language and format as Markdown. Appended to that come the page the visitor is on (so "this product" resolves) and the **site context**: pages, FAQs and blog posts, rendered as text per locale by the context sources and cached. Sources whose module is off are skipped. Answers stream to the browser; a provider error shows an "unavailable" notice (since 2.11). The browser renders the Markdown itself, escaped first: paragraphs, bold and italic, links, nested lists and tables (since 2.21). Links in answers open in a new tab, so the conversation stays open. The script is marked `data-cookieconsent="ignore"`, because Cookiebot's auto blocking would otherwise run it after Alpine has started and leave the widget empty (since 2.21). Visitors cannot replace the instructions: the server resolves the prompt from the published block and ignores any prompt a client sends (since 2.14).

## Blocks and widget

The **AI Chatbot block** (`cms.aiChatbot`, group Interactive) has a title, an introduction, the system prompt, the input placeholder and a disclaimer line. Place it on a page to get an embedded chat. Publish the block, otherwise it is ignored.

The **floating widget** (`CHATBOT_WIDGET=true`) adds a chat button in the bottom right corner of every page. Its texts and prompt come from a published chatbot block, `CHATBOT_WIDGET_BLOCK` picks which one. Without a published block the widget renders nothing. The starter theme includes the widget since 2.15; a project with an older theme adds `@includeWhen(View::exists('ai-chatbot::widget'), 'ai-chatbot::widget')` to its frontend layout and rebuilds the CSS. A custom scroll-up button in the same corner should move up while the widget is on.

## Conversation log

Every question and answer is stored with its conversation ID, the page it was asked from, tool calls, model and token counts. No IP address is stored (since 2.14). The panel lists conversations under **Chatbot > Unterhaltungen** (`/evolve/ai-chatbot/conversation`), newest first, with search over questions, answers and pages, a thread view, and a CSV export that honours the search. Cmd-K: "Conversations".

Two obligations follow: the notice below the input tells visitors about the log, and the site's privacy policy should mention it. `CHATBOT_RETENTION_DAYS` sets how long the log is kept.

## Publishing

`ai-chatbot.config` publishes `config/ai-chatbot.php`, `ai-chatbot.blueprints` the block blueprint to `app/Blueprints`, `ai-chatbot.views` the block view to `theme/views/components/blocks/cms`. A project that published the block view before 2.14 must send the block ID as `block` and the `conversation` UUID along, otherwise the default instructions apply and threads are not grouped.

## Verifying

Place a published chatbot block, ask a question the site answers (an FAQ works well) and one it cannot answer. Then open **Chatbot > Unterhaltungen** in the panel: both questions appear in one conversation with the model and token counts. `php artisan schedule:list` shows the daily `model:prune` entry.

## Troubleshooting

* **Module on, nothing in the sidebar:** `laravel/ai` is not installed. The log says so.
* **Answers ignore the system prompt:** the block is not published, or a published view still sends `system_prompt` instead of `block`.
* **Widget missing:** `CHATBOT_WIDGET` is off, no chatbot block is published, or the theme layout lacks the include.
* **Stale answers about changed content:** wait for `CHATBOT_CONTEXT_CACHE` or clear the cache.
