Allow models to search the web for the latest information before generating a response.
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.
There are three main types of web search available with OpenAI models:
Nonâreasoning web search: The non-reasoning model sends the userâs query to the web search tool, which returns the response based on top results. Thereâs no internal planning and the model simply passes along the search toolâs responses. This method is fast and ideal for quick lookups.
Agentic search with reasoning models is an approach where the model actively manages the search process. It can perform web searches as part of its chain of thought, analyze results, and decide whether to keep searching. This flexibility makes agentic search well suited to complex workflows, but it also means searches take longer than quick lookups. For example, you can adjust reasoning levels on models like gpt-5.5 to change both the depth and latency of the search.
Deep research is a specialized, agent-driven method for in-depth, extended investigations by reasoning models. The model conducts web searches as part of its chain of thought, often tapping into hundreds of sources. Deep research can run for several minutes and is best used with background mode. Use gpt-5.5 with reasoning set to high or xhigh.
Choose an integration
Use case
Recommended path
Notes
New web search integration
Responses API with web_search and gpt-5.5
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-5.5 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
JavaScript
1
2
3
4
5
6
7
8
9
10import OpenAI from"openai";constclient=newOpenAI();constresponse=await client.responses.create({ model: "gpt-5.6", tools: [{ type: "web_search" }], input: "What was a positive news story from today?",});console.log(response.output_text);
1
2
3
4
5
6
7
8
9
10
11from openai import OpenAIclient = OpenAI()response = client.responses.create( model="gpt-5.6", tools=[{"type": "web_search"}], input="What was a positive news story from today?",)print(response.output_text)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15using OpenAI.Responses;#pragma warning disable OPENAI001string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;ResponsesClient client = new(key);CreateResponseOptions options = new() { Model = "gpt-5.6" };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());
1
2
3
4
5
6
7
8
9
10
11require "openai"openai = OpenAI::Client.newresponse = openai.responses.create( model: "gpt-5.6", tools: [{type: "web_search"}], input: "What was a positive news story from today?")puts(response.output_text)
1
2
3
4
5
6
7
8curl "https://api.openai.com/v1/responses" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -d '{ "model": "gpt-5.6", "tools": [{"type": "web_search"}], "input": "what was a positive news story from today?"}'
1
2
3
4
5
6
7
8openai responses create \ --model gpt-5.6 \ --raw-output \ --transform 'output.#(type=="message").content.0.text' <<'YAML'tools: - type: web_searchinput: 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_call output item with the ID of the search call, along with the action taken in web_search_call.action. The action is one of:
search, which represents a web search. It will usually (but not always) includes the search queries which 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 message output item containing:
The text result in message.content[0].text
Annotations message.content[0].annotations for the cited URLs
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 displaying web results or information contained in web results to end
users, inline citations must be made clearly visible and clickable in your
user interface.
When using Chat Completions, the model always retrieves information from the web before responding to your query. To let the model decide whether to search, switch to the Responses API with the web_search tool.
Currently, use this model for web search in Chat Completions:
gpt-5-search-api
Web search parameter example
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import OpenAI from"openai";constclient=newOpenAI();constcompletion=await client.chat.completions.create({ model: "gpt-5-search-api", web_search_options: {}, messages: [ { role: "user", content: "What was a positive news story from today?", }, ],});console.log(completion.choices[0].message.content);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from openai import OpenAIclient = OpenAI()completion = client.chat.completions.create( model="gpt-5-search-api", web_search_options={}, messages=[ { "role": "user", "content": "What was a positive news story from today?", } ],)print(completion.choices[0].message.content)
1
2
3
4
5
6
7
8
9
10require "openai"client = OpenAI::Client.newcompletion = client.chat.completions.create( model: "gpt-5-search-api", messages: [{role: :user, content: "What was a positive news story today?"}], web_search_options: {})puts(completion.choices.fetch(0).message.content)
1
2
3
4
5
6
7
8
9
10
11curl -X POST "https://api.openai.com/v1/chat/completions" \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-type: application/json" \ -d '{ "model": "gpt-5-search-api", "web_search_options": {}, "messages": [{ "role": "user", "content": "What was a positive news story from today?" }] }'
Output and citations
The API response item in the choices array will include:
message.content with the text result from the model, inclusive of any inline citations
annotations with a list of cited URLs
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 and title of the cited source, as well as the start and end index characters in the modelâs response where those sources were used.
When displaying web results or information contained in web results to end
users, inline citations must be made clearly visible and clickable in your
user interface.
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
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 simple lookups, 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
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14import OpenAI from"openai";constopenai=newOpenAI();constresponse=await openai.responses.create({ model: "gpt-5.6", tools: [ { type: "web_search", search_context_size: "low", }, ], input: "What movie won best picture in 2025?",});console.log(response.output_text);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from openai import OpenAIclient = OpenAI()response = client.responses.create( model="gpt-5.6", tools=[ { "type": "web_search", "search_context_size": "low", } ], input="What movie won best picture in 2025?",)print(response.output_text)
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
curl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import OpenAI from "openai";const client = new OpenAI();const response = await client.responses.create({ model: "gpt-5.6", 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"),});console.log(response.output_text);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24from openai import OpenAIclient = OpenAI()response = client.responses.create( model="gpt-5.6", 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)
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
26
27
28
29
30
31
32
33
34
35
36
37package mainimport ( "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-5.6", 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())}
1
2
3
4
5
6
7
8
9
10
11require "openai"client = OpenAI::Client.newresponse = client.responses.create( model: "gpt-5.6", 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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14curl"https://api.openai.com/v1/responses"\-H"Content-Type: application/json"\-H"Authorization: Bearer $OPENAI_API_KEY"\-d'{ "model": "gpt-5.6", "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
curl
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
26
27
28import OpenAI from "openai";const client = new OpenAI();const response = await client.responses.create({ model: "gpt-5.6", 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);
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
26
27
28
29
30
31
32from openai import OpenAIclient = OpenAI()response = client.responses.create( model="gpt-5.6", 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)
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
26
27
28
29
30package mainimport ( "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-5.6", 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())}
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
26
27
28
29curl"https://api.openai.com/v1/responses"\-H"Content-Type: application/json"\-H"Authorization: Bearer $OPENAI_API_KEY"\-d'{ "model": "gpt-5.6", "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
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import OpenAI from"openai";constclient=newOpenAI();constresponse=await client.responses.create({ model: "gpt-5.6", 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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from openai import OpenAIclient = OpenAI()response = client.responses.create( model="gpt-5.6", 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)
Control whether the web search tool fetches live content or uses only cached/indexed results in the Responses API.
Set external_web_access: false on the web_search tool 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 if external_web_access is true.
Control live internet access
curl
1
2
3
4
5
6
7
8
9
10
11curl"https://api.openai.com/v1/responses"\-H"Content-Type: application/json"\-H"Authorization: Bearer $OPENAI_API_KEY"\-d'{ "model": "gpt-5.6", "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." }'
1
2
3
4
5
6
7
8
9
10
11import OpenAI from "openai";const client = new OpenAI();const response = await client.responses.create({ model: "gpt-5.6", 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);
1
2
3
4
5
6
7
8
9
10
11from openai import OpenAIclient = OpenAI()resp = client.responses.create( model="gpt-5.6", 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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package mainimport ( "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-5.6", 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())}
1
2
3
4
5
6
7
8
9
10
11require "openai"client = OpenAI::Client.newresponse = client.responses.create( model: "gpt-5.6", 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.