---
title: "Make streamed answers work with a screen · Agent Wranglers"
url: https://agentwranglers.se/playbook/ai-features/latency-cost-and-fallbacks/accessible-streaming
updated: 2026-10-21
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Make streamed answers work with a screen reader

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers). Updated 2026-10-21.

For AI agents: [llms.txt](https://agentwranglers.se/llms.txt) is a short guide that sends you to the rules your problem needs, and [rules.json](https://agentwranglers.se/playbook/ai-features/rules.json) holds every rule of this playbook as JSON.

- Level: Required
- Chapter: [Latency, cost and fallbacks](https://agentwranglers.se/playbook/ai-features/latency-cost-and-fallbacks)
- Rule: Announce a streamed answer to screen reader users once, when it ends, not piece by piece. Give every streaming answer a stop button that also cancels the model call.
- Risk: A law broken
- Applies when: The project it uses AI models.
- How: Stream the text into a container that is not a live region, marked `aria-busy="true"` while text arrives. A live region around the stream makes screen readers read each fragment. When the answer ends, remove `aria-busy` and write a short note, such as "Answer ready", into the page's status region. That follows [announce changes without moving focus](https://agentwranglers.se/playbook/website/accessibility/status-messages). Show a stop button while text arrives, because WCAG asks for a way to stop content that updates on its own. On stop, abort the request, and let the server cancel its provider call. Keep the partial text and mark it as stopped, as [handle refusals and cut-off answers](https://agentwranglers.se/playbook/ai-features/guardrails-and-human-review/refusals-and-truncation) does for cut-off answers.
- Check: A browser test plays a fake stream of 200 chunks. The answer container has no `aria-live` or live role, and the status region changes once. Pressing stop ends the stream within 1 second, and the fake provider records the cancelled call.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### TypeScript example

```ts
export async function showStreamedAnswer(question: string, answer: HTMLElement, status: HTMLElement, stop: HTMLButtonElement) {
  const controller = new AbortController();
  stop.hidden = false;
  stop.onclick = () => controller.abort();
  answer.setAttribute('aria-busy', 'true');
  try {
    for await (const text of readAnswerStream(question, controller.signal)) answer.append(text);
    status.textContent = 'Answer ready';
  } catch (error) {
    if (!controller.signal.aborted) throw error;
    status.textContent = 'Answer stopped';
  } finally {
    answer.removeAttribute('aria-busy');
    stop.hidden = true;
  }
}
```

### Python example

```python
@app.get("/api/assistant")
async def assistant(request: Request, q: str, user: User = Depends(current_user)):
    async def events():
        async with ai.open_stream(prompt_id="help-chat", variables={"question": q}, user_id=user.id) as stream:
            async for text in stream:
                if await request.is_disconnected():
                    await stream.cancel()
                    log.info("ai.stream_cancelled", user_id=user.id)
                    return
                yield f"data: {json.dumps({'text': text})}\n\n"
    return StreamingResponse(events(), media_type="text/event-stream", headers={"Cache-Control": "no-store"})
```

## Sources

- [WCAG 2.2 criterion 4.1.3 Status Messages](https://www.w3.org/TR/WCAG22/#status-messages)
- [WCAG 2.2 criterion 2.2.2 Pause, Stop, Hide](https://www.w3.org/TR/WCAG22/#pause-stop-hide)
- [WAI-ARIA 1.2 on aria-busy](https://www.w3.org/TR/wai-aria-1.2/#aria-busy)

## Related rules

- [Announce changes without moving focus](https://agentwranglers.se/playbook/website/accessibility/status-messages) in Website
- [Handle refusals and cut-off answers](https://agentwranglers.se/playbook/ai-features/guardrails-and-human-review/refusals-and-truncation) in AI features

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/ai-features/latency-cost-and-fallbacks/accessible-streaming">Agent Wranglers AI features playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Send work nobody waits for as a batch](https://agentwranglers.se/playbook/ai-features/latency-cost-and-fallbacks/batch-offline-work)
- [Latency, cost and fallbacks](https://agentwranglers.se/playbook/ai-features/latency-cost-and-fallbacks)
