By default, when you make a request to the OpenAI API, we generate the modelâs entire output before sending it back in a single HTTP response. When generating long outputs, waiting for a response can take time. Streaming responses lets you start printing or processing the beginning of the modelâs output while it continues generating the full response.
This guide focuses on HTTP streaming (stream=true) over server-sent events (SSE). For persistent WebSocket transport with incremental inputs via previous_response_id, see the Responses API WebSocket mode.
To start streaming responses, set stream=True in your request to the Responses endpoint:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import { OpenAI } from "openai";
const client = new OpenAI();
const stream = await client.responses.create({
model: "gpt-5.6",
input: [
{
role: "user",
content: "Say 'double bubble bath' ten times fast.",
},
],
stream: true,
});
for await (const event of stream) {
console.log(event);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17from openai import OpenAI
client = OpenAI()
stream = client.responses.create(
model="gpt-5.6",
input=[
{
"role": "user",
"content": "Say 'double bubble bath' ten times fast.",
},
],
stream=True,
)
for event in stream:
print(event)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
stream := client.Responses.NewStreaming(context.Background(), responses.ResponseNewParams{
Model: "gpt-5.6",
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Say 'double bubble bath' ten times fast.")},
})
for stream.Next() {
fmt.Println(stream.Current().Type)
}
if err := stream.Err(); err != nil {
panic(err)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.http.StreamResponse;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseStreamEvent;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-5.6")
.input("Say 'double bubble bath' ten times fast.")
.build();
try (StreamResponse<ResponseStreamEvent> stream = client.responses().createStreaming(params)) {
stream.stream().forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
var responses = client.CreateResponseStreamingAsync(
"gpt-5.6",
"Say 'double bubble bath' ten times fast."
);
await foreach (StreamingResponseUpdate response in responses)
{
if (response is StreamingResponseOutputTextDeltaUpdate delta)
{
Console.Write(delta.Delta);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17require "openai"
openai = OpenAI::Client.new
stream = openai.responses.stream(
model: "gpt-5.6",
input: [
{
role: "user",
content: "Say 'double bubble bath' ten times fast."
}
]
)
stream.each do |event|
puts(event)
end
The Responses API uses semantic events for streaming. Each event is typed with a predefined schema, so you can listen for events you care about.
For a full list of event types, see the API reference for streaming. Here are a few examples:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26StreamingEvent = (
ResponseCreatedEvent
| ResponseInProgressEvent
| ResponseFailedEvent
| ResponseCompletedEvent
| ResponseOutputItemAdded
| ResponseOutputItemDone
| ResponseContentPartAdded
| ResponseContentPartDone
| ResponseOutputTextDelta
| ResponseOutputTextAnnotationAdded
| ResponseTextDone
| ResponseRefusalDelta
| ResponseRefusalDone
| ResponseFunctionCallArgumentsDelta
| ResponseFunctionCallArgumentsDone
| ResponseFileSearchCallInProgress
| ResponseFileSearchCallSearching
| ResponseFileSearchCallCompleted
| ResponseCodeInterpreterInProgress
| ResponseCodeInterpreterCallCodeDelta
| ResponseCodeInterpreterCallCodeDone
| ResponseCodeInterpreterCallInterpreting
| ResponseCodeInterpreterCallCompleted
| Error
)
1type StreamingEvent = responses.ResponseStreamEventUnion
1
2
3
4
5
6
7
8
9
10
11
12import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.http.StreamResponse;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseStreamEvent;
ResponseCreateParams params =
ResponseCreateParams.builder().model("gpt-5.5").input("Say hello.").build();
try (StreamResponse<ResponseStreamEvent> stream = client.responses().createStreaming(params)) {
stream.stream().forEach(System.out::println);
}
1
2
3
4
5require "openai"
client = OpenAI::Client.new
stream = client.responses.stream(model: "gpt-5.5", input: "Say hello.")
stream.each { |event| puts(event) }
Streaming Chat Completions is fairly straightforward. However, we recommend using the Responses API for streaming, as we designed it with streaming in mind. The Responses API uses semantic events for streaming and is type-safe.
To stream completions, set stream=True when calling the Chat Completions or legacy Completions endpoints. This returns an object that streams back the response as data-only server-sent events.
The response is sent back incrementally in chunks with an event stream. You can iterate over the event stream with a for loop, like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import OpenAI from "openai";
const openai = new OpenAI();
const stream = await openai.chat.completions.create({
model: "gpt-5.6",
messages: [
{
role: "user",
content: "Say 'double bubble bath' ten times fast.",
},
],
stream: true,
});
for await (const chunk of stream) {
console.log(chunk);
console.log(chunk.choices[0].delta);
console.log("****************");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19from openai import OpenAI
client = OpenAI()
stream = client.chat.completions.create(
model="gpt-5.6",
messages=[
{
"role": "user",
"content": "Say 'double bubble bath' ten times fast.",
},
],
stream=True,
)
for chunk in stream:
print(chunk)
print(chunk.choices[0].delta)
print("****************")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
stream := client.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-5.6",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.UserMessage("Say 'double bubble bath' ten times fast."),
},
})
for stream.Next() {
fmt.Println(stream.Current())
}
if err := stream.Err(); err != nil {
panic(err)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.http.StreamResponse;
import com.openai.models.chat.completions.ChatCompletionChunk;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-5.6")
.addUserMessage("Say hello.")
.build();
try (StreamResponse<ChatCompletionChunk> stream =
client.chat().completions().createStreaming(params)) {
stream.stream().forEach(System.out::println);
}
1
2
3
4
5require "openai"
client = OpenAI::Client.new
stream = client.chat.completions.stream(model: "gpt-5.6", messages: [{role: :user, content: "Say hello."}])
stream.each { |event| puts(event) }
If youâre using our SDK, every event is a typed instance. You can also identity individual events using the type property of the event.
Some key lifecycle events are emitted only once, while others are emitted multiple times as the response is generated. Common events to listen for when streaming text are:
- `response.created`
- `response.output_text.delta`
- `response.completed`
- `error`
For a full list of events you can listen for, see the API reference for streaming.
When you stream a chat completion, the responses has a delta field rather than a message field. The delta field can hold a role token, content token, or nothing.
{ role: 'assistant', content: '', refusal: null }
****************
{ content: 'Why' }
****************
{ content: " don't" }
****************
{ content: ' scientists' }
****************
{ content: ' trust' }
****************
{ content: ' atoms' }
****************
{ content: '?\n\n' }
****************
{ content: 'Because' }
****************
{ content: ' they' }
****************
{ content: ' make' }
****************
{ content: ' up' }
****************
{ content: ' everything' }
****************
{ content: '!' }
****************
{}
****************
To stream only the text response of your chat completion, your code would like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import OpenAI from "openai";
const client = new OpenAI();
const stream = await client.chat.completions.create({
model: "gpt-5.6",
messages: [
{
role: "user",
content: "Say 'double bubble bath' ten times fast.",
},
],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || "");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18from openai import OpenAI
client = OpenAI()
stream = client.chat.completions.create(
model="gpt-5.6",
messages=[
{
"role": "user",
"content": "Say 'double bubble bath' ten times fast.",
},
],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end="")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
stream := client.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-5.6",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.UserMessage("Say 'double bubble bath' ten times fast."),
},
})
for stream.Next() {
if len(stream.Current().Choices) > 0 {
fmt.Print(stream.Current().Choices[0].Delta.Content)
}
}
if err := stream.Err(); err != nil {
panic(err)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.http.StreamResponse;
import com.openai.models.chat.completions.ChatCompletionChunk;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-5.6")
.addUserMessage("Say 'double bubble bath' ten times fast.")
.build();
try (StreamResponse<ChatCompletionChunk> stream =
client.chat().completions().createStreaming(params)) {
stream.stream()
.flatMap(chunk -> chunk.choices().stream())
.flatMap(choice -> choice.delta().content().stream())
.forEach(System.out::print);
}
1
2
3
4
5
6
7
8
9
10
11require "openai"
client = OpenAI::Client.new
stream = client.chat.completions.stream(
model: "gpt-5.6",
messages: [{
role: :user,
content: "Say 'double bubble bath' ten times fast."
}]
)
stream.text.each { |text| print(text) }
For more advanced use cases, like streaming tool calls, check out the following dedicated guides:
Note that streaming the modelâs output in a production application makes it more difficult to moderate the content of the completions, as partial completions may be more difficult to evaluate. This may have implications for approved usage.
If you request moderation scores with a generation request, the scores arrive after the full generated output is available. They arenât included with partial output deltas.