streaming
build-with-claude/streaming
History
build-with-claude/streaming First recorded · 1531 lines, first recorded
## Streaming with SDKs ## Get the final message without handling events ## Event types ### Ping events ### Error events ### Other events ## Content block delta types ### Text delta ### Input JSON delta ### Thinking delta ## Full HTTP stream response ### Basic streaming request ### Streaming request with tool use ### Streaming request with thinking ### Streaming request with web search tool use ## Error recovery ### Claude 4.5 and earlier ### Claude 4.6 and later ### Error recovery best practices ## Next steps
The first capture of this source. The page was already there, and this is what it said.
---
title: Streaming messages
url: https://platform.claude.com/docs/en/build-with-claude/streaming
description: Stream Messages API responses incrementally with server-sent events, including text, tool use, and extended thinking deltas.
---
When creating a Message, you can set `"stream": true` to incrementally stream the response using [server-sent events](https://developer.mozilla.org/en-US/Web/API/Server-sent%5Fevents/Using%5Fserver-sent%5Fevents) (SSE).
## Streaming with SDKs
The [Python SDK](https://github.com/anthropics/anthropic-sdk-python) and [TypeScript SDK](https://github.com/anthropics/anthropic-sdk-typescript) offer multiple ways of streaming. The [PHP SDK](https://github.com/anthropics/anthropic-sdk-php) provides streaming through `createStream()`. The Python SDK allows both sync and async streams. See the documentation in each SDK for details.
<CodeGroup>
```bash CLI
ant messages create --stream --format jsonl \
--model claude-opus-5 \
--max-tokens 1024 \
--message '{role: user, content: "Hello"}' \
| jq -rj 'select(.delta.type? == "text_delta") | .delta.text'
```
```python Python
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
model="claude-opus-5",
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
```
```typescript TypeScript
const client = new Anthropic();
await client.messages
.stream({
messages: [{ role: "user", content: "Hello" }],
model: "claude-opus-5",
max_tokens: 1024
})
.on("text", (text) => {
console.log(text);
});
```
```csharp C#
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus5,
MaxTokens = 1024,
Messages = [new() { Role = Role.User, Content = "Hello" }]
};
await foreach (var msg in client.Messages.CreateStreaming(parameters))
{
Console.Write(msg);
}
```
```go Go
client := anthropic.NewClient()
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5,
MaxTokens: 1024,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Hello")),
},
})
for stream.Next() {
event := stream.Current()
switch eventVariant := event.AsAny().(type) {
case anthropic.ContentBlockDeltaEvent:
switch deltaVariant := eventVariant.Delta.AsAny().(type) {
case anthropic.TextDelta:
fmt.Print(deltaVariant.Text)
}
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
```
```java Java
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5)
.maxTokens(1024L)
.addUserMessage("Hello")
.build();
try (var streamResponse = client.messages().createStreaming(params)) {
streamResponse.stream().forEach(event -> {
event.contentBlockDelta().ifPresent(deltaEvent ->
deltaEvent.delta().text().ifPresent(td ->
System.out.print(td.text())
)
);
});
}
```
```php PHP
$client = new Client();
$stream = $client->messages->createStream(
maxTokens: 1024,
messages: [
['role' => 'user', 'content' => 'Hello']
],
model: 'claude-opus-5',
);
foreach ($stream as $message) {
echo $message;
}
```
```ruby Ruby
client = Anthropic::Client.new
stream = client.messages.stream(
model: "claude-opus-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }]
)
stream.text.each { |text| print(text) }
```
</CodeGroup>
## Get the final message without handling events
If you don't need to process text as it arrives, the SDKs provide a way to use streaming internally while returning the complete `Message` object, identical to what `.create()` returns. This is especially useful for requests with large `max_tokens` values, where the SDKs require streaming to avoid HTTP timeouts.
<CodeGroup>
```bash CLI
# The ant CLI's --stream flag emits one event per line and does not
# accumulate into a final Message. For long generations, stream the
# raw events:
ant messages create --stream --format jsonl <<'YAML'
model: claude-opus-5
max_tokens: 128000
messages:
- role: user
content: Write a detailed analysis...
YAML
```
```python Python
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=128000,
messages=[{"role": "user", "content": "Write a detailed analysis..."}],
model="claude-opus-5",
) as stream:
message = stream.get_final_message()
for block in message.content:
if block.type == "text":
print(block.text)
```
```typescript TypeScript
const client = new Anthropic();
const stream = client.messages.stream({
max_tokens: 128000,
messages: [{ role: "user", content: "Write a detailed analysis..." }],
model: "claude-opus-5"
});
const message = await stream.finalMessage();
const textBlock = message.content.find((block) => block.type === "text");
if (textBlock && textBlock.type === "text") {
console.log(textBlock.text);
}
```
```csharp C#
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus5,
MaxTokens = 128000,
Messages = [new() { Role = Role.User, Content = "Write a detailed analysis..." }]
};
var fullText = "";
await foreach (var msg in client.Messages.CreateStreaming(parameters))
{
fullText += msg;
}
Console.WriteLine(fullText);
```
```go Go
client := anthropic.NewClient()
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5,
MaxTokens: 128000,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Write a detailed analysis...")),
},
})
message := anthropic.Message{}
for stream.Next() {
event := stream.Current()
if err := message.Accumulate(event); err != nil {
log.Fatal(err)
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
for _, block := range message.Content {
if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
fmt.Println(textBlock.Text)
}
}
```
```java Java
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5)
.maxTokens(128000L)
.addUserMessage("Write a detailed analysis...")
.build();
MessageAccumulator accumulator = MessageAccumulator.create();
try (var streamResponse = client.messages().createStreaming(params)) {
streamResponse.stream().forEach(accumulator::accumulate);
}
Message message = accumulator.message();
message.content().stream()
.flatMap(block -> block.text().stream())
.forEach(textBlock -> System.out.println(textBlock.text()));
```
```php PHP
$client = new Client();
$stream = $client->messages->createStream(
maxTokens: 128000,
messages: [
['role' => 'user', 'content' => 'Write a detailed analysis...']
],
model: 'claude-opus-5',
);
$fullText = '';
foreach ($stream as $event) {
if ($event->type === 'content_block_delta' && $event->delta->type === 'text_delta') {
$fullText .= $event->delta->text;
}
}
echo $fullText;
```
```ruby Ruby
client = Anthropic::Client.new
message = client.messages.stream(
model: "claude-opus-5",
max_tokens: 128000,
messages: [{ role: "user", content: "Write a detailed analysis..." }]
).accumulated_message
message.content.each do |block|
puts block.text if block.type == :text
end
```
</CodeGroup>
The `.stream()` call keeps the HTTP connection alive with server-sent events, then `.get_final_message()` (Python) or `.finalMessage()` (TypeScript) accumulates all events and returns the complete `Message` object. In Go, you call `message.Accumulate(event)` inside the stream loop to build the same complete `Message`. In Java, use `MessageAccumulator.create()` and call `accumulator.accumulate(event)` on each event. In C#, await the stream's `.Aggregate()` extension method to get the complete `Message`, or pass a `MessageContentAggregator` to `.CollectAsync()` to aggregate while handling events. In Ruby, call `.accumulated_message` on the stream. In the PHP SDK, you iterate over stream events manually to accumulate the response.
## Event types
Each server-sent event includes a named event type and associated JSON data. Each event uses an SSE event name (for example, `event: message_stop`), and includes the matching event `type` in its data.
Each stream uses the following event flow:
1. `message_start`: contains a `Message` object with empty `content`.
Cut at 300 lines.