Everything the module does is recorded in its own MySQL table, module_chatbot_log, and summarised on the dashboard.
Dashboard
Admin > Chatbot (/admin/chatbot) opens the dashboard. It is built entirely from the log table, so the figures depend on the Log level setting: chat and search events are logged at info, and a level of warning or error hides them from the dashboard.
- At a glance: chats in the last 24 hours, 7 days and 30 days; searches in the last 30 days; average and 95th percentile response time over 7 days; errors and rate-limit hits over 7 days.
- Daily activity: a bar chart of chats plus searches per day for the last 30 days.
- Top queries: the ten most frequent questions and search queries over 30 days, compared case-insensitively.
- Events: a count per event name over 30 days.
- Recent chat responses: the last 20 answers. Expand one to read the full question, the generated answer and the cited sources.
The page actions link to Export CSV, View Logs and Settings.
Log viewer
View Logs (/admin/chatbot/logs) lists entries newest first, 50 per page, with a Filter by level selector. Each row shows the level, event name, message and time. Entries with extra context, such as the full question and answer of a chat, have an expandable Context section showing the raw JSON.
| Event | Level | Meaning |
|---|---|---|
index.item, index.media, index.blog_post, index.site_page |
info | A resource was indexed. |
index.chunk |
info | One chunk was embedded, with timing. |
index.skip |
info | A resource was skipped: no text, not public, or outside the item set filter. |
index.embed |
error | Embedding or the Turso insert failed. |
index.rebuild |
warning | The DISKANN index could not be rebuilt. |
delete.index, delete.vector |
error, warning | Removing a deleted resource's chunks failed. |
dispatch.error |
error | An index job could not be queued. |
chat.search |
info | Retrieval step of a chat, with embed and search timings. |
chat.complete |
info | An answer was generated. Context holds the question, answer, sources, timings, model, site id and the item set ids sent with the request (null when none). |
semantic_search |
info | A search ran. Context holds the query, chunk count, timings, site id and item set ids. |
chat.rate_limit, search.rate_limit |
warning | A request was refused by the rate limiter. |
chat.error, search.error |
error | Turso or OpenAI failure, returned to the visitor as HTTP 503. |
chat.unexpected, search.unexpected |
error | Any other failure, returned as HTTP 500. |
Exporting logs
Export CSV on the dashboard or the log viewer downloads every log entry, not just the current page, as chatbot-logs-YYYYMMDD-HHMMSS.csv. From the log viewer the active level filter is applied. Columns: id, created_at, level, event, message, question, answer, source_count, total_ms, site_id and the raw context JSON. The file starts with a UTF-8 byte order mark so it opens cleanly in Excel.
Log retention
Set Log retention (days) on the Behaviour tab (default 90; 0 keeps everything). Retention is not applied on a schedule. Click Purge Old Logs Now on the Diagnostics tab to dispatch a PurgeChatbotLog job that deletes older entries in batches of 1000. The button is disabled when retention is 0.
Test search
Run Test Search on the Diagnostics tab embeds the text you enter (or "test" if empty), runs a live vector search and prints:
- the current embedding model, dimensions, chunk size, Top-K and Turso URL,
- whether Turso is reachable, the number of chunks indexed and when the last chunk was written,
- the last 10 warnings and errors from the log,
- the vector length returned by OpenAI and the top matching chunks with their distance and a snippet.
If no chunks are indexed, or chunks exist but the search returns nothing, a hint tells you to re-index. The test search is available to every role that can open the settings page: editors, site admins and global admins.