Learn how to stream ChatGPT responses in web applications using the OpenAI API. This guide covers setup, implementation in JavaScript and Python, event handling, and troubleshooting for real-time text generation.
This guide covers how to stream ChatGPT responses in web applications using the OpenAI API. It is for developers who want to build real-time, interactive chat interfaces that display model output as it is generated, rather than waiting for the full response. You will learn the concepts behind streaming, how to set up your environment, implement streaming in JavaScript (Node.js) and Python, handle events, and troubleshoot common issues.
Before you begin, you need the following:
.zshrc file or another text file on your computer.Streaming is a technique where the server sends the response data in chunks as they become available, rather than waiting for the entire response to be generated. For ChatGPT, this means you can start displaying the model's output to the user almost immediately, creating a more responsive and engaging experience.
The OpenAI API supports streaming for the Responses API and the Chat Completions API. When you make a streaming request, the API returns a stream of events. Each event contains a portion of the model's output. Your application listens to this stream and processes each event as it arrives.
This is the recommended approach for security. The OpenAI SDKs automatically read the API key from the OPENAI_API_KEY environment variable.
macOS / Linux
Open your terminal and run:
export OPENAI_API_KEY="your_api_key_here"
To make this permanent, add the line to your shell profile file (e.g., ~/.zshrc, ~/.bashrc, or ~/.bash_profile).
Windows (PowerShell)
setx OPENAI_API_KEY "your_api_key_here"
JavaScript (Node.js)
Create a new project directory and initialize it:
mkdir streaming-chatgpt
cd streaming-chatgpt
npm init -y
Install the OpenAI SDK:
npm install openai
Python
Create a new project directory and set up a virtual environment (recommended):
mkdir streaming-chatgpt
cd streaming-chatgpt
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
Install the OpenAI SDK:
pip install openai

The official OpenAI SDK for JavaScript and TypeScript supports streaming natively. When you set the stream parameter to true in the request, the SDK returns a stream object that you can iterate over.
Create a file named stream.js and add the following code:
import OpenAI from "openai";
const client = new OpenAI();
async function main() {
const stream = await client.responses.create({
model: "gpt-5.6",
input: "Write a one-sentence bedtime story about a unicorn.",
stream: true,
});
for await (const event of stream) {
// Process each event
console.log(event);
}
}
main();
Explanation:
import OpenAI from "openai"; imports the OpenAI SDK.const client = new OpenAI(); creates a new client instance. It automatically reads the API key from the OPENAI_API_KEY environment variable.client.responses.create(...) makes a request to the Responses API.model: "gpt-5.6" specifies the model to use. The official documentation uses gpt-5.6 in its examples.input: "..." is the user's prompt.stream: true tells the API to return a stream of events instead of a single response object.for await (const event of stream) iterates over the stream asynchronously. Each event is a chunk of data from the API.Run the script:
node stream.js
You will see a series of events printed to the console. Each event has a type property that indicates what kind of data it contains.
The stream emits different types of events. The most important ones for text generation are:
response.output_text.delta: Contains a portion of the model's text output.response.output_text.done: Indicates that a particular text output is complete.response.completed: Indicates that the entire response is complete.Here is an example that extracts and prints only the text deltas:
import OpenAI from "openai";
const client = new OpenAI();
async function main() {
const stream = await client.responses.create({
model: "gpt-5.6",
input: "Write a one-sentence bedtime story about a unicorn.",
stream: true,
});
let fullText = "";
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
fullText += event.delta;
process.stdout.write(event.delta); // Print as it arrives
}
}
console.log("\n\nFull response:", fullText);
}
main();
Explanation:
event.type === "response.output_text.delta" checks if the event is a text delta.event.delta contains the new text chunk.process.stdout.write(event.delta) prints the text to the console without adding a newline, so the text appears character by character.fullText variable accumulates all deltas to get the complete response.You can also use the instructions parameter to guide the model's behavior. According to the official documentation, the instructions parameter gives the model high-level instructions on how it should behave while generating a response, including tone, goals, and examples of correct responses. Any instructions provided this way will take priority over a prompt in the input parameter.
import OpenAI from "openai";
const client = new OpenAI();
async function main() {
const stream = await client.responses.create({
model: "gpt-5.6",
instructions: "Talk like a pirate.",
input: "Are semicolons optional in JavaScript?",
stream: true,
});
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
process.stdout.write(event.delta);
}
}
}
main();
The official documentation explains that you can use message roles (developer, user, assistant) in the input array. The developer role is for instructions provided by the application developer, and it is prioritized ahead of user messages. This is equivalent to using the instructions parameter.
import OpenAI from "openai";
const client = new OpenAI();
async function main() {
const stream = await client.responses.create({
model: "gpt-5.6",
input: [
{
role: "developer",
content: "Talk like a pirate.",
},
{
role: "user",
content: "Are semicolons optional in JavaScript?",
},
],
stream: true,
});
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
process.stdout.write(event.delta);
}
}
}
main();
Explanation:
input array contains multiple messages.role: "developer" and contains the system instructions.role: "user" and contains the user's question.instructions parameter only applies to the current response generation request. If you are managing conversation state with the previous_response_id parameter, the instructions used on previous turns will not be present in the context.The official OpenAI SDK for Python also supports streaming. Create a file named stream.py and add the following code:
from openai import OpenAI
client = OpenAI()
stream = client.responses.create(
model="gpt-5.6",
input="Write a one-sentence bedtime story about a unicorn.",
stream=True,
)
for event in stream:
# Process each event
print(event)
Explanation:
from openai import OpenAI imports the SDK.client = OpenAI() creates a new client instance. It reads the API key from the OPENAI_API_KEY environment variable.client.responses.create(...) makes a request.stream=True enables streaming.for event in stream: iterates over the stream. Each event is a chunk of data.Run the script:
python stream.py
Similar to the JavaScript SDK, the Python SDK emits events. Here is an example that extracts and prints only the text deltas:
from openai import OpenAI
client = OpenAI()
stream = client.responses.create(
model="gpt-5.6",
input="Write a one-sentence bedtime story about a unicorn.",
stream=True,
)
full_text = ""
for event in stream:
if event.type == "response.output_text.delta":
full_text += event.delta
print(event.delta, end="", flush=True)
print("\n\nFull response:", full_text)
Explanation:
event.type == "response.output_text.delta" checks if the event is a text delta.event.delta contains the new text chunk.print(event.delta, end="", flush=True) prints the text without a newline and flushes the output buffer so it appears immediately.full_text variable accumulates all deltas.from openai import OpenAI
client = OpenAI()
stream = client.responses.create(
model="gpt-5.6",
instructions="Talk like a pirate.",
input="Are semicolons optional in JavaScript?",
stream=True,
)
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
from openai import OpenAI
client = OpenAI()
stream = client.responses.create(
model="gpt-5.6",
input=[
{
"role": "developer",
"content": "Talk like a pirate."
},
{
"role": "user",
"content": "Are semicolons optional in JavaScript?"
}
],
stream=True,
)
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
reasoning ParameterThe official documentation shows that you can use the reasoning parameter with models that support it. For example, with gpt-5.6, you can set reasoning: { effort: "low" } to control how much reasoning the model does before generating its response. This parameter can be used in both streaming and non-streaming requests.
import OpenAI from "openai";
const client = new OpenAI();
async function main() {
const stream = await client.responses.create({
model: "gpt-5.6",
reasoning: { effort: "low" },
instructions: "Talk like a pirate.",
input: "Are semicolons optional in JavaScript?",
stream: true,
});
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
process.stdout.write(event.delta);
}
}
}
main();
output_text PropertyAccording to the official documentation, some of the official SDKs include an output_text property on model responses for convenience, which aggregates all text outputs from the model into a single string. This may be useful as a shortcut to access text output from the model. However, in streaming mode, you should not rely on this property until the stream is complete. The documentation also warns that the output array often has more than one item in it. It can contain tool calls, data about reasoning tokens generated by reasoning models, and other items. It is not safe to assume that the model's text output is present at output[0].content[0].text.
The official documentation provides examples of using built-in tools like web_search, file_search, and code_interpreter with the Responses API. These tools can also be used with streaming requests. When a tool is called, the stream will emit events related to the tool call before the text output.
Here is an example of using the web_search tool with streaming in JavaScript:
import OpenAI from "openai";
const client = new OpenAI();
async function main() {
const stream = await client.responses.create({
model: "gpt-5.6",
tools: [{ type: "web_search" }],
input: "What was a positive news story from today?",
stream: true,
});
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
process.stdout.write(event.delta);
} else if (event.type === "response.web_search_call.in_progress") {
console.log("\n[Searching the web...]");
}
}
}
main();
The official documentation mentions the previous_response_id parameter for managing multi-turn conversations. When using streaming, you can pass the ID of the previous response to continue the conversation. The instructions parameter only applies to the current response generation request, so you need to include it in each request if you want consistent behavior across turns.

If you are not receiving any events from the stream, check the following:
gpt-5.6) is available in your region and for your account tier. The official documentation uses gpt-5.6 in its examples.stream: true (or stream=True in Python) in your request. Without this, the API will return a single response object instead of a stream.If the text you receive is incomplete or garbled, consider the following:
response.output_text.delta, such as response.output_text.done or response.completed. Ignoring these may cause you to miss the end of the stream.flush=True in your print statement to ensure text is displayed immediately. In Node.js, process.stdout.write does not add a newline, so the text appears as it arrives.If you encounter rate limit errors (HTTP 429) or other API errors, the official documentation recommends:
import OpenAI from "openai";
const client = new OpenAI();
async function main() {
try {
const stream = await client.responses.create({
model: "gpt-5.6",
input: "Write a one-sentence bedtime story about a unicorn.",
stream: true,
});
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
process.stdout.write(event.delta);
}
}
} catch (error) {
console.error("An error occurred:", error);
}
}
main();
Community members on forums and GitHub have reported the following issues and solutions:
response.completed event is received.response.completed event or when the stream ends.Now that you have implemented basic streaming, you can explore more advanced topics:
instructions parameter. Experiment with different prompts to get the best results for your use case.gpt-5.5-2026-04-23) to ensure consistent behavior. This is especially important when using streaming, as different model versions may produce different streaming behavior.Learn how to use the OpenAI Batch API to cut costs by 50% for bulk processing tasks. Covers setup, request formatting, job creation, monitoring, error handling, and troubleshooting.
Learn how to write prompts for ChatGPT that reliably generate working code. Covers core concepts, setup, and specific patterns for different coding tasks.
Learn how to use the OpenAI Vision API to analyze images with GPT models. Covers setup, sending images via URL, Base64, or file ID, controlling detail levels, cost calculation, and troubleshooting.
Learn how to use OpenAI's text embedding models for semantic search, clustering, recommendations, and classification. This guide covers concepts, setup, API usage, dimension reduction, and practical tips from official documentation and community experience.
Learn how to handle OpenAI API rate limits (429) and quota errors. Covers error types, exponential backoff, Python library exceptions, and troubleshooting steps for production applications.
Learn how to use OpenAI Structured Outputs to guarantee JSON schema conformance from GPT models. Covers function tool definitions, strict mode, tool call handling, and best practices for both Chat Completions and Responses APIs.
Workflows from the Neura Market marketplace related to this ChatGPT resource