
Building Agentic Web Browsing Tools: Integrating LLMs with Headless Browser Automation for Real-Time Data Grounding
Learn how to combine LLMs with headless browsers for grounded, agentic web scraping—complete with code examples, architecture patterns, and best practices for reliable data extraction.
AlterLab handles this automatically — scrape any URL with one API call. No infrastructure required.
Try it freeTL;DR
Agentic web browsing combines an LLM planner with a headless browser executor. The LLM decides what to click or type based on live DOM context, while the browser performs actions and returns grounded observations. This loop yields reliable, real-time data extraction without brittle selectors.
Why Agentic Browsing Beats Traditional Scraping
Classic scrapers rely on static selectors (CSS, XPath) that break when a site updates its layout. An agentic approach replaces fixed selectors with a reasoning loop: the LLM observes the current page, chooses an action, and the browser enacts it. Because each step is grounded in the actual DOM, the system adapts to changes, handles dynamic content, and can recover from unexpected modals or redirects.
The core loop looks like this:
- Observe – extract relevant text, attributes, or screenshots from the browser.
- Reason – feed the observation to an LLM with a prompt that asks for the next action (e.g., “click the button labeled ‘Load more’” or “extract the price”).
- Act – translate the LLM’s output into a Playwright/Puppeteer command.
- Loop – repeat until a termination condition (data collected, timeout, or max steps).
This pattern mirrors how humans browse: look, decide, act, look again.
Architecture Overview
Below is a simplified data flow for an agentic scraper built on top of AlterLab’s headless browser API.
AlterLab’s API handles the heavy lifting: automatic retries, proxy rotation, and anti-bot mitigation, so your agentic loop focuses on logic rather than infrastructure.
Grounding the LLM: What to Send as Observation
Sending the full HTML wastes tokens and confuses the model. Instead, extract a concise representation:
- Visible text –
page.evaluate(() => document.body.innerText)trimmed to first 2000 characters. - Key attributes – for interactive elements, pull
id,aria-label,innerText, andtype. - Optional screenshot – a base64‑encoded thumbnail (≤ 200 KB) can help the model discern layout when text alone is ambiguous.
Example observation JSON:
{
"url": "https://example.com/products",
"visible_text": "Showing 1‑24 of 89 results… Load more",
"elements": [
{"tag":"button","id":"load-more","aria-label":"Load more results","innerText":"Load more"},
{"tag":"span","class":"price","innerText":"$29.99"}
]
}Keep each observation under ~1500 tokens to stay within typical LLM context limits.
Prompt Design for Reliable Actions
A well‑crafted prompt dramatically reduces hallucinations. Use a strict output format (e.g., JSON) and few‑shot examples.
System prompt:
You are a web‑browsing agent. Given the current page observation and the user goal, return the next action as a JSON object.
Allowed actions:
- { "type": "click", "selector": "<css selector>" }
- { "type": "type", "selector": "<css selector>", "text": "<string>" }
- { "type": "extract", "selector": "<css selector>", "attribute": "innerText|href|value" }
- { "type": "wait", "milliseconds": <number> }
- { "type": "done" }
If unsure, return { "type": "wait", "milliseconds": 1000 }.Provide 2‑3 short examples in the prompt showing correct JSON for clicking a button and extracting text.
Code Example: Python SDK
Below is a complete, runnable example using AlterLab’s Python SDK and OpenAI’s GPT‑4o (or any compatible LLM). The script searches a generic listings page and extracts all item titles.
import alterlab
import json
import openai
import os
import time
# Initialize clients
browser = alterlab.Client(os.getenv("ALTERLAB_API_KEY"))
openai.api_key = os.getenv("OPENAI_API_KEY")
GOAL = "Extract the titles of all items on the page"
MAX_STEPS = 20
def observe(page):
"""Return a compact JSON observation for the LLM."""
obs = page.evaluate("""() => {
const inner = document.body.innerText.slice(0, 1500);
const buttons = Array.from(document.querySelectorAll('button, [role="button"]'))
.map(b => ({tag:b.tagName.toLowerCase(), id:b.id||'', 'aria-label':b.getAttribute('aria-label')||'', innerText:b.innerText.slice(0,50)}));
const inputs = Array.from(document.querySelectorAll('input, textarea, select'))
.map(i => ({tag:i.tagName.toLowerCase(), id:i.id||'', 'aria-label':i.getAttribute('aria-label')||'', innerText:i.value||''}));
return {url: location.href, visible_text: inner, elements: [...buttons, ...inputs]};
}""")
return obs
def llm_decide(obs, goal):
prompt = f"""You are a web‑browsing agent.
Goal: {goal}
Observation: {json.dumps(obs)}
Return ONLY a JSON action as described."""
response = openai.chat.completions.create(
model="gpt-4o",
messages=[{"role":"system","content":"You output JSON actions only."},
{"role":"user","content":prompt}],
temperature=0,
max_tokens=200,
)
content = response.choices[0].message.content.strip()
# Expect pure JSON; fallback to wait if malformed
try:
return json.loads(content)
except json.JSONDecodeError:
return {"type":"wait","milliseconds":1000}
def run():
# Start a headless session with AlterLab (smart rendering enabled)
session = browser.sessions.create({
"url": "https://example.com/listings",
"render": True,
"wait_for": "networkidle"
})
page = session.page
for step in range(MAX_STEPS):
obs = observe(page)
action = llm_decide(obs, GOAL)
print(f"Step {step}: {action}")
if action.get("type") == "click":
selector = action["selector"]
page.click(selector)
page.wait_for_load_state("networkidle")
elif action.get("type") == "type":
selector = action["selector"]
text = action["text"]
page.fill(selector, text)
page.keyboard.press("Enter")
page.wait_for_load_state("networkidle")
elif action.get("type") == "extract":
selector = action["selector"]
attr = action.get("attribute","innerText")
value = page.evaluate(f"""() => {{
const el = document.querySelector("{selector}");
return el ? el.{attr} : null;
}}""")
print(f"Extracted: {value}")
elif action.get("type") == "wait":
time.sleep(action.get("milliseconds",1000)/1000)
elif action.get("type") == "done":
break
else:
# unknown action → wait
time.sleep(1)
browser.sessions.delete(session.id)
if __name__ == "__main__":
run()Highlighted lines: client initialization, observation extraction, LLM call, and action dispatch.
Code Example: cURL Equivalent
You can drive the same loop from Bash by calling AlterLab’s REST endpoints and a local LLM API (e.g., Ollama). This shows the protocol‑level flow.
#!/usr/bin/env bash
API_KEY="${ALTERLAB_API_KEY}"
LLM_URL="http://localhost:11434/api/generate" # Ollama endpoint
GOAL="Extract all product prices"
MAX_STEPS=15
# 1. Create session
SESSION_ID=$(curl -s -X POST "https://api.alterlab.io/v1/sessions" \
-H "X-API-Key: $API_KEY" \
-d '{"url":"https://example.com/Was this article helpful?
Frequently Asked Questions
Related Articles
![[title]](/_next/image?url=https%3A%2F%2Fimages.pexels.com%2Fphotos%2F7870693%2Fpexels-photo-7870693.jpeg%3Fauto%3Dcompress%26cs%3Dtinysrgb%26w%3D800%26fit%3Dcrop&w=1920&q=75)
[title]
[excerpt]
Herald Blog Service

How to Scrape Home Depot Data: Complete Guide for 2026
Learn how to scrape Home Depot using Python and Node.js. This guide covers bypassing anti-bot protections and extracting structured e-commerce data at scale.
Herald Blog Service

How to Scrape Lowe's Data: Complete Guide for 2026
Learn how to scrape Lowe's e-commerce data efficiently using Python and Node.js. This guide covers bypassing anti-bot protections and using AI for data extraction.
Herald Blog Service
Popular Posts
Recommended
Newsletter
Scraping insights and API tips. No spam.
Recommended Reading

How to Scrape AliExpress: Complete Guide for 2026

Why Your Headless Browser Gets Detected (and How to Fix It)

AlterLab vs Firecrawl: Which Scraping API Is Better in 2026?

How to Scrape Twitter/X Data: Complete Guide for 2026

How to Scrape Cloudflare-Protected Sites in 2026
Stay in the Loop
Get scraping insights, API tips, and platform updates. No spam — we only send when we have something worth reading.
Explore AlterLab
Web Scraping API Resources
Part of the Web Scraping API Documentation cluster
Complete API reference with 5-tier auto-escalation — Curl to challenge resolution.
Pillar pageConfigure Tier 4 browser rendering for SPAs and dynamic content.
Scrape pages behind login using session management.
Real success rates and cost data across all 5 tiers.
MCP Server, Python SDK, and Firecrawl-compatible API for AI agent workflows.