Skip to main content
Lesson 5 of 20 · API Tools: Search, Files, and Code Interpreter

Web Search API: Programmatic Web Search

Lesson 5 of 20 Updated November 2, 2026 Developer
On this page
  1. Web Search API: Programmatic Web Search
  2. Enable Web Search
  3. Response Structure
  4. User Context for Relevance
  5. Combine Web Search with Custom Functions
  6. Production Use Cases
  7. Known Limitations
  8. Key Takeaways

Lesson updated November 2, 2026 based on OpenAI documentation: the Code Interpreter tool now requires a container parameter (added to all examples), input text parts are of type input_text, and web search uses the web_search tool (web_search_preview is now a legacy tool without domain filters). Generated files are retrieved using the fichiers_generes and telecharger functions from Lesson 10. Sources: Code Interpreter · Web search.

The Web Search tool lets the model perform real-time web searches directly from the Responses API. You no longer need to integrate a third-party search API: the model formulates the query, executes the search, and synthesizes the results.

Activation takes just one line, which masks a fundamental shift: your application is no longer limited by the model’s knowledge cutoff. Questions about yesterday’s events, current pricing, or recent regulations become answerable without integrating or paying for a third-party search engine.

from openai import OpenAI

client = OpenAI()

response = client.responses.create(
    model="gpt-5.6-terra",
    input="What are the latest Ligue 1 results?",
    tools=[{"type": "web_search"}]
)

print(response.output_text)

The model decides when to search on its own, and this point deserves attention: it does not search systematically. For questions it believes fall within its existing knowledge, it answers directly—faster and cheaper, but with the risk of presenting outdated information with the same confidence. When freshness is critical, state this explicitly in your prompt rather than hoping the model guesses correctly.

Response Structure

Sources arrive as annotations attached to the response, separate from the text. This lets you display them your way, verify them, or flag as suspicious any response that lacks sources when the topic demands them.

response = client.responses.create(
    model="gpt-5.6-terra",
    input="What is the current stock price of LVMH?",
    tools=[{"type": "web_search"}]
)

# Synthesized text
print(response.output_text)

# Examine sources
for item in response.output:
    if hasattr(item, "content"):
        for block in item.content:
            if hasattr(block, "annotations"):
                for annotation in block.annotations:
                    if annotation.type == "url_citation":
                        print(f"Source: {annotation.url}")
                        print(f"Title : {annotation.title}")

User Context for Relevance

Location affects results more than you might expect, and not just for obviously local searches. Questions about taxation, pricing, availability, or legal obligations yield different answers depending on the country: without user_location, the model defaults to a context that is often US-centric.

response = client.responses.create(
    model="gpt-5.6-terra",
    input="Which Japanese restaurant is open tonight?",
    tools=[{
        "type": "web_search",
        "user_location": {
            "type": "approximate",
            "city": "Paris",
            "country": "FR"
        }
    }]
)

The user_location parameter accepts several levels of precision:

# Approximate location
"user_location": {
    "type": "approximate",
    "city": "Lyon",
    "region": "Auvergne-Rhone-Alpes",
    "country": "FR"
}

Combine Web Search with Custom Functions

The most productive combination always follows the same pattern: the web brings external information, your functions provide internal context, and the model connects the dots. This connection is where the value lies—neither the search nor your data alone answers “does this change affect us?”

tools = [
    {"type": "web_search"},
    {
        "type": "function",
        "name": "sauvegarder_veille",
        "description": "Save a monitoring result to the database",
        "parameters": {
            "type": "object",
            "properties": {
                "titre": {"type": "string"},
                "resume": {"type": "string"},
                "url_source": {"type": "string"},
                "categorie": {
                    "type": "string",
                    "enum": ["concurrent", "marche", "reglementation", "technologie"]
                }
            },
            "required": ["titre", "resume", "categorie"],
            "additionalProperties": False
        },
        "strict": True
    }
]

response = client.responses.create(
    model="gpt-5.6-terra",
    input="Search for the latest news on AI regulation in Europe "
          "and save important results",
    tools=tools
)

Production Use Cases

Automated Competitive Intelligence

def veille_quotidienne(entreprises: list[str]):
    """Launches web monitoring for each competitor."""
    resultats = []
    for entreprise in entreprises:
        response = client.responses.create(
            model="gpt-5.6-terra",
            input=f"What is the latest news about {entreprise}? "
                  "Focus on product announcements, funding rounds, "
                  "and partnerships from the last 7 days.",
            tools=[{"type": "web_search"}]
        )
        resultats.append({
            "entreprise": entreprise,
            "synthese": response.output_text
        })
    return resultats

Fact-Checking

def verifier_affirmation(affirmation: str) -> dict:
    """Verifies a claim by cross-referencing multiple web sources."""
    response = client.responses.create(
        model="gpt-5.6-terra",
        input=f"Verify this claim by searching for reliable sources: "
              f"'{affirmation}'. State whether it is true, false, or uncertain, "
              f"including the sources supporting your conclusion.",
        tools=[{"type": "web_search"}]
    )

    # Extract citations
    sources = []
    for item in response.output:
        if hasattr(item, "content"):
            for block in item.content:
                if hasattr(block, "annotations"):
                    for ann in block.annotations:
                        if ann.type == "url_citation":
                            sources.append(ann.url)

    return {
        "analyse": response.output_text,
        "nombre_sources": len(sources),
        "sources": sources
    }

Known Limitations

  • The model may not find relevant results for very niche topics
  • Results depend on web indexing at the time of the request
  • The number of searches per call is limited: the model optimizes by formulating precise queries
  • Content behind paywalls or login screens is inaccessible

Key Takeaways

  • Add web_search in one line within tools
  • The model decides autonomously when to search the web
  • user_location improves relevance for local results
  • url_citation annotations provide sources
  • Combine Web Search with your functions to automate monitoring