Web search
For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending
.mdto the page URL.
Web search allows models to access up-to-date information from the internet and provide answers with sourced citations. To enable this, use the web search tool in the Responses API or, in some cases, Chat Completions.
Choose a search workflow based on the question you need to answer.
- For a quick lookup, ask a model to search for a specific fact and cite its source.
- For a question that needs several sources, use a reasoning model such as
gpt-6-astra. It can refine its searches as it reads results. Use background mode for a request that might take several minutes.
Choose an integration
| Use case | Recommended path | Notes |
|---|---|---|
| New web search integration | Responses API with web_search and gpt-6-astra |
Supports hosted web search controls such as filters, sources, live-access control, and longer research runs |
| Existing Chat Completions search integration | Chat Completions with gpt-5-search-api |
Use this only when you need to preserve a Chat Completions integration |
| Multi-step research or long-running reporting | gpt-6-astra with high or xhigh reasoning |
Use background mode for reports that can take several minutes |
Using the Responses API, you can enable web search by configuring it in the tools array in an API request to generate content. Like any other tool, the model can choose to search the web or not based on the content of the input prompt.
For new Responses API integrations, use { "type": "web_search" }. The earlier web_search_preview tool remains available for legacy integrations, but it does not support newer controls such as filters, external_web_access, and return_token_budget.
Web search tool example
import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
tools: [{ type: "web_search" }],
input: "What was a positive news story from today?",
});
console.log(response.output_text);
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
tools=[{"type": "web_search"}],
input="What was a positive news story from today?",
)
print(response.output_text)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Tools: []responses.ToolUnionParam{
responses.ToolParamOfWebSearch(responses.WebSearchToolTypeWebSearch),
},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("What was a positive news story from today?")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.WebSearchTool;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("What was a positive news story from today?")
.addTool(WebSearchTool.builder().type(WebSearchTool.Type.WEB_SEARCH).build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
CreateResponseOptions options = new() { Model = "gpt-6-astra" };
options.Tools.Add(ResponseTool.CreateWebSearchTool());
options.InputItems.Add(
ResponseItem.CreateUserMessageItem("What was a positive news story from today?")
);
ResponseResult response = await client.CreateResponseAsync(options);
Console.WriteLine(response.GetOutputText());
require "openai"
openai = OpenAI::Client.new
response = openai.responses.create(
model: "gpt-6-astra",
tools: [{ type: "web_search" }],
input: "What was a positive news story from today?"
)
puts(response.output_text)
curl "https://api.openai.com/v1/responses" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"tools": [{"type": "web_search"}],
"input": "what was a positive news story from today?"
}'
openai responses create \
--model gpt-6-astra \
--raw-output \
--transform 'output.#(type=="message").content.0.text' <<'YAML'
tools:
- type: web_search
input: What was a positive news story from today?
YAML
Output and citations
Model responses that use the web search tool will include two parts:
- A
web_search_calloutput item with the ID of the search call, along with the action taken inweb_search_call.action. The action is one of:search, which represents a web search. It will usually (but not always) includes the searchquerieswhich were searched. Search actions incur a tool call cost (see pricing).open_page, which represents a page being opened. Supported in reasoning models.find_in_page, which represents searching within a page. Supported in reasoning models.
- A
messageoutput item containing:- The text result in
message.content[0].text - Annotations
message.content[0].annotationsfor the cited URLs
- The text result in
By default, the model's response will include inline citations for URLs found in the web search results. In addition to this, the url_citation annotation object will contain the URL, title and location of the cited source.
When your interface displays web results or information from them, you must show inline citations as prominent, clickable links.
[
{
"type": "web_search_call",
"id": "ws_67c9fa0502748190b7dd390736892e100be649c1a5ff9609",
"status": "completed",
"action": {
"type": "search",
"query": "latest news about AI"
}
},
{
"id": "msg_67c9fa077e288190af08fdffda2e34f20be649c1a5ff9609",
"type": "message",
"status": "completed",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "On March 6, 2025, several news...",
"annotations": [
{
"type": "url_citation",
"start_index": 2606,
"end_index": 2758,
"url": "https://...",
"title": "Title..."
}
]
}
]
}
]
Migrating from legacy web search
| If you use | Recommended path | Notes |
|---|---|---|
web_search_preview in Responses |
Migrate to web_search |
web_search supports newer controls such as filters, external_web_access, and return_token_budget |
gpt-4o-search-preview or gpt-4o-mini-search-preview |
Migrate to Responses web_search, or use gpt-5-search-api if you must stay on Chat Completions |
The preview search models are deprecated and shut down on 2026-07-23 |
| Chat Completions search integrations | Use gpt-5-search-api, or migrate to Responses web_search for more tool controls and optional search |
Chat Completions search models always search before responding; Responses search is a tool |
o4-mini in Responses |
Migrate to a supported reasoning model with web_search |
The model shut down on October 23, 2026 |
For integrations still using gpt-5, web search requires reasoning effort above minimal.
Search context size
search_context_size controls how much context from web search results is made available to the model before it generates a response. Use low for a lookup that needs only a few details, medium for a balanced default, and high when the answer may require more detail from search results. This setting does not set an exact token count or guarantee a specific number of sources or citations.
Set search context size
import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.responses.create({
model: "gpt-6-astra",
tools: [
{
type: "web_search",
search_context_size: "low",
},
],
input: "What movie won best picture in 2025?",
});
console.log(response.output_text);
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
tools=[
{
"type": "web_search",
"search_context_size": "low",
}
],
input="What movie won best picture in 2025?",
)
print(response.output_text)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolParamOfWebSearch(responses.WebSearchToolTypeWebSearch)
tool.OfWebSearch.SearchContextSize = responses.WebSearchToolSearchContextSizeLow
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("What movie won best picture in 2025?")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.WebSearchTool;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("What movie won best picture in 2025?")
.addTool(
WebSearchTool.builder()
.type(WebSearchTool.Type.WEB_SEARCH)
.searchContextSize(WebSearchTool.SearchContextSize.LOW)
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
CreateResponseOptions options = new() { Model = "gpt-6-astra" };
options.Tools.Add(
ResponseTool.CreateWebSearchTool(
searchContextSize: WebSearchToolContextSize.Low
)
);
options.InputItems.Add(
ResponseItem.CreateUserMessageItem("What movie won best picture in 2025?")
);
ResponseResult response = await client.CreateResponseAsync(options);
Console.WriteLine(response.GetOutputText());
require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "What movie won best picture in 2025?",
tools: [
{
type: :web_search,
search_context_size: :low
}
]
)
puts(response.output_text)
curl "https://api.openai.com/v1/responses" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"tools": [{
"type": "web_search",
"search_context_size": "low"
}],
"input": "What movie won best picture in 2025?"
}'
Run longer web research
If your research also uses private records, run public web search and private MCP lookups in separate requests.
return_token_budget controls how much web search result content the tool can return during a Responses API search run with GPT-5+ reasoning models. Keep the default for most requests. Set it to unlimited only for high-effort research or evaluation runs that need to inspect many pages and might otherwise stop at the standard returned-token cap.
Use unlimited selectively because it can increase latency and cost. For long-running multi-search tasks, use background mode (background: true) so the request can keep running asynchronously and you can retrieve the final response later.
| Value | Behavior |
|---|---|
default |
Uses the standard returned-token budget for web search results. This is the same behavior as omitting return_token_budget. |
unlimited |
Removes the default returned-token budget for the web search run. |
This parameter applies only to the hosted Responses API web_search tool with GPT-5+ reasoning web search. It does not change the search context window, and it does not apply to non-reasoning web search, legacy Search API paths, container web search, Chat Completions search models, or web_search_preview. Only default and unlimited are supported values; null, numbers, and other strings are rejected.
Run longer web searches
import OpenAI from "openai";
import { Agent, fetch } from "undici";
// Allow long research runs without automatic request retries.
const timeout = 15 * 60 * 1000;
const dispatcher = new Agent({
headersTimeout: timeout,
bodyTimeout: timeout,
});
const client = new OpenAI({
timeout,
maxRetries: 0,
fetch,
fetchOptions: { dispatcher },
});
try {
const stream = client.responses.stream({
model: "gpt-6-astra",
reasoning: { effort: "xhigh" },
tools: [
{
type: "web_search",
return_token_budget: "unlimited",
},
],
input: [
"Research the economic impact of semaglutide on global healthcare systems.",
"",
"Do:",
"- Include specific figures, trends, statistics, and measurable outcomes.",
"- Prioritize reliable, up-to-date sources: peer-reviewed research, health organizations (e.g., WHO, CDC), regulatory agencies, or pharmaceutical earnings reports.",
"- Include inline citations and return all source metadata.",
"",
"Be analytical, avoid generalities, and ensure that each section supports data-backed reasoning that could inform healthcare policy or financial modeling.",
].join("\n"),
});
const response = await stream.finalResponse();
if (response.status !== "completed") {
throw new Error(`Research response ended with status ${response.status}`);
}
console.log(response.output_text);
} finally {
await dispatcher.close();
}
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
reasoning={"effort": "xhigh"},
tools=[
{
"type": "web_search",
"return_token_budget": "unlimited",
}
],
input="""Research the economic impact of semaglutide on global healthcare systems.
Do:
- Include specific figures, trends, statistics, and measurable outcomes.
- Prioritize reliable, up-to-date sources: peer-reviewed research, health organizations (e.g., WHO, CDC), regulatory agencies, or pharmaceutical earnings reports.
- Include inline citations and return all source metadata.
Be analytical, avoid generalities, and ensure that each section supports data-backed reasoning that could inform healthcare policy or financial modeling.""",
)
print(response.output_text)
package main
import (
"context"
"fmt"
"strings"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
tool := responses.ToolParamOfWebSearch(responses.WebSearchToolTypeWebSearch)
tool.OfWebSearch.SetExtraFields(map[string]any{"return_token_budget": "unlimited"})
input := strings.Join([]string{
"Research the economic impact of semaglutide on global healthcare systems.",
"",
"Do:",
"- Include specific figures, trends, statistics, and measurable outcomes.",
"- Prioritize reliable, up-to-date sources: peer-reviewed research, health organizations, regulatory agencies, or pharmaceutical earnings reports.",
"- Include inline citations and return all source metadata.",
"",
"Be analytical, avoid generalities, and ensure that each section supports data-backed reasoning that could inform healthcare policy or financial modeling.",
}, "\n")
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Reasoning: shared.ReasoningParam{Effort: shared.ReasoningEffortXhigh},
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(input)},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.Reasoning;
import com.openai.models.ReasoningEffort;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.WebSearchTool;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Research the economic impact of semaglutide on global healthcare systems. Include current figures and citations.")
.reasoning(Reasoning.builder().effort(ReasoningEffort.XHIGH).build())
.addTool(
WebSearchTool.builder()
.type(WebSearchTool.Type.WEB_SEARCH)
.putAdditionalProperty("return_token_budget", JsonValue.from("unlimited"))
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Research the economic impact of semaglutide on global healthcare systems. Include current figures and citations.",
reasoning: { effort: :xhigh },
tools: [
{
type: :web_search,
return_token_budget: :unlimited
}
]
)
puts(response.output_text)
curl "https://api.openai.com/v1/responses" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"reasoning": { "effort": "xhigh" },
"tools": [
{
"type": "web_search",
"return_token_budget": "unlimited"
}
],
"input": "Research the economic impact of semaglutide on global healthcare systems.\n\nDo:\n- Include specific figures, trends, statistics, and measurable outcomes.\n- Prioritize reliable, up-to-date sources: peer-reviewed research, health organizations (e.g., WHO, CDC), regulatory agencies, or pharmaceutical earnings reports.\n- Include inline citations and return all source metadata.\n\nBe analytical, avoid generalities, and ensure that each section supports data-backed reasoning that could inform healthcare policy or financial modeling."
}'
Domain filtering
Domain filtering in web search lets you limit results to a specific set of domains. With the filters parameter you can configure up to 100 allowed_domains or up to 100 blocked_domains. When formatting domains, omit the HTTP or HTTPS prefix. For example, use openai.com instead of https://openai.com/. This approach also includes subdomains in the search. Note that domain filtering is only available in the Responses API with the web_search tool.
Sources
To view all URLs retrieved during a web search, use the sources field. Unlike inline citations, which show only the most relevant references, sources returns the complete list of URLs the model consulted when forming its response.
The number of sources is often greater than the number of citations. Real-time third-party feeds are also surfaced here and are labeled as oai-sports, oai-weather, or oai-finance. The sources field is available with both the web_search and web_search_preview tools.
List sources
import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
reasoning: { effort: "low" },
tools: [
{
type: "web_search",
filters: {
allowed_domains: [
"pubmed.ncbi.nlm.nih.gov",
"clinicaltrials.gov",
"www.who.int",
"www.cdc.gov",
"www.fda.gov",
],
blocked_domains: ["reddit.com", "quora.com", "wikipedia.org"],
},
},
],
tool_choice: "auto",
include: ["web_search_call.action.sources"],
input:
"Please perform a web search on how semaglutide is used in the treatment of diabetes.",
});
console.log(response.output_text);
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
reasoning={"effort": "low"},
tools=[
{
"type": "web_search",
"filters": {
"allowed_domains": [
"pubmed.ncbi.nlm.nih.gov",
"clinicaltrials.gov",
"www.who.int",
"www.cdc.gov",
"www.fda.gov",
],
"blocked_domains": [
"reddit.com",
"quora.com",
"wikipedia.org",
],
},
}
],
tool_choice="auto",
include=["web_search_call.action.sources"],
input="Please perform a web search on how semaglutide is used in the treatment of diabetes.",
)
print(response.output_text)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
tool := responses.ToolParamOfWebSearch(responses.WebSearchToolTypeWebSearch)
tool.OfWebSearch.Filters = responses.WebSearchToolFiltersParam{
AllowedDomains: []string{"pubmed.ncbi.nlm.nih.gov", "clinicaltrials.gov", "www.who.int", "www.cdc.gov", "www.fda.gov"},
}
tool.OfWebSearch.Filters.SetExtraFields(map[string]any{"blocked_domains": []string{"reddit.com", "quora.com", "wikipedia.org"}})
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Reasoning: shared.ReasoningParam{Effort: shared.ReasoningEffortLow},
Tools: []responses.ToolUnionParam{tool},
Include: []responses.ResponseIncludable{responses.ResponseIncludableWebSearchCallActionSources},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Please perform a web search on how semaglutide is used in the treatment of diabetes.")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.Reasoning;
import com.openai.models.ReasoningEffort;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseIncludable;
import com.openai.models.responses.WebSearchTool;
import java.util.List;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Search for how semaglutide is used in the treatment of diabetes.")
.reasoning(Reasoning.builder().effort(ReasoningEffort.LOW).build())
.addInclude(ResponseIncludable.of("web_search_call.action.sources"))
.addTool(
WebSearchTool.builder()
.type(WebSearchTool.Type.WEB_SEARCH)
.filters(
WebSearchTool.Filters.builder()
.allowedDomains(
List.of(
"pubmed.ncbi.nlm.nih.gov",
"clinicaltrials.gov",
"www.who.int",
"www.cdc.gov",
"www.fda.gov"))
.putAdditionalProperty(
"blocked_domains",
JsonValue.from(List.of("reddit.com", "quora.com", "wikipedia.org")))
.build())
.build())
.build();
var response = client.responses().create(params);
response.output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
response.output().stream()
.flatMap(item -> item.webSearchCall().stream())
.flatMap(call -> call.action().search().stream())
.flatMap(action -> action.sources().stream())
.flatMap(List::stream)
.forEach(source -> System.out.println(source.url()));
require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
reasoning: { effort: :low },
input: "Search for how semaglutide is used in the treatment of diabetes.",
include: ["web_search_call.action.sources"],
tools: [
{
type: :web_search,
filters: {
allowed_domains: [
"pubmed.ncbi.nlm.nih.gov",
"clinicaltrials.gov",
"www.who.int",
"www.cdc.gov",
"www.fda.gov"
],
blocked_domains: ["reddit.com", "quora.com", "wikipedia.org"]
}
}
]
)
puts(response.output_text)
response.output
.grep(OpenAI::Models::Responses::ResponseFunctionWebSearch)
.each do |search_call|
action = search_call.action
next unless action.is_a?(
OpenAI::Models::Responses::ResponseFunctionWebSearch::Action::Search
)
Array(action.sources).each { |source| puts(source.url) }
end
curl "https://api.openai.com/v1/responses" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"reasoning": { "effort": "low" },
"tools": [
{
"type": "web_search",
"filters": {
"allowed_domains": [
"pubmed.ncbi.nlm.nih.gov",
"clinicaltrials.gov",
"www.who.int",
"www.cdc.gov",
"www.fda.gov"
],
"blocked_domains": [
"reddit.com",
"quora.com",
"wikipedia.org"
]
}
}
],
"tool_choice": "auto",
"include": ["web_search_call.action.sources"],
"input": "Please perform a web search on how semaglutide is used in the treatment of diabetes."
}'
Image search results
Web search can return image results alongside regular text results. Use image search when your application needs current or web-grounded visuals, such as product photos, landmarks, places, events, or visual references.
To use image search, set search_content_types to include image. Add text when you also want supporting text results that help the model summarize, rank, or explain the retrieved images.
Use image_settings to control image-specific behavior:
max_results: Request a positive number of image results.caption: Ask for short image descriptions when available.
To inspect raw image results, include web_search_call.results in the request and read web_search_call.results[] from the response. Image results are returned separately from the assistant message, so parse the web_search_call item directly when your application needs the URLs or metadata.
Search for images
import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
reasoning: { effort: "low" },
tools: [
{
type: "web_search",
search_content_types: ["image", "text"],
image_settings: {
max_results: 3,
caption: true,
},
},
],
include: ["web_search_call.results"],
input:
"Search for recent images and supporting text sources about the Golden Gate Bridge at sunset.",
});
console.log(response.output);
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
reasoning={"effort": "low"},
tools=[
{
"type": "web_search",
"search_content_types": ["image", "text"],
"image_settings": {
"max_results": 3,
"caption": True,
},
}
],
include=["web_search_call.results"],
input="Search for recent images and supporting text sources about the Golden Gate Bridge at sunset.",
)
print(response.output)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
tool := responses.ToolParamOfWebSearch(responses.WebSearchToolTypeWebSearch)
tool.OfWebSearch.SetExtraFields(map[string]any{
"search_content_types": []string{"image", "text"},
"image_settings": map[string]any{"max_results": 3, "caption": true},
})
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Reasoning: shared.ReasoningParam{Effort: shared.ReasoningEffortLow},
Tools: []responses.ToolUnionParam{tool},
Include: []responses.ResponseIncludable{responses.ResponseIncludableWebSearchCallResults},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Search for recent images and supporting text sources about the Golden Gate Bridge at sunset.")},
})
if err != nil {
panic(err)
}
fmt.Println(response.Output)
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.Reasoning;
import com.openai.models.ReasoningEffort;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseIncludable;
import com.openai.models.responses.WebSearchTool;
import java.util.List;
import java.util.Map;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Search for recent images and supporting text sources about the Golden Gate Bridge at sunset.")
.reasoning(Reasoning.builder().effort(ReasoningEffort.LOW).build())
.addInclude(ResponseIncludable.of("web_search_call.results"))
.addTool(
WebSearchTool.builder()
.type(WebSearchTool.Type.WEB_SEARCH)
.putAdditionalProperty(
"search_content_types", JsonValue.from(List.of("image", "text")))
.putAdditionalProperty(
"image_settings", JsonValue.from(Map.of("max_results", 3, "caption", true)))
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.webSearchCall().stream())
.map(call -> call._additionalProperties().get("results"))
.filter(java.util.Objects::nonNull)
.forEach(System.out::println);
require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
reasoning: { effort: :low },
input: "Search for recent images and supporting text sources about the Golden Gate Bridge at sunset.",
include: ["web_search_call.results"],
tools: [
{
type: :web_search,
search_content_types: ["image", "text"],
image_settings: {
max_results: 3,
caption: true
}
}
]
)
puts(response.output)
curl "https://api.openai.com/v1/responses" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"reasoning": { "effort": "low" },
"tools": [
{
"type": "web_search",
"search_content_types": ["image", "text"],
"image_settings": {
"max_results": 3,
"caption": true
}
}
],
"include": ["web_search_call.results"],
"input": "Search for recent images and supporting text sources about the Golden Gate Bridge at sunset."
}'
Each image_result includes:
image_url: The canonical image URL for the result.source_website_url: The page where the image was found.thumbnail_url: A thumbnail URL when available.caption: A short caption or description when available.
{
"output": [
{
"type": "web_search_call",
"status": "completed",
"results": [
{
"type": "image_result",
"image_url": "https://cdn.example/golden-gate-sunset.jpg",
"thumbnail_url": "https://cdn.example/golden-gate-sunset-thumb.jpg",
"source_website_url": "https://example.com/source-page",
"caption": "Golden Gate Bridge at sunset"
}
]
}
]
}
User location
To refine search results based on geography, you can specify an approximate user location using country, city, region, and/or timezone.
- The
cityandregionfields are free text strings, likeMinneapolisandMinnesotarespectively. - The
countryfield is a two-letter ISO country code, likeUS. - The
timezonefield is an IANA timezone likeAmerica/Chicago.
Customizing user location
import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.responses.create({
model: "gpt-6-astra",
tools: [
{
type: "web_search",
user_location: {
type: "approximate",
country: "GB",
city: "London",
region: "London",
},
},
],
input: "What are the best restaurants near me?",
});
console.log(response.output_text);
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
tools=[
{
"type": "web_search",
"user_location": {
"type": "approximate",
"country": "GB",
"city": "London",
"region": "London",
},
}
],
input="What are the best restaurants near me?",
)
print(response.output_text)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolParamOfWebSearch(responses.WebSearchToolTypeWebSearch)
tool.OfWebSearch.UserLocation = responses.WebSearchToolUserLocationParam{
Type: "approximate",
Country: openai.String("GB"),
City: openai.String("London"),
Region: openai.String("London"),
}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("What are the best restaurants near me?")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.WebSearchTool;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("What are the best restaurants near me?")
.addTool(
WebSearchTool.builder()
.type(WebSearchTool.Type.WEB_SEARCH)
.userLocation(
WebSearchTool.UserLocation.builder()
.type(WebSearchTool.UserLocation.Type.APPROXIMATE)
.city("London")
.country("GB")
.region("London")
.build())
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
CreateResponseOptions options = new() { Model = "gpt-6-astra" };
options.Tools.Add(
ResponseTool.CreateWebSearchTool(
userLocation: WebSearchToolLocation.CreateApproximateLocation(
country: "GB",
city: "London",
region: "London"
)
)
);
options.InputItems.Add(
ResponseItem.CreateUserMessageItem("What are the best restaurants near me?")
);
ResponseResult response = await client.CreateResponseAsync(options);
Console.WriteLine(response.GetOutputText());
require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "What are the best restaurants near me?",
tools: [
{
type: :web_search,
user_location: {
type: :approximate,
country: "GB",
city: "London",
region: "London"
}
}
]
)
puts(response.output_text)
curl "https://api.openai.com/v1/responses" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"tools": [{
"type": "web_search",
"user_location": {
"type": "approximate",
"country": "GB",
"city": "London",
"region": "London"
}
}],
"input": "What are the best restaurants near me?"
}'
Live internet access
Control whether the web search tool fetches live content or uses only cached/indexed results in the Responses API.
- Set
external_web_access: falseon theweb_searchtool to run in offline/cache‑only mode. - Default is
true(live access) if you do not set it. - Preview variants (
web_search_preview) ignore this parameter and behave as ifexternal_web_accessistrue.
Control live internet access
curl "https://api.openai.com/v1/responses" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"tools": [
{ "type": "web_search", "external_web_access": false }
],
"tool_choice": "auto",
"input": "Find when the Eiffel Tower opened to the public and cite the source."
}'
import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
tools: [{ type: "web_search", external_web_access: false }],
tool_choice: "auto",
input: "Find when the Eiffel Tower opened to the public and cite the source.",
});
console.log(response.output_text);
from openai import OpenAI
client = OpenAI()
resp = client.responses.create(
model="gpt-6-astra",
tools=[{"type": "web_search", "external_web_access": False}],
tool_choice="auto",
input="Find when the Eiffel Tower opened to the public and cite the source.",
)
print(resp.output_text)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolParamOfWebSearch(responses.WebSearchToolTypeWebSearch)
tool.OfWebSearch.SetExtraFields(map[string]any{"external_web_access": false})
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Find when the Eiffel Tower opened to the public and cite the source.")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.WebSearchTool;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Find when the Eiffel Tower opened to the public and cite the source.")
.addTool(
WebSearchTool.builder()
.type(WebSearchTool.Type.WEB_SEARCH)
.putAdditionalProperty("external_web_access", JsonValue.from(false))
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Find when the Eiffel Tower opened to the public and cite the source.",
tools: [
{
type: :web_search,
external_web_access: false
}
]
)
puts(response.output_text)
Limitations
Chat Completions API
The Chat Completions API supports only specialized search models for web search. These models do not support Responses API web_search features such as domain filters, complete source lists, live-access control, and returned-token budget control.
| Model | Context window | Limitation |
|---|---|---|
gpt-5-search-api |
200k | Uses the Chat Completions search model path |
Responses API
Use the hosted web_search tool. The Responses API still accepts web_search_preview for legacy integrations, but use web_search for new integrations.
The web search context window is limited to 128k, even when the underlying model has a larger context window. For the context limit of gpt-6-astra or another supported model, check its model page.
gpt-5.4with reasoning effort set tononemay produce lower-quality results.- Responses API web search uses the underlying model's tiered rate limits.
web_search_previewdoes not supportfiltersorreturn_token_budget, and ignoresexternal_web_access.- With
tool_choice: "auto", search is optional. Usetool_choice: "required"or a specific web search tool choice when search must run.
Usage notes
| API Availability | Rate limits | Notes |
|---|---|---|
|
Same as tiered rate limits for underlying [model](/openai/api/history/docs/en/2026-11-05-2300..2026-11-06-2300/models/) used with the tool. |
[Pricing](/openai/api/history/docs/en/2026-11-05-2300..2026-11-06-2300/pricing/#built-in-tools)
|