Google's Agent Development Kit (ADK) hit 2.0 GA in early 2026, shipping graph-based workflows, \ multi-agent fan-out/fan-in, and first-class Gemini integration. If you're already running Gemini models in production, \ ADK is the natural glue for your agentic workflows. The one gap: ADK doesn't ship with browser access. Anchor fills it.
This guide shows you how to pair ADK with Anchor's managed cloud browsers \ to build a research agent that browses the web in parallel, returning structured results back into your ADK agent graph.
Why Google ADK?
ADK gives you three things that matter for production browser agents:
- Graph workflows – deterministic fan-out/fan-in patterns let you spawn N browser sessions and merge results cleanly.
- Multi-agent architecture – delegate browsing to specialized sub-agents while a coordinator handles reasoning.
- Gemini-native – direct access to Gemini 2.5 Pro's 1M-token context window for summarizing long scraped pages.
Setup
pip install google-adk anchor-browser playwright
playwright install chromium
export ANCHOR_API_KEY="your_anchor_key"
export GOOGLE_API_KEY="your_google_key"
Building a Browser Tool
ADK tools are plain Python functions — pass them to Agent(tools=[...]) and ADK infers the schema \
from type hints and the docstring automatically.
import os
from anchor_browser import AnchorClient
from playwright.sync_api import sync_playwright
anchor = AnchorClient(api_key=os.environ["ANCHOR_API_KEY"])
def browse_url(url: str) -> dict:
"Navigate to a URL and return the page title and body text (first 4 000 chars)."
session = anchor.sessions.create(
proxy_country="us",
options={"adblock": True},
)
pw = sync_playwright().start()
browser = pw.chromium.connect_over_cdp(session.ws_endpoint)
page = browser.contexts[0].pages[0]
page.goto(url, wait_until="domcontentloaded")
title = page.title()
body = page.locator("body").inner_text()[:4000]
browser.close()
pw.stop()
anchor.sessions.stop(session.id)
return {"title": title, "content": body, "url": url}
A few things worth noting:
- Each
anchor.sessions.create()spins up an isolated cloud browser with a real IP and fingerprint — anti-bot systems see it as a normal user. - We cap
inner_textat 4,000 characters so the Gemini context budget stays manageable per tool call. proxy_country="us"routes the session through a US residential IP — useful when target sites geo-gate content.options={"adblock": True}strips cookie banners that waste tokens and break navigation.anchor.sessions.stop()frees the session immediately; without it you hold it open until timeout.
Your First ADK Browser Agent
from google.adk.agents.llm_agent import Agent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
root_agent = Agent(
model="gemini-2.5-flash",
name="web_researcher",
description="A research agent that browses the web and summarizes findings.",
instruction=(
"You are a research assistant. When given a topic, "
"browse specific URLs for relevant information "
"and return a concise summary with key facts."
),
tools=[browse_url],
)
session_service = InMemorySessionService()
runner = Runner(
agent=root_agent,
app_name="anchor_researcher",
session_service=session_service,
)
session = session_service.create_session(
app_name="anchor_researcher",
user_id="user_01",
)
response = runner.run(
user_id="user_01",
session_id=session.id,
new_message=types.Content(
role="user",
parts=[types.Part(text="Summarize the latest Playwright release notes.")],
),
)
for event in response:
if event.is_final_response():
print(event.content.parts[0].text)
The agent decides on its own which URL to fetch, calls browse_url, and synthesizes the result — you never hardcode the URL.
Parallel Browsing with ADK Graph Workflows
ADK 2.0 graph workflows support fan-out. Spawn multiple Anchor sessions simultaneously and merge results with ParallelAgent:
from google.adk.agents import ParallelAgent, SequentialAgent
# Sub-agent that browses one competitor page
browser_agent = Agent(
model="gemini-2.5-flash",
name="browser_agent",
instruction="Browse the given URL and return all pricing information found.",
tools=[browse_url],
)
# Coordinator: run three browser_agents in parallel, then a sequentially chained step
coordinator = SequentialAgent(
name="pricing_researcher",
sub_agents=[
ParallelAgent(
name="parallel_browsers",
sub_agents=[browser_agent, browser_agent, browser_agent],
)
],
)
Each browser_agent instance gets its own Anchor session — fully isolated fingerprints, separate IP addresses, no shared state.
Structured Output with Pydantic
For pipelines that need typed data, combine ADK's tool calling with Pydantic validation in the tool itself:
from pydantic import BaseModel
from typing import List
class PricingTier(BaseModel):
plan: str
monthly_usd: float
features: List[str]
def scrape_pricing(url: str) -> dict:
"Fetch a pricing page and return tiers as structured JSON."
raw = browse_url(url)
# Ask a lightweight model to extract structure from raw text
from google.genai import Client
client = Client()
resp = client.models.generate_content(
model="gemini-2.5-flash",
contents=f"Extract pricing tiers as JSON matching this schema: {PricingTier.schema()}\n\n{raw['content']}",
)
return json.loads(resp.text)
Production Tips
- Scope sessions to runs. Create a fresh Anchor session per agent run and close it in a
finallyblock to avoid session bleed across concurrent jobs. - Use
gemini-2.5-flashover Pro for high-throughput tasks. The latency improvement is significant when you're fanning out across 10+ pages simultaneously. - Cap concurrency. Anchor handles parallel sessions gracefully, but your Google API quota limits the number of simultaneous ADK tool-call evaluations.
- Swap
InMemorySessionServicefor a database-backed store in production — ADK supports PostgreSQL and Firestore backends for persistent multi-turn workflows.
What's Next
Try Anchor free and run your first ADK browser agent in minutes →



