Web Search Tool
Allow models to search the web for the latest information before generating a response.
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.
Choose an integration
AvalAI offers two complementary search paths:
| Use case | Recommended path | Notes |
|---|---|---|
| New AI answers with citations | /v1/responses + tools: [{"type": "web_search"}] | Best default for Responses-first apps; the model decides when to search unless you force tool_choice. |
| Raw search results for your app | /v1/search | Returns URLs, snippets, and provider-specific metadata without LLM synthesis. |
| Existing Chat Completions search apps | /v1/chat/completions with an AvalAI-supported search model | Keep existing integrations, but prefer Responses web_search for new work. |
Use search_context_size: "low" for fast lookups, "medium" as the balanced default, and "high" when the answer needs richer source context.
Web search tool example
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: "https://api.avalai.ir/v1",
}); // Use custom base URL
const response = await client.responses.create({
model: "gpt-5.5",
tools: [{ type: "web_search" }],
input: "What was a positive news story from today?",
});
console.log(response.output_text);from openai import OpenAI
import os
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1", # Custom API endpoint
) # Use custom base URL
response = client.responses.create(
model="gpt-5.5",
tools=[{"type": "web_search"}],
input="What was a positive news story from today?",
)
print(response.output_text)curl https://api.avalai.ir/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-d '{
"model": "gpt-5.5",
"tools": [{"type": "web_search"}],
"input": "what was a positive news story from today?"
}'package main
import (
"context"
"fmt"
"github.com/openai/openai-go" // OpenAI Go client
"github.com/openai/openai-go/option"
"os"
)
func main() {
apiKey := os.Getenv("AVALAI_API_KEY")
client := openai.NewClient(
option.WithAPIKey(apiKey),
option.WithBaseURL("https://api.avalai.ir/v1"), // Use custom base URL
)
resp, err := client.Responses.Create(
context.Background(),
openai.ResponsesCreateParams{
Model: "gpt-5.5",
Tools: []openai.ToolParamUnion{
openai.ToolParam{
Type: openai.F("web_search"),
},
},
Input: "What was a positive news story from today?",
},
)
if err != nil {
fmt.Printf("Response creation error: %v\n", err)
return
}
fmt.Println(resp.OutputText)
}<?php
require_once(__DIR__ . '/vendor/autoload.php'); // Assuming Composer autoload
$apiKey = getenv('AVALAI_API_KEY');
$client = OpenAI::client($apiKey, ["base_uri" => "https://api.avalai.ir/v1"]); // Using OpenAI PHP client with custom base URL
$response = $client->responses()->create([
'model' => 'gpt-5.5',
'tools' => [['type' => 'web_search']],
'input' => 'What was a positive news story from today?',
]);
echo $response->output_text;
?>Web search tool versions
Use web_search for new Responses API integrations. The older web_search_preview tool remains available for legacy integrations, but it does not support newer controls such as filters, live-access control, and returned-token budgets.
You can force web search with the tool_choice parameter, for example { "type": "web_search" }, when search must run for a request.
Migration path from legacy search models
Do not remove existing Chat Completions search integrations just because newer Responses tooling exists. AvalAI still lists gpt-4o-search-preview and gpt-4o-mini-search-preview in data/models.json, so they remain documented while they are active. For new work, prefer /v1/responses with gpt-5.5 and tools: [{"type": "web_search"}].
| Current integration | Keep or migrate? | Recommended next step |
|---|---|---|
/v1/responses + web_search_preview | Migrate | Replace the tool with {"type": "web_search"} to use filters, source metadata, live-access control, and returned-token budget controls. |
/v1/chat/completions + gpt-4o-search-preview | Keep only for legacy apps | Plan migration before the scheduled July 23, 2026 shutdown listed in deprecations; move new search UX to Responses web_search. |
/v1/chat/completions + gpt-4o-mini-search-preview | Keep only for legacy apps | Same migration path as above; use Responses for optional search, domain filters, and richer web_search_call metadata. |
Raw search endpoint /v1/search | Keep when you need raw results | Use it for URL/snippet retrieval without LLM synthesis; use Responses when the model should synthesize cited answers. |
There are three practical search modes to design for:
- Quick lookup: low or medium
search_context_size, optional search, and short answers. - Agentic research: reasoning models can search, inspect results, and continue searching when the prompt requires more evidence.
- Deep research: use higher reasoning effort and background processing for long reports that can take minutes.
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 and anactionfield. Depending on the model and search path, the action can besearch,open_page, orfind_in_page. - 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 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.
[
{
"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..."
}
]
}
]
}
]Citation rendering checklist
Use this checklist when turning web_search output into a product UI:
- Render inline
url_citationannotations as visible, clickable source links near the generated claim. - Preserve each citation's
url,title, and text span so users can inspect what the model relied on. - Request
include: ["web_search_call.action.sources"]when you need the complete consulted-source list for audits, not only the citations selected for the final answer. - Store the
web_search_call.actionobject with your trace logs so you can debug whether the model searched, opened a page, or searched within a page. - If a response has no citations for a freshness-sensitive answer, treat it as ungrounded and retry with
tool_choice: "required"or a narrower prompt.
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.
User location is a hint for local relevance, not a proof of the user's precise position. Do not use it for compliance, billing, access-control, or safety decisions. It is also not supported for deep-research web-search runs; keep those prompts source-focused instead of location-personalized.
Customizing user location
from openai import OpenAI
import os
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1", # Custom API endpoint
) # Use custom base URL
response = client.responses.create(
model="gpt-5.5",
tools=[
{
"type": "web_search",
"user_location": {
"type": "approximate",
"country": "GB",
"city": "London",
"region": "London",
},
}
],
input="What are the best restaurants around Granary Square?",
)
print(response.output_text)import OpenAI from "openai";
const openai = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: "https://api.avalai.ir/v1",
}); // Use custom base URL
const response = await openai.responses.create({
model: "gpt-5.5",
tools: [
{
type: "web_search",
user_location: {
type: "approximate",
country: "GB",
city: "London",
region: "London",
},
},
],
input: "What are the best restaurants around Granary Square?",
});
console.log(response.output_text);curl https://api.avalai.ir/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-d '{
"model": "gpt-5.5",
"tools": [{
"type": "web_search",
"user_location": {
"type": "approximate",
"country": "GB",
"city": "London",
"region": "London"
}
}],
"input": "What are the best restaurants around Granary Square?"
}'package main
import (
"context"
"fmt"
"github.com/openai/openai-go" // OpenAI Go client
"github.com/openai/openai-go/option"
"os"
)
func main() {
apiKey := os.Getenv("AVALAI_API_KEY")
client := openai.NewClient(
option.WithAPIKey(apiKey),
option.WithBaseURL("https://api.avalai.ir/v1"), // Use custom base URL
)
resp, err := client.Responses.Create(
context.Background(),
openai.ResponsesCreateParams{
Model: "gpt-5.5",
Tools: []openai.ToolParamUnion{
openai.ToolParam{
Type: openai.F("web_search"),
UserLocation: &openai.UserLocation{
Type: openai.F("approximate"),
Country: openai.F("GB"),
City: openai.F("London"),
Region: openai.F("London"),
},
},
},
Input: "What are the best restaurants around Granary Square?",
},
)
if err != nil {
fmt.Printf("Response creation error: %v\n", err)
return
}
fmt.Println(resp.OutputText)
}<?php
require_once(__DIR__ . '/vendor/autoload.php'); // Assuming Composer autoload
$apiKey = getenv('AVALAI_API_KEY');
$client = OpenAI::client($apiKey, ["base_uri" => "https://api.avalai.ir/v1"]); // Using OpenAI PHP client with custom base URL
$response = $client->responses()->create([
'model' => 'gpt-5.5',
'tools' => [[
'type' => 'web_search',
'user_location' => [
'type' => 'approximate',
'country' => 'GB',
'city' => 'London',
'region' => 'London',
]
]],
'input' => 'What are the best restaurants around Granary Square?',
]);
echo $response->output_text;
?>Search context size
When using this tool, the search_context_size parameter controls how much web-result context is made available before the model formulates a response. It is a quality/cost/latency control, not an exact token count, source count, or citation guarantee.
Choosing a context size impacts:
- Cost: Pricing of our search tool varies based on the value of this parameter. Higher context sizes are more expensive. See tool pricing here.
- Quality: Higher search context sizes generally provide richer context, resulting in more accurate, comprehensive answers.
- Latency: Higher context sizes require processing more tokens, which can slow down the tool's response time.
Available values:
high: Most comprehensive context, highest cost, slower response.medium(default): Balanced context, cost, and latency.low: Least context, lowest cost, fastest response, but potentially lower answer quality.
Check the pricing page for costs associated with each context size, and treat the setting as a retrieval-depth control rather than a persistence mechanism across turns.
Customizing search context size
from openai import OpenAI
import os
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1", # Custom API endpoint
) # Use custom base URL
response = client.responses.create(
model="gpt-5.5",
tools=[
{
"type": "web_search",
"search_context_size": "low",
}
],
input="What movie won best picture in 2025?",
)
print(response.output_text)import OpenAI from "openai";
const openai = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: "https://api.avalai.ir/v1",
}); // Use custom base URL
const response = await openai.responses.create({
model: "gpt-5.5",
tools: [
{
type: "web_search",
search_context_size: "low",
},
],
input: "What movie won best picture in 2025?",
});
console.log(response.output_text);curl https://api.avalai.ir/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-d '{
"model": "gpt-5.5",
"tools": [{
"type": "web_search",
"search_context_size": "low"
}],
"input": "What movie won best picture in 2025?"
}'package main
import (
"context"
"fmt"
"github.com/openai/openai-go" // OpenAI Go client
"github.com/openai/openai-go/option"
"os"
)
func main() {
apiKey := os.Getenv("AVALAI_API_KEY")
client := openai.NewClient(
option.WithAPIKey(apiKey),
option.WithBaseURL("https://api.avalai.ir/v1"), // Use custom base URL
)
resp, err := client.Responses.Create(
context.Background(),
openai.ResponsesCreateParams{
Model: "gpt-5.5",
Tools: []openai.ToolParamUnion{
openai.ToolParam{
Type: openai.F("web_search"),
SearchContextSize: openai.F("low"),
},
},
Input: "What movie won best picture in 2025?",
},
)
if err != nil {
fmt.Printf("Response creation error: %v\n", err)
return
}
fmt.Println(resp.OutputText)
}<?php
require_once(__DIR__ . '/vendor/autoload.php'); // Assuming Composer autoload
$apiKey = getenv('AVALAI_API_KEY');
$client = OpenAI::client($apiKey, ["base_uri" => "https://api.avalai.ir/v1"]); // Using OpenAI PHP client with custom base URL
$response = $client->responses()->create([
'model' => 'gpt-5.5',
'tools' => [[
'type' => 'web_search',
'search_context_size' => 'low',
]],
'input' => 'What movie won best picture in 2025?',
]);
echo $response->output_text;
?>Advanced search controls
Use these controls when the selected model and AvalAI routing support them:
- Domain filtering:
filters.allowed_domainsandfilters.blocked_domainsconstrain search to trusted sources or exclude low-quality domains. Omithttps://from domain names, for examplewho.int. - Source metadata: add
include: ["web_search_call.action.sources"]when your app needs the complete list of consulted URLs, not only inline citations. - Live access control: set
external_web_access: falseto prefer cached/indexed results for offline or restricted runs. The default is live access. - Long research:
return_token_budget: "unlimited"can allow larger returned search context for high-effort research, but may increase latency and cost. - Image search:
search_content_types: ["image", "text"]plusimage_settingscan return visual web results when the UI needs current product photos, landmarks, or event images.
Domain filters accept up to 100 allowed domains or up to 100 blocked domains. Enter bare domains such as who.int or pubmed.ncbi.nlm.nih.gov; do not include https://, and expect subdomains to be included. return_token_budget supports default and unlimited; use unlimited only for GPT-5-family reasoning searches where the route supports longer web research, and combine it with background processing when a report may take minutes.
For privacy-sensitive workflows, treat live web search as an external data flow. OpenAI's data-controls guide distinguishes live internet access from offline/cache-only search modes; in AvalAI, only use external_web_access: false or make HIPAA/BAA, ZDR, or residency claims after the selected model route explicitly confirms support. Never send private account data, secrets, or raw personal identifiers in search queries.
Trusted-source search with source metadata
Use domain filters when your answer must come from a known source set, and request source metadata when your application needs to audit or render every consulted URL. external_web_access: false is useful for cache-only/restricted runs when the selected model and route support it.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
response = client.responses.create(
model="gpt-5.5",
input="Summarize the latest WHO guidance on diabetes treatment and cite sources.",
tools=[
{
"type": "web_search",
"search_context_size": "medium",
"filters": {
"allowed_domains": ["who.int", "cdc.gov", "fda.gov"],
"blocked_domains": ["reddit.com", "quora.com"],
},
}
],
include=["web_search_call.action.sources"],
tool_choice="auto",
)
print(response.output_text)
for item in response.output:
if item.type == "web_search_call":
print(item.action)import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: "https://api.avalai.ir/v1",
});
const response = await client.responses.create({
model: "gpt-5.5",
input: "Summarize the latest WHO guidance on diabetes treatment and cite sources.",
tools: [
{
type: "web_search",
search_context_size: "medium",
filters: {
allowed_domains: ["who.int", "cdc.gov", "fda.gov"],
blocked_domains: ["reddit.com", "quora.com"],
},
},
],
include: ["web_search_call.action.sources"],
tool_choice: "auto",
});
console.log(response.output_text);
console.log(response.output.filter((item) => item.type === "web_search_call"));curl https://api.avalai.ir/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-d '{
"model": "gpt-5.5",
"input": "Summarize the latest WHO guidance on diabetes treatment and cite sources.",
"tools": [
{
"type": "web_search",
"search_context_size": "medium",
"filters": {
"allowed_domains": ["who.int", "cdc.gov", "fda.gov"],
"blocked_domains": ["reddit.com", "quora.com"]
}
}
],
"include": ["web_search_call.action.sources"],
"tool_choice": "auto"
}'Image search results
When a product or research UI needs visual references, request image results explicitly and inspect the web_search_call.results items instead of relying only on output_text.
Each image result can include image_url, source_website_url, thumbnail_url, and caption. Validate the source domain and image URL before rendering or proxying the asset in your application.
response = client.responses.create(
model="gpt-5.5",
input="Find recent product images of electric cargo bikes and summarize design trends.",
tools=[
{
"type": "web_search",
"search_content_types": ["image", "text"],
"image_settings": {"max_results": 3, "caption": True},
}
],
include=["web_search_call.results"],
)
for item in response.output:
if item.type == "web_search_call":
print(item.results)const imageResponse = await client.responses.create({
model: "gpt-5.5",
input: "Find recent product images of electric cargo bikes and summarize design trends.",
tools: [
{
type: "web_search",
search_content_types: ["image", "text"],
image_settings: { max_results: 3, caption: true },
},
],
include: ["web_search_call.results"],
});
console.log(imageResponse.output);Limitations
Below are a few notable implementation considerations when using web search.
- Chat Completions search models use a specialized model path and do not support the newer Responses
web_searchcontrols such as domain filters, full source lists, live-access control, or returned-token budget control. - OpenAI's current docs recommend newer Chat Completions search models for that path; in AvalAI docs, only use model IDs that exist in
data/models.json. - With
tool_choice: "auto", search is optional. Usetool_choice: "required"or a specific web-search tool choice when search must run. - When used as a tool in the Responses API, web search follows the selected model's tiered rate limits plus tool pricing.
- Review the Privacy Policy and Content Policy for data handling, residency, retention, and safety expectations.