The states your AI feature forgets: loading, error, empty
Most AI features get built for the demo: the prompt returns, the text appears, everyone claps. Then it ships, and real users hit the three states nobody designed: the wait, the failure, and the blank first screen. Those states decide whether people trust the feature enough to use it twice.
This is a practical guide to the non-happy-path UX of an AI feature inside a SaaS product: how long to wait before showing something, which loading pattern to pick, what an honest error looks like, and how to make an empty state teach instead of stall.
Start with a latency budget, not a spinner
You cannot design the wait until you know how long it is. An LLM call has two parts users feel: the time to the first token (often 500ms to 2s while the model reads your prompt and pulls context) and the time to finish streaming the rest. Measure both at p50 and p95 before you choose a pattern. We wrote a full method for this in where the milliseconds go in your RAG pipeline, and covered time-to-first-token specifically in the time-to-first-token guide.
Once you have the numbers, the pattern falls out of the budget.
Under one second
Do nothing. A loading indicator that flashes for 300ms reads as jank, not progress. Let the result land.
One to ten seconds
Show structure, not a spinner. A skeleton screen that mirrors the shape of the answer makes the wait feel roughly 30 to 40 percent shorter than a blank panel with a spinner, because it sets an expectation of what is coming. If the output is text and you can stream it, stream instead.
Over ten seconds
Show the steps. For a long agent run or a multi-document analysis, a status line that updates ("Reading 12 sources", then "Drafting summary") turns dead time into visible progress. Never leave the screen static for more than a couple of seconds without a text change.
Streaming is the highest-leverage change you can make
If the feature generates text, stream it. In user testing, streaming cuts perceived wait time by 55 to 70 percent even when the total generation time is identical, because the user starts reading before the model finishes writing. The mechanics are simple: open a Server-Sent Events connection, append each token chunk to the DOM as it arrives, and show a blinking cursor while more is coming. We covered the implementation and its failure modes in streaming LLM responses as a SaaS feature.
Two things teams forget once they add streaming. First, a streamed error is worse than a blocked one, because half an answer is already on screen when the connection drops; you have to catch the mid-stream failure and swap to an error state, not leave a truncated sentence hanging. Second, streaming interacts with trust: if you show citations, decide whether they appear as they stream or all at once at the end, so the answer never looks unsupported mid-flight. That trade-off is covered in citations and confidence in AI feature UX.
Design the error state before you ship, not after
AI features fail in ways ordinary features do not: the provider returns a 429, the model times out, the output fails a schema check, or the answer is empty because retrieval found nothing. Each needs a different message, and none of them should read "Something went wrong".
Write the copy for each failure mode up front. A rate-limit error should say the system is busy and offer a retry, not blame the user; the runtime handling behind it is in handling 429s in production. A timeout should offer to try again or fall back to a lighter model rather than dead-ending, which is the pattern in what to do when the model fails. A no-results answer should tell the user what it looked at and suggest a narrower query. The rule of thumb: an error state should always give the user one obvious next action.
The empty state is your first-run tutorial
The first time a user opens your AI feature, there is no input and no output. That blank screen is one of the most-viewed states of the whole feature, and most teams ship it empty. Use it to teach: show two or three example prompts the user can click to run, phrased as real jobs ("Summarize this contract", "Find customers at churn risk"). A good empty state cuts the number of users who type one vague query, get a mediocre answer, and never come back.
The same applies to the empty result. When the model genuinely has nothing to return, say so plainly and explain why, rather than fabricating a filler answer to avoid the blank. An honest empty state builds more trust than a confident wrong one.
Give users a way to recover from a bad answer
LLM output is non-deterministic, so a share of answers will be off even when everything works. Users tolerate that if you give them controls: a regenerate button to try again, an edit affordance to fix the output in place, and, where the feature takes an action, an undo. These are cheap to build and they change how the feature feels, from a black box that is sometimes wrong to a tool the user is in control of.
Pair the recovery controls with a lightweight feedback signal, a thumbs up or down. It gives the user an outlet and gives you labeled failures, which feed straight into your eval set as described in turning user feedback into an eval dataset.
Instrument the states you just designed
Every state above is a metric. Track time-to-first-token and full-completion latency at p95, the rate of each error type, how often users hit regenerate, and the thumbs-down rate. Without that you are guessing which state is hurting adoption. Wiring these into a dashboard is covered in monitoring an LLM feature in production.
Frequently asked questions
Should I use a spinner or a skeleton screen for an AI feature?
Use a skeleton when you know the shape of the answer and the wait is one to ten seconds; it feels faster than a spinner. Use streaming whenever the output is text. Reserve spinners for short, shapeless waits of a second or two.
How long can an AI feature take before users abandon it?
There is no single number, but perceived wait matters more than actual wait. With streaming and a clear status line, users tolerate ten seconds or more. With a blank screen, patience runs out in two to three. Budget your latency first, then design the wait to match it.
What should an AI feature show when it has no answer?
Say so plainly, explain what it searched, and suggest a narrower or different query. Never fabricate a filler answer to avoid the blank; an honest empty state protects trust.
Do I need to design error states if the model rarely fails?
Yes. Providers return 429s and timeouts under load, and schema checks reject malformed output regularly at scale. Rare per request still means visible failures across thousands of users, and an unhandled one is the worst impression your feature can make.
Rather we just build it?
Book a free scoping call and we'll ship your production-safe AI feature this week.