Chatbot replies are too slow and users leave before it answers
This runbook is for teams whose chatbot feels sluggish, times out, or makes visitors abandon the conversation. You will learn how to identify whether the delay is caused by the AI model, your app server, a database lookup, a third-party integration, or frontend settings, and how to fix each one with concrete steps.
TL;DR — If your chatbot is taking too long, the most common cause is slow upstream work before the answer is shown: a large AI model call, slow retrieval from your knowledge base, or a frontend timeout/loading pattern that hides progress. Start by timing the full request in your browser and in your server logs; if the AI call itself is slow, switch to streaming responses or a faster model first. Reading time: ~6 min
The scenario
It is a normal Tuesday afternoon. You open your site, ask the chatbot a simple question like "What are your support hours?", and then just watch the typing indicator spin. Some visitors wait 15 to 30 seconds, some refresh the page, and some close the chat entirely. Your app dashboard says the site is "up", but support messages are coming in saying the bot is "broken" because it answers too late to be useful.
Symptoms
- The chat widget shows a spinner, "Thinking...", or no visible change for more than 8-10 seconds.
- Users report they "gave up waiting" or send duplicate messages because they think the first one was ignored.
- Browser Network tab shows a slow request such as:
POST /api/chat 200 (18.4 s)
- Reverse proxy (the server that sits in front of your app) logs show long request times, for example:
"POST /api/chat HTTP/1.1" 200 8421 rt=19.237 uct=0.003 urt=19.201
- App logs show slow model or retrieval calls, for example:
chat request completed in 21.4s
llm_latency_ms=16782
retrieval_latency_ms=3241
- Some requests fail only after waiting a long time, with messages like:
504 Gateway Timeout
upstream request timeout
ETIMEDOUT
context deadline exceeded
- The first message after inactivity is much slower than later ones (a common sign of cold start, meaning the app was asleep and had to wake up).
Likely causes
| Cause | How common | Quick check |
|---|---|---|
| AI model call is slow or using a heavyweight model | Very common | Browser DevTools → Network → open POST /api/chat and compare total time with your app log's llm_latency_ms |
| Retrieval/database lookup is slow before the model answers | Common | In your app logs, search for retrieval, vector, db, or query duration around a slow request |
| No streaming response, so users see nothing until the full answer is done | Common | Browser DevTools → Network → click chat request and check whether bytes arrive gradually or only at the end |
| App server is overloaded or scaled to zero | Common | In your hosting dashboard, open Metrics/Monitoring and check CPU, memory, and request queue during a slow chat |
| Third-party integration in the chat flow is blocking the reply | Sometimes | Temporarily disable one integration/webhook in your app settings and retest one prompt |
| Proxy or app timeout is too low, causing retries or long hangs | Sometimes | Check your proxy/app logs for 504, timeout, upstream timed out, or context deadline exceeded |
Step-by-step diagnosis
-
Measure one slow reply in the browser
Open your site in Chrome or Edge, pressF12, then go to Network. Send one test message likeWhat are your support hours?and click the request that handles chat, often something like/api/chat,/chat, or/messages.
This is your problem if: the request takes more than 8 seconds total. Note whether the response starts quickly or only appears at the very end.
Jump to: If nothing appears until the end, go to No streaming response. If it starts late because the server is slow, continue to step 2. -
Check your app logs for where the time is spent
In your hosting provider's dashboard, open Logs for the web service or app service that handles chat. Search by the request path or timestamp of your test. If you have CLI access, tail logs while sending one message:
tail -f /var/log/app.log
This is your problem if: you see one clear slow section such as llm_latency_ms=..., retrieval_latency_ms=..., db query took ... ms, or a webhook call taking several seconds.
Jump to: llm slow → AI model call is slow. retrieval/db slow → Retrieval/database lookup is slow. webhook/integration slow → Third-party integration is blocking.
-
Check server load and cold starts
In your hosting dashboard, open Monitoring, Metrics, or Observability for the app. Look at CPU, memory, and request count during a slow test. If your platform can scale to zero, also check whether the app had zero running instances before the request.
This is your problem if: CPU is pinned high, memory is near the limit, request queue grows, or the first request after idle is much slower than the next one.
Jump to: App server is overloaded or scaled to zero. -
Look for timeout errors
Search logs for these exact terms:
504
upstream timed out
context deadline exceeded
ETIMEDOUT
This is your problem if: slow requests end with one of those messages, or users wait a long time and then get an error.
Jump to: Proxy or app timeout is too low.
-
Rule out a blocking integration
In your app admin area, temporarily turn off one optional step in the chat flow, such as CRM lookup, ticket creation, analytics webhook, or translation call. Retest the same prompt. If settings vary by product, look for Integrations, Automations, or Webhooks in your app dashboard.
This is your problem if: response time drops sharply after disabling one integration.
Jump to: Third-party integration is blocking. -
Confirm whether streaming is enabled end-to-end
If your app claims to stream tokens (small chunks of text sent as they are generated), test whether the browser actually receives chunks. In DevTools → Network, click the chat request and watch whether the response grows while the request is still open.
This is your problem if: the full answer arrives only when the request finishes, even though your backend supports streaming.
Jump to: No streaming response.
Fixes
AI model call is slow or using a heavyweight model
Use a faster model for chat, lower the maximum output length, and stream the answer as it is generated.
Typical app settings to change:
{
"model": "smaller-or-faster-chat-model",
"temperature": 0.2,
"max_output_tokens": 400,
"stream": true
}
If your model settings are stored in environment variables, update them in your hosting dashboard under Settings → Environment Variables or similar:
MODEL_NAME=smaller-or-faster-chat-model
MAX_OUTPUT_TOKENS=400
ENABLE_STREAMING=true
If your code waits for the full model response before replying, change it to stream partial output to the browser instead of buffering it server-side.
Verify it worked: send the same prompt again and confirm the first text appears within 2-4 seconds, even if the full answer finishes later.
Retrieval/database lookup is slow before the model answers
Reduce the amount of data searched, add indexes (data structures that speed up lookups), and set a hard time limit on retrieval so the bot can answer without waiting forever.
For Postgres, check slow queries and add an index for common filters:
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_documents_org_id ON documents (org_id);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_messages_conversation_id ON messages (conversation_id);
If your app does semantic search (finding similar text), reduce the number of chunks fetched before sending context to the model. For example, change retrieval from 20 chunks to 5 in your app config:
{
"retrieval_top_k": 5,
"retrieval_timeout_ms": 1500
}
If you have a provider dashboard for your database, open Monitoring → Slow queries and use the exact query shown there to add the right index.
Verify it worked: app logs should show retrieval or DB time dropping to low hundreds of milliseconds instead of several seconds.
No streaming response, so users see nothing until the full answer is done
Turn on streaming in both the backend and the reverse proxy. A common mistake is enabling streaming in app code but buffering it in nginx.
If you use nginx, disable buffering for the chat endpoint:
location /api/chat {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
chunked_transfer_encoding on;
proxy_read_timeout 300s;
}
Then reload nginx:
sudo nginx -t && sudo systemctl reload nginx
If your frontend waits for the entire response body before rendering, update it to append chunks as they arrive instead of calling a single response.json() at the end.
Verify it worked: in DevTools, the response should start growing before the request completes, and users should see text appear progressively.
App server is overloaded or scaled to zero
Increase the number of app instances, raise CPU/memory limits if they are pegged, and keep at least one instance warm if your platform supports sleeping services.
In your hosting provider's dashboard, open your app service and increase:
- Instances/Replicas from
1to2 - Memory if usage is consistently above 80%
- CPU if CPU is pinned during chat bursts
- Minimum instances from
0to1if the platform sleeps when idle
If you manage the app with Docker Compose, you can raise resources and run more than one app process behind a proxy, but use the dashboard path first if available.
⚠️ Changing instance counts or memory can briefly restart the app and may cause a short interruption.
Verify it worked: the first request after idle is no longer dramatically slower, and CPU/request queue graphs flatten during busy periods.
Third-party integration in the chat flow is blocking the reply
Move non-essential integrations after the reply, or run them asynchronously (in the background instead of inline). For example, do not wait for CRM sync, analytics, or ticket enrichment before showing the answer.
If your app has webhook settings, shorten the timeout and stop retrying inline:
{
"webhook_timeout_ms": 1000,
"webhook_async": true,
"webhook_retries_inline": 0
}
In your dashboard, look for Integrations, Automations, or Webhooks, then disable each optional integration one at a time and keep the slow one off until it is rewritten to run in the background.
Verify it worked: disabling the integration cuts reply time immediately for the same prompt.
Proxy or app timeout is too low, causing retries or long hangs
Raise the timeout enough for legitimate long responses, but pair that with streaming so users are not staring at a blank spinner.
For nginx:
location /api/chat {
proxy_pass http://app;
proxy_connect_timeout 10s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
Reload nginx:
sudo nginx -t && sudo systemctl reload nginx
If your app has its own request timeout, increase it in environment variables or config:
REQUEST_TIMEOUT_MS=300000
Do not set timeouts extremely high unless you also fix the root cause; otherwise users will just wait longer before failure.
Verify it worked: timeout errors disappear from logs, and long answers either stream properly or complete successfully.
Prevention
- Add a latency alert for the chat endpoint. In your monitoring tool, alert when p95 (95th percentile) latency for
POST /api/chatstays above 8 seconds for 10 minutes. If you use nginx logs, include request time in the log format:
log_format timed '$remote_addr - $request $status rt=$request_time urt=$upstream_response_time';
- Log each stage of the chat pipeline separately so you can see whether the delay is model, retrieval, DB, or integration:
{
"event": "chat_timing",
"request_id": "abc123",
"retrieval_ms": 420,
"llm_ms": 3100,
"webhook_ms": 0,
"total_ms": 3650
}
- Put a performance check in CI/CD (build and deploy pipeline) that fails if median chat time regresses too far. Example smoke test:
curl -s -o /dev/null -w 'total=%{time_total}\n' -X POST https://your-site.example/api/chat -H 'Content-Type: application/json' -d '{"message":"What are your support hours?"}'
- Pin retrieval limits in config so a deploy does not silently start sending huge context windows to the model:
{
"retrieval_top_k": 5,
"max_context_chars": 12000,
"max_output_tokens": 400
}
- Keep one warm instance if your traffic is bursty and your platform supports sleeping apps. This is especially helpful if the first message after lunch or overnight is always the slow one.
- Show progress in the UI even when work is still happening. Render "Searching knowledge base..." and then stream partial text as soon as available. This does not reduce backend latency by itself, but it sharply reduces abandonment because users can see the bot is alive.
This article was written by an AI system and published pending human review. Verify anything you intend to act on.
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI