Menu
ai-agentsmcptutorialllm

How to Give Your AI Agent the Ability to Take Screenshots

SnapSharp Team·April 16, 2026·10 min read

AI agents can browse the web, run code, and call APIs — but most of them are blind. They work with raw text: HTML, JSON, scraped content. They can't see what a page actually looks like.

Giving your agent eyes changes what it can do. Vision-capable models (GPT-4o, Claude 3.5, Gemini 1.5) can analyze screenshots to detect UI regressions, read rendered text, understand layout, and extract data that isn't in the DOM.

This guide covers every method for adding screenshot capability to an AI agent.

Why agents need screenshots (not just HTML)

When an agent scrapes HTML, it gets the document structure. It doesn't get:

  • CSS-rendered visual layout
  • JavaScript-rendered content (SPAs, lazy-loaded images)
  • The actual pixel output the user sees
  • Visual context like colors, spacing, typography

A screenshot gives the model the ground truth: exactly what a human would see, regardless of how the page is built.

Use cases:

  • Visual QA: take a screenshot before and after a deployment, ask the model to identify any visual regressions
  • Competitive analysis: schedule screenshots of competitor pages, analyze pricing and feature changes
  • UI testing: ask the model to verify that a redesign renders correctly across breakpoints
  • Data extraction: when structured scraping fails, fall back to screenshot + vision model
  • Accessibility audits: check color contrast, text size, and layout issues visually

Method 1: MCP (Model Context Protocol)

MCP is the standard for connecting tools to Claude (and Claude Desktop/Cursor/Windsurf). SnapSharp ships a native MCP server:

// claude_desktop_config.json
{
  "mcpServers": {
    "snapsharp": {
      "command": "npx",
      "args": ["-y", "@snapsharp/mcp"],
      "env": {
        "SNAPSHARP_API_KEY": "sk_live_YOUR_KEY"
      }
    }
  }
}

After adding this, Claude can take screenshots as part of any task:

"Take a screenshot of staging.myapp.com and compare it to the production version at myapp.com. List any visual differences."

The MCP server exposes these tools to Claude:

  • screenshot — capture any URL
  • site_audit — extract design tokens and tech stack
  • og_image — generate social preview images
  • diff — visual diff between two URLs or images
  • create_monitor — set up scheduled screenshot monitoring

No code needed for MCP — just config. Claude handles the rest.

Method 2: LangChain tool

For Python-based agent frameworks, create a LangChain tool that wraps the SnapSharp API:

from langchain.tools import BaseTool
from pydantic import BaseModel, Field
from snapsharp import SnapSharp
import base64
import os

class ScreenshotInput(BaseModel):
    url: str = Field(description="The URL to screenshot")
    width: int = Field(default=1280, description="Viewport width in pixels")
    full_page: bool = Field(default=False, description="Capture full page height")

class ScreenshotTool(BaseTool):
    name: str = "screenshot"
    description: str = (
        "Take a screenshot of a website URL. Returns base64-encoded PNG image data. "
        "Use this when you need to visually inspect a web page, verify UI, or extract "
        "visual information that isn't available in HTML."
    )
    args_schema: type[BaseModel] = ScreenshotInput

    def _run(self, url: str, width: int = 1280, full_page: bool = False) -> str:
        client = SnapSharp(os.environ["SNAPSHARP_API_KEY"])
        image_bytes = client.screenshot(url=url, width=width, full_page=full_page)
        b64 = base64.b64encode(image_bytes).decode("utf-8")
        return f"data:image/png;base64,{b64}"

# Use with GPT-4o (vision-capable)
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate

llm = ChatOpenAI(model="gpt-4o", temperature=0)
tools = [ScreenshotTool()]

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a web analyst. When asked to analyze a website, use the screenshot tool to capture it first, then analyze the visual output."),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])

agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

result = executor.invoke({
    "input": "Screenshot https://linear.app and describe their pricing page design"
})

Method 3: OpenAI function calling

For direct OpenAI API usage, define the screenshot capability as a function:

import openai
import requests
import base64
import json
import os

client = openai.OpenAI()

# Tool definition
tools = [{
    "type": "function",
    "function": {
        "name": "take_screenshot",
        "description": "Take a screenshot of a web page. Returns the image as base64.",
        "parameters": {
            "type": "object",
            "properties": {
                "url": {
                    "type": "string",
                    "description": "The URL to capture"
                },
                "width": {
                    "type": "integer",
                    "description": "Viewport width in pixels (default: 1280)",
                    "default": 1280
                },
                "full_page": {
                    "type": "boolean",
                    "description": "Capture full page height",
                    "default": False
                }
            },
            "required": ["url"]
        }
    }
}]

def take_screenshot(url: str, width: int = 1280, full_page: bool = False) -> str:
    """Call SnapSharp API and return base64 image."""
    params = {"url": url, "width": width, "full_page": str(full_page).lower(), "format": "png"}
    res = requests.get(
        "https://api.snapsharp.dev/v1/screenshot",
        params=params,
        headers={"Authorization": f"Bearer {os.environ['SNAPSHARP_API_KEY']}"}
    )
    res.raise_for_status()
    return base64.b64encode(res.content).decode("utf-8")

def run_agent(user_message: str):
    messages = [{"role": "user", "content": user_message}]

    while True:
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=tools,
        )
        msg = response.choices[0].message

        if msg.tool_calls:
            messages.append(msg)
            for call in msg.tool_calls:
                args = json.loads(call.function.arguments)
                b64_image = take_screenshot(**args)
                messages.append({
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": [
                        {
                            "type": "image_url",
                            "image_url": {"url": f"data:image/png;base64,{b64_image}"}
                        }
                    ]
                })
        else:
            return msg.content

# Example usage
result = run_agent("Screenshot https://vercel.com/pricing and tell me what their cheapest paid plan includes")
print(result)

Method 4: Anthropic tool use (Claude API)

Claude handles images natively via the messages API. Define screenshot as a tool:

import anthropic
import requests
import base64
import json
import os

client = anthropic.Anthropic()

tools = [{
    "name": "screenshot",
    "description": "Capture a screenshot of any URL. Use this to visually inspect web pages.",
    "input_schema": {
        "type": "object",
        "properties": {
            "url": {"type": "string", "description": "URL to screenshot"},
            "width": {"type": "integer", "description": "Viewport width (default 1280)"},
            "full_page": {"type": "boolean", "description": "Capture full page height"}
        },
        "required": ["url"]
    }
}]

def take_screenshot(url: str, width: int = 1280, full_page: bool = False) -> str:
    res = requests.get(
        "https://api.snapsharp.dev/v1/screenshot",
        params={"url": url, "width": width, "full_page": str(full_page).lower()},
        headers={"Authorization": f"Bearer {os.environ['SNAPSHARP_API_KEY']}"}
    )
    res.raise_for_status()
    return base64.standard_b64encode(res.content).decode("utf-8")

def run_agent(user_message: str) -> str:
    messages = [{"role": "user", "content": user_message}]

    while True:
        response = client.messages.create(
            model="claude-opus-4-6",
            max_tokens=4096,
            tools=tools,
            messages=messages,
        )

        if response.stop_reason == "tool_use":
            tool_results = []
            for block in response.content:
                if block.type == "tool_use":
                    b64 = take_screenshot(**block.input)
                    tool_results.append({
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": [{
                            "type": "image",
                            "source": {"type": "base64", "media_type": "image/png", "data": b64}
                        }]
                    })
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": tool_results})
        else:
            return next(b.text for b in response.content if hasattr(b, "text"))

result = run_agent("Visit https://github.com/trending and list the top 5 trending repositories")
print(result)

Method 5: LlamaIndex tool

For LlamaIndex-based agents:

from llama_index.core.tools import FunctionTool
from snapsharp import SnapSharp
import base64
import os

snap = SnapSharp(os.environ["SNAPSHARP_API_KEY"])

def screenshot_website(url: str, full_page: bool = False) -> str:
    """
    Take a screenshot of a website and return it as base64 PNG data.
    Use this when you need to visually inspect a web page.

    Args:
        url: The URL to capture
        full_page: Whether to capture the full page height (default: False)
    """
    image = snap.screenshot(url=url, width=1280, full_page=full_page)
    return f"data:image/png;base64,{base64.b64encode(image).decode()}"

screenshot_tool = FunctionTool.from_defaults(fn=screenshot_website)

Practical patterns

Visual regression testing

import base64, os
from snapsharp import SnapSharp

snap = SnapSharp(os.environ["SNAPSHARP_API_KEY"])

def check_for_regressions(staging_url: str, prod_url: str) -> dict:
    """Compare staging vs production and return a diff report."""
    diff = snap.diff(url1=staging_url, url2=prod_url)
    return {
        "diff_percent": diff["diffPercent"],
        "has_regression": diff["diffPercent"] > 1.0,
        "diff_image_url": diff.get("diffImageUrl"),
    }

result = check_for_regressions(
    "https://staging.yourapp.com",
    "https://yourapp.com"
)
print(f"Visual diff: {result['diff_percent']:.2f}% — regression: {result['has_regression']}")

Async batch for large-scale analysis

import asyncio
from snapsharp import SnapSharp
import os

snap = SnapSharp(os.environ["SNAPSHARP_API_KEY"])

async def analyze_competitor_pages(urls: list[str]) -> list[dict]:
    """Screenshot and analyze multiple competitor pages."""
    # Submit async job
    job = snap.async_screenshot({
        "urls": urls,
        "width": 1280,
        "format": "png",
        "callback_url": "https://yourapi.com/webhook/screenshots"
    })

    print(f"Job submitted: {job['id']}{len(urls)} pages")
    return job

# Submit 50 URLs, get webhook when done
asyncio.run(analyze_competitor_pages([
    "https://competitor1.com/pricing",
    "https://competitor2.com/pricing",
    # ...
]))

Rate limits and performance

  • Free plan: 5 req/min, 100 req/month
  • Starter: 30 req/min, 5,000 req/month
  • Growth: 60 req/min, 25,000 req/month

For agents making many screenshot calls: enable caching with cache=true. Repeated calls for the same URL return in ~50ms from Redis.

# Cache screenshot results — repeated calls are instant
image = snap.screenshot(url="https://example.com", cache=True, cache_ttl=3600)

Getting started

# Install the Python SDK
pip install snapsharp

# Or use the Node.js SDK
npm install @snapsharp/sdk

Sign up at snapsharp.dev/sign-up — 100 free screenshots/month, no credit card required.

The MCP server for Claude Desktop is available at npx -y @snapsharp/mcp — see the MCP setup docs for the full config.

How to Give Your AI Agent the Ability to Take Screenshots — SnapSharp Blog