Back to AI App Dev Series

Gemini SDK Track Part 7: Built-in Tools: Search, Maps, URL & Code Execution

May 24, 2026 Wasil Zafar 35 min read

Ground Gemini responses with Google Search, Google Maps, URL context, and code execution sandbox. Combine multiple built-in tools and render grounding metadata in your UI.

Table of Contents

  1. Grounding with Google Search
  2. Grounding with Google Maps
  3. URL Context Tool
  4. Code Execution Sandbox
  5. Combining Multiple Built-in Tools
What You’ll Learn: The Live API enables real-time, bidirectional communication with Gemini over WebSocket — streaming text, audio, and video simultaneously. This powers voice assistants, live video analysis, and interactive applications that respond in real-time. Think of it like FaceTime with AI: continuous, natural interaction instead of turn-based chat.

Grounding connects Gemini’s responses to real-time information from Google Search, eliminating hallucination for factual queries. When enabled, the model can retrieve current data — news, stock prices, weather, sports scores — and cite its sources.

1.1 Basic Setup

from google import genai
from google.genai import types

client = genai.Client()

# Enable Google Search grounding
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="What were the top 3 news stories today?",
    config=types.GenerateContentConfig(
        tools=[types.Tool(google_search=types.GoogleSearch())]
    )
)

print(response.text)
When to Use Search Grounding: Enable it for queries about current events, live data (stocks, weather), recent publications, or any factual claim that could be outdated based on the model’s training cutoff. Disable it for creative writing, code generation, or analysis of provided documents.

1.2 Grounding Metadata & Citations

Search-grounded responses include rich metadata — source URLs, titles, and grounding chunks that map specific claims to their sources:

from google import genai
from google.genai import types

client = genai.Client()

response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="What is the current population of Tokyo and when was the last census?",
    config=types.GenerateContentConfig(
        tools=[types.Tool(google_search=types.GoogleSearch())]
    )
)

print("Answer:", response.text)
print("\n--- Grounding Metadata ---")

# Access grounding metadata from the candidate
candidate = response.candidates[0]
if candidate.grounding_metadata:
    gm = candidate.grounding_metadata
    
    # Search entry point (rendered search widget)
    if gm.search_entry_point:
        print(f"\nSearch query: {gm.search_entry_point.rendered_content[:100]}...")
    
    # Grounding chunks — individual source citations
    if gm.grounding_chunks:
        print(f"\nSources ({len(gm.grounding_chunks)}):")
        for i, chunk in enumerate(gm.grounding_chunks):
            if chunk.web:
                print(f"  [{i+1}] {chunk.web.title}")
                print(f"      {chunk.web.uri}")
    
    # Grounding supports — maps text segments to sources
    if gm.grounding_supports:
        print(f"\nSupported claims ({len(gm.grounding_supports)}):")
        for support in gm.grounding_supports[:3]:
            print(f"  Segment: \"{support.segment.text[:80]}...\"")
            print(f"  Sources: {support.grounding_chunk_indices}")
            print(f"  Confidence: {support.confidence_scores}")

1.3 Rendering in UI

For production applications, render grounding metadata as inline citations or footnotes:

from google import genai
from google.genai import types

client = genai.Client()

def format_grounded_response(response) -> str:
    """Format a grounded response with inline citations."""
    candidate = response.candidates[0]
    text = response.text
    
    if not candidate.grounding_metadata or not candidate.grounding_metadata.grounding_chunks:
        return text
    
    # Build citation list
    sources = []
    for chunk in candidate.grounding_metadata.grounding_chunks:
        if chunk.web:
            sources.append({"title": chunk.web.title, "url": chunk.web.uri})
    
    # Append footnotes
    if sources:
        text += "\n\n---\nSources:\n"
        for i, source in enumerate(sources, 1):
            text += f"[{i}] {source['title']} — {source['url']}\n"
    
    return text

response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="What are the latest developments in quantum computing?",
    config=types.GenerateContentConfig(
        tools=[types.Tool(google_search=types.GoogleSearch())]
    )
)

formatted = format_grounded_response(response)
print(formatted)

2. Grounding with Google Maps

The Google Maps tool provides location-aware responses with real business data, directions, and place information.

2.1 Configuration

from google import genai
from google.genai import types

client = genai.Client()

# Enable Google Maps grounding
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="Find the best-rated Italian restaurants near Times Square, New York.",
    config=types.GenerateContentConfig(
        tools=[types.Tool(google_maps=types.GoogleMaps())]
    )
)

print(response.text)

2.2 Location-Aware Responses

Maps grounding excels at queries involving places, distances, business hours, and local recommendations:

from google import genai
from google.genai import types

client = genai.Client()

# Complex location query — combines Maps data with reasoning
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="I'm at the British Museum in London. What are 3 good lunch spots "
             "within a 10-minute walk that are open right now and have vegetarian options?",
    config=types.GenerateContentConfig(
        tools=[types.Tool(google_maps=types.GoogleMaps())]
    )
)

print(response.text)

# Access maps-specific grounding data
candidate = response.candidates[0]
if candidate.grounding_metadata and candidate.grounding_metadata.grounding_chunks:
    print("\n--- Places Referenced ---")
    for chunk in candidate.grounding_metadata.grounding_chunks:
        if chunk.web:
            print(f"  • {chunk.web.title}: {chunk.web.uri}")
Maps vs Search: Use Google Maps for queries about specific places, directions, business info, or “near me” type requests. Use Google Search for general factual queries, news, or non-location information. You can combine both for comprehensive location-aware answers.
Real-World Application

Real-Time Sports Commentary

A sports analytics company streams live game video to Gemini’s Live API, which provides instant tactical analysis, identifies key plays, and generates commentary. The system processes video frames in real-time, correlating visual events with statistical data from their database.

Live APISports AnalyticsReal-Time

3. URL Context Tool

The URL Context tool lets the model fetch and read specific web pages, enabling it to answer questions about particular URLs you provide or that it discovers during reasoning.

3.1 Fetching Web Pages

from google import genai
from google.genai import types

client = genai.Client()

# Let the model read and analyze a specific URL
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="Summarize the key points from this page: "
             "https://ai.google.dev/gemini-api/docs/thinking",
    config=types.GenerateContentConfig(
        tools=[types.Tool(url_context=types.UrlContext())]
    )
)

print(response.text)

You can also combine URL context with Google Search to let the model both search for relevant pages and read their full content:

from google import genai
from google.genai import types

client = genai.Client()

# Combine URL context with Search — model searches, finds pages, reads them
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="Find the official Gemini API pricing page and tell me the exact "
             "cost per million tokens for Gemini 3.5 Flash input and output.",
    config=types.GenerateContentConfig(
        tools=[
            types.Tool(google_search=types.GoogleSearch()),
            types.Tool(url_context=types.UrlContext())
        ]
    )
)

print(response.text)

3.2 URL Context Metadata

Responses using URL context include metadata about which pages were fetched and how they contributed to the answer:

from google import genai
from google.genai import types

client = genai.Client()

response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="Read https://docs.python.org/3/library/asyncio.html and explain "
             "the difference between asyncio.gather() and asyncio.wait().",
    config=types.GenerateContentConfig(
        tools=[types.Tool(url_context=types.UrlContext())]
    )
)

print("Answer:", response.text[:500])

# Check URL context metadata
candidate = response.candidates[0]
if candidate.grounding_metadata:
    gm = candidate.grounding_metadata
    
    # URL context metadata shows which URLs were fetched
    if hasattr(gm, 'url_context_metadata') and gm.url_context_metadata:
        print("\n--- URLs Fetched ---")
        for url_meta in gm.url_context_metadata:
            print(f"  URL: {url_meta.url}")
            print(f"  Status: {url_meta.status}")
Limitations: The URL context tool cannot access pages behind authentication, paywalls, or robots.txt restrictions. It also has a content size limit — very large pages may be truncated. For reliable access to your own content, use the Files API or context caching instead.

4. Code Execution Sandbox

The Code Execution tool gives the model a sandboxed Python environment where it can write and run code. This is invaluable for calculations, data transformations, and generating visualizations.

from google import genai
from google.genai import types

client = genai.Client()

# Enable code execution — model writes AND runs Python code
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="Calculate the first 20 Fibonacci numbers and find which ones are prime.",
    config=types.GenerateContentConfig(
        tools=[types.Tool(code_execution=types.ToolCodeExecution())]
    )
)

print(response.text)

The model can also use code execution for data processing tasks that require precision:

from google import genai
from google.genai import types

client = genai.Client()

# Complex calculation that benefits from actual code execution
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="I have quarterly revenue data: Q1=$2.3M, Q2=$2.8M, Q3=$3.1M, Q4=$3.6M. "
             "Calculate the quarter-over-quarter growth rates, the compound annual growth rate, "
             "and project Q1 next year assuming the trend continues.",
    config=types.GenerateContentConfig(
        tools=[types.Tool(code_execution=types.ToolCodeExecution())]
    )
)

print(response.text)

# Inspect executable code parts in the response
for part in response.candidates[0].content.parts:
    if part.executable_code:
        print("\n--- Generated Code ---")
        print(part.executable_code.code)
    if part.code_execution_result:
        print("\n--- Execution Output ---")
        print(part.code_execution_result.output)
Sandbox Environment: Code executes in a secure, ephemeral sandbox with limited Python libraries (numpy, pandas, matplotlib are available). No network access, no file system persistence, no installing packages. Each execution is isolated and stateless.
from google import genai
from google.genai import types

client = genai.Client()

# Chart generation — the model creates matplotlib charts in the sandbox
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="Create a visualization comparing the Big-O complexities: "
             "O(1), O(log n), O(n), O(n log n), O(n²) for n from 1 to 100. "
             "Use matplotlib with a clean, professional style.",
    config=types.GenerateContentConfig(
        tools=[types.Tool(code_execution=types.ToolCodeExecution())]
    )
)

# The response may include generated image data
for part in response.candidates[0].content.parts:
    if part.executable_code:
        print("Code generated:")
        print(part.executable_code.code[:300])
    if part.inline_data:
        print(f"\nImage generated: {part.inline_data.mime_type}, "
              f"{len(part.inline_data.data)} bytes")
    if part.text:
        print(f"\nExplanation: {part.text[:200]}...")

5. Combining Multiple Built-in Tools

The most powerful pattern combines multiple built-in tools in a single request. The model decides which tools to use based on the query:

from google import genai
from google.genai import types

client = genai.Client()

# All built-in tools enabled — model picks what it needs
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="What was Apple's stock price at close yesterday? "
             "Calculate the P/E ratio if their earnings per share is $6.42. "
             "Also find their next earnings date.",
    config=types.GenerateContentConfig(
        tools=[
            types.Tool(google_search=types.GoogleSearch()),
            types.Tool(code_execution=types.ToolCodeExecution())
        ]
    )
)

print(response.text)

# The model used Search to get the stock price and earnings date,
# then Code Execution to calculate the P/E ratio precisely
from google import genai
from google.genai import types

client = genai.Client()

# Search + URL Context + Code Execution — comprehensive research assistant
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="Find the latest World Bank GDP data for the G7 countries, "
             "then create a bar chart comparing them and calculate the "
             "percentage each contributes to the G7 total.",
    config=types.GenerateContentConfig(
        tools=[
            types.Tool(google_search=types.GoogleSearch()),
            types.Tool(url_context=types.UrlContext()),
            types.Tool(code_execution=types.ToolCodeExecution())
        ]
    )
)

print(response.text)
Tool Selection Behavior: When multiple tools are available, the model analyzes the query and selects the most appropriate tool(s). It may use multiple tools sequentially (search for data → code execution for calculations) or pick just one. You cannot force which tool is used — write clear, specific prompts to guide selection.
from google import genai
from google.genai import types

client = genai.Client()

# Combine built-in tools with custom functions
def get_company_internal_data(ticker: str) -> dict:
    """Get internal company metrics not available publicly."""
    internal_data = {
        "AAPL": {"internal_score": 92, "team_size": 164000, "patents_filed_2025": 2340},
        "GOOGL": {"internal_score": 88, "team_size": 182000, "patents_filed_2025": 3100},
    }
    return internal_data.get(ticker, {"error": "Company not found"})

response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="Compare Apple and Google: get their current stock prices from the web, "
             "then pull our internal metrics for both, and create a comparison table.",
    config=types.GenerateContentConfig(
        tools=[
            types.Tool(google_search=types.GoogleSearch()),
            types.Tool(code_execution=types.ToolCodeExecution()),
            get_company_internal_data
        ]
    )
)

# Model orchestrates: Search → Custom Function → Code Execution
for part in response.candidates[0].content.parts:
    if part.function_call:
        print(f"Custom tool called: {part.function_call.name}")
    if part.text:
        print(part.text[:300])
Production Pattern: For production applications, combine Google Search (real-time data) + URL Context (deep reading) + Code Execution (precise calculations) + Custom Functions (your business logic). This creates a powerful research assistant that can find information, read sources, compute answers, and access internal systems — all in a single request.
Try It Yourself: Build a ‘live study buddy’: (1) establish a WebSocket connection to Gemini’s Live API, (2) stream audio input (questions about a topic), (3) receive and play audio responses, (4) add a function call for ‘show_diagram’ that the model can invoke mid-conversation to display visual aids.

Next in the Gemini SDK Track

In Part 8: File Search & RAG, we’ll upload documents via the Files API, build retrieval-augmented generation pipelines with Gemini’s 1M+ token context, implement semantic search over uploaded corpora, and combine file-based grounding with other tools for comprehensive document Q&A.