Code execution and Google Search grounding (Gemini)

Gemini ships three first-party “server tools” — Python code_execution, google_search grounding, and url_context — that run on Google’s infrastructure when you enable them, rather than client-side functions you implement. All three are enabled by adding a Tool entry to the request and require zero implementation work on your side. The model decides when to use them, executes them in-flight, and folds results back into its generation, returning the trail (executed code, search citations, fetched URLs) in the response so you can render or audit. Together they make agentic Gemini workflows possible without you wiring up a sandbox, a search API, or a fetcher.

See also

1. Code execution

Enabling

from google import genai
from google.genai import types
 
resp = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="What is the 50th Fibonacci number? Compute it.",
    config=types.GenerateContentConfig(
        tools=[types.Tool(code_execution=types.ToolCodeExecution())],
    ),
)

The model decides when to write + run Python. The response includes the code, the execution result, and the natural-language interpretation as separate parts.

Inspecting the trail

for part in resp.candidates[0].content.parts:
    if part.text:
        print(f"TEXT: {part.text}")
    elif part.executable_code:
        print(f"CODE ({part.executable_code.language}):")
        print(part.executable_code.code)
    elif part.code_execution_result:
        print(f"RESULT ({part.code_execution_result.outcome}):")
        print(part.code_execution_result.output)

outcome values: OUTCOME_OK, OUTCOME_FAILED, OUTCOME_DEADLINE_EXCEEDED, OUTCOME_UNSPECIFIED.

Sandbox details

Per ai.google.dev/gemini-api/docs/code-execution (2026-05):

PropertyValue
LanguagePython only (model can generate other languages as text, but only Python executes)
Max execution time30 seconds per code block
MemorySandbox-limited (no documented exact value; ~few GB)
NetworkNo external network access (cannot make HTTP requests)
FilesystemEphemeral; can read input files passed to the model
Pre-installed librariesNumPy, Pandas, Matplotlib, scikit-learn, TensorFlow, PyTorch, SymPy, SciPy, OpenCV, Pillow, fpdf, reportlab, statsmodels, BeautifulSoup, requests (won’t reach external), 30+ others — see docs for current list
Custom packagesCannot install (pip install not available)

Visualization

Matplotlib output is captured as an image and included in the response:

for part in resp.candidates[0].content.parts:
    if part.inline_data and part.inline_data.mime_type.startswith("image/"):
        # Plot image bytes available in part.inline_data.data
        with open("plot.png", "wb") as f:
            f.write(part.inline_data.data)

Other visualization libraries (Plotly, Seaborn) can render but only Matplotlib’s image capture is documented to round-trip back.

File input to code execution

You can pass files (PDF, CSV, image, audio) and the code can read them:

csv_file = client.files.upload(file="data.csv")
resp = client.models.generate_content(
    model="gemini-3.5-flash",
    contents=[
        "Load this CSV with pandas and show summary stats. Make a histogram of column 'price'.",
        csv_file,
    ],
    config=types.GenerateContentConfig(
        tools=[types.Tool(code_execution=types.ToolCodeExecution())],
    ),
)

File input ~1-2 MB max in this context (token-window constrained). For larger CSVs, sample first.

Billing

Per the docs: no additional charge for enabling code execution. Token usage:

  • Original prompt → input tokens
  • Generated code + execution result → intermediate tokens (billed as output)
  • Summary + final answer → output tokens

A run that generates 500 tokens of code + 2,000 tokens of result + 300-token summary costs ~2,800 output tokens. At Gemini 3.5 Flash’s $9 / MTok output, that’s ~$0.025 per code run.

When code execution helps vs hurts

Helps:

  • Exact math (Fibonacci, primes, statistics) — model is unreliable without execution
  • Data analysis on provided CSV / JSON
  • Chart generation
  • Algorithm verification
  • Calendar / date arithmetic
  • Unit conversions at precision

Hurts (per the docs caveat — “Enabling code execution can lead to regressions in other areas of model output”):

  • Simple Q&A — model may unnecessarily write code to “be sure”
  • Latency-sensitive UI — code execution adds seconds
  • Creative writing — code distracts the model

Practical: enable for analytical / quantitative tasks; disable for chat / creative / generative.

2. Google Search grounding

Enabling

resp = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="What's the latest news on the SpaceX Starship test?",
    config=types.GenerateContentConfig(
        tools=[types.Tool(google_search=types.GoogleSearch())],
    ),
)

The model decides when to search. Returns a normal text response plus groundingMetadata documenting the searches and sources.

Response structure

gm = resp.candidates[0].grounding_metadata
print(gm.web_search_queries)        # ["spacex starship test 2026", ...]
for chunk in gm.grounding_chunks:
    if chunk.web:
        print(chunk.web.uri, chunk.web.title)
for support in gm.grounding_supports:
    print(support.segment.start_index, support.segment.end_index,
          support.grounding_chunk_indices, support.confidence_scores)
print(gm.search_entry_point.rendered_content)  # HTML widget to display

Fields:

  • web_search_queries — the queries the model actually issued (often paraphrases of the user prompt)
  • grounding_chunks — sources, each with web.uri (URL) and web.title
  • grounding_supports — links text spans in the response to source indices, with confidence scores
  • search_entry_point.rendered_content — an HTML/CSS snippet to render the “Search suggestions” widget (required to display by Google’s grounding terms)

Rendering citations

Walk grounding_supports and inject footnote markers:

text = resp.candidates[0].content.parts[0].text
supports = sorted(gm.grounding_supports, key=lambda s: s.segment.end_index, reverse=True)
for s in supports:
    cites = ",".join(str(i+1) for i in s.grounding_chunk_indices)
    text = text[:s.segment.end_index] + f"[{cites}]" + text[s.segment.end_index:]

Then render the chunks list as a footnotes section.

Search widget requirement

Per Google’s grounding terms, when you display grounded output you must render the searchEntryPoint.renderedContent HTML widget (clickable “Search suggestions” chips that link to Google Search). The widget is provided pre-styled. Compliance requirement, not optional.

Billing — major change at Gemini 3

Per ai.google.dev/gemini-api/docs/pricing 2026-05:

Model generationBilling model
Gemini 3.xPer-query: each search the model decides to execute is one billable unit ($14 / 1,000 queries on paid tier, after the 5,000 monthly free queries on Gemini 3)
Gemini 2.5 and olderPer-prompt: any request that triggered grounding counted as one billable use, regardless of how many sub-searches happened

Practical impact: a single Gemini 3 prompt that triggers 5 searches now costs 5× a single Gemini 2.5 prompt with the same searches. Heavy agentic loops can hit grounding costs much faster on 3.x. Budget for it; consider routing pure factual Q&A to grounding-free models when freshness isn’t critical.

Quota / free tier

  • Gemini 3 models: 5,000 grounded queries / month free on paid tier
  • Beyond free: $14 per 1,000 queries
  • Gemini 2.5 / older: per-prompt — cheaper for heavy use

Best practices

  • Use grounding when you need fresh information (post-training-cutoff events, current prices, breaking news)
  • Don’t use grounding for evergreen knowledge — it adds latency + cost for no benefit
  • Inspect groundingMetadata.grounding_supports[].confidence_scores — low confidence (< 0.5) suggests the claim is weakly supported
  • Render the searchEntryPoint widget (compliance)

3. URL context tool

A separate hosted tool for fetching specific URLs without going through Google Search.

resp = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="Compare the documentation at https://example.com/a and https://example.com/b.",
    config=types.GenerateContentConfig(
        tools=[types.Tool(url_context=types.UrlContext())],
    ),
)

The model fetches the URLs (HTML rendered to text/markdown) and uses them in the response. Returns url_context_metadata listing the fetched URLs and statuses.

When to use vs grounding

NeedTool
Fresh information, no specific sourcegoogle_search
Compare / summarize specific URLs you knowurl_context
BothEnable both — they can be combined

URL context is also useful for “follow this link the user gave me” — the user provides URLs, the model fetches.

Limits

  • Max URLs per request: ~20 (observed; not strictly documented)
  • Max content per URL: token-window-bounded (~1M total context)
  • Failed fetches (404, paywall) surface in url_context_metadata with status

4. Combining tools

config=types.GenerateContentConfig(
    tools=[
        types.Tool(function_declarations=[my_custom_tool]),
        types.Tool(google_search=types.GoogleSearch()),
        types.Tool(code_execution=types.ToolCodeExecution()),
        types.Tool(url_context=types.UrlContext()),
    ],
)

Limitations on combinations as of 2026-05:

  • Code execution + grounding — supported. The model can search for context, then execute code on the findings.
  • Code execution + function calling — supported, but the model occasionally gets confused choosing between executing code itself vs calling out. Be explicit in the system prompt.
  • Grounding + structured output (response_schema)may not be supported simultaneously. Test for your use case; fall back to grounding-only with a manual structuring pass.

5. Cost summary across tools

ToolPer-invocation cost (beyond standard tokens)
code_execution$0 — pay only for tokens consumed
google_search (Gemini 3)$14 / 1,000 queries (after 5,000 free / month)
google_search (Gemini 2.5)per-prompt (lower for heavy use)
url_context$0 — pay only for tokens consumed
Custom function$0 — your function runs on your infra

6. Comparison to other vendors

CapabilityGeminiClaudeOpenAI
Hosted Python sandboxcode_execution — 30s, no net, Pythoncode_execution_* tool — 60s, opt-in libsCode Interpreter on Assistants / Responses
Web search groundinggoogle_search — Google indexweb_search_* toolWeb Search hosted tool
URL fetchurl_contextweb_fetch_* tool(via tools or custom)
Server-side billing surchargeSearch only ($14/1k on 3.x)Search $10/1kSearch add-on, varies
Combination friendlinessMostly free to mixMostly free to mixSome restrictions on Assistants vs Responses

7. Common pitfalls

  1. Forgetting to render searchEntryPoint — compliance violation under Google’s grounding terms. Always render.
  2. Cost surprise on Gemini 3 grounding — agentic loop triggers 10 searches per turn × 20 turns = 200 queries = ~$2.80 per session. Budget.
  3. Code execution timeout — 30s is short for matrix-heavy workloads. Pre-compute / cache when possible.
  4. No package install — code execution can’t pip install. If your task needs an exotic library, switch to a custom function calling out to your own sandbox.
  5. Grounding + structured output — combination is fragile; do them in two passes.
  6. url_context on auth-required URLs — fetcher has no cookies / OAuth. Fails on private content.
  7. Searches that the model doesn’t execute — model may decline to search if it thinks it knows the answer. Force with system prompt instructions like “Always search for current information about ” or use a function-call tool.
  8. Code that executes destructive ops — sandbox prevents actual harm (no filesystem persistence, no network), but generated code can os.remove files passed in. Treat input files as ephemeral.

8. Further reading