NewIntroducing semantic snapshotsPair every capture with structured DOM data →

For agents that need to see the page

Give a vision model the screenshot and a map of what is on it

Send a model the picture of the page together with each element's position, role, name and selectors, from one capture.

The problem

Some questions are about layout: which plan is highlighted, whether the error banner is showing, what the button next to the price says. Markdown loses that. A screenshot keeps it, but a model that answers "click the blue button on the right" has given you a description, not something you can act on.

How domscout handles it

A capture with semanticSnapshot returns the screenshot and, under analysis.semanticSnapshot, the page's elements with their role, accessible name, visible text and form state, each with its box in CSS pixels and in screenshot pixels and a set of ranked selector candidates. Give the model the image and the element list, and it can answer with an element's ID from this snapshot, which your code maps back to a selector for the next request. IDs belong to one snapshot; carry the selectors, not the IDs, between requests.

Where it shows up

  • A browsing agent that decides what to click from the picture and acts on a real element.
  • Visual checks a model performs on a page, such as whether a banner is shown.
  • A model's answer about a page tied to elements that actually exist.

The request

POST /screenshot. semanticSnapshot starts at Pro and adds 1 credit, so a capture costs 2. Summary detail comes back in the same response; full detail is large enough that it runs as a job. Through the MCP server, domscout_inspect_page gives an assistant the same snapshot.

cURL
curl -X POST https://api.domscout.io/screenshot \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.example.com/pricing",
    "responseType": "json",
    "semanticSnapshot": {"detail": "summary", "maxNodes": 500}
  }'
Node.js
const response = await fetch("https://api.domscout.io/screenshot", {
  method: "POST",
  headers: { "Content-Type": "application/json", "x-api-key": "YOUR_API_KEY" },
  body: JSON.stringify({
    url: "https://www.example.com/pricing",
    responseType: "json",
    semanticSnapshot: { detail: "summary", maxNodes: 500 }
  }),
});
console.log(await response.json());
Python
import requests

response = requests.post(
    "https://api.domscout.io/screenshot",
    headers={"x-api-key": "YOUR_API_KEY"},
    json={
        "url": "https://www.example.com/pricing",
        "responseType": "json",
        "semanticSnapshot": {"detail": "summary", "maxNodes": 500}
    },
)
print(response.json())
Go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	body, _ := json.Marshal(map[string]any{
		"url": "https://www.example.com/pricing",
		"responseType": "json",
		"semanticSnapshot": map[string]any{"detail": "summary", "maxNodes": 500},
	})
	req, _ := http.NewRequest("POST", "https://api.domscout.io/screenshot", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("x-api-key", "YOUR_API_KEY")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	raw, _ := io.ReadAll(res.Body)
	fmt.Println(string(raw))
}
PHP
<?php
$ch = curl_init('https://api.domscout.io/screenshot');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'x-api-key: YOUR_API_KEY'],
    CURLOPT_POSTFIELDS => json_encode([
        'url' => 'https://www.example.com/pricing',
        'responseType' => 'json',
        'semanticSnapshot' => ['detail' => 'summary', 'maxNodes' => 500]
    ]),
]);
$response = curl_exec($ch);
if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}
echo $response;
Ruby
require "json"
require "net/http"

response = Net::HTTP.post(
  URI("https://api.domscout.io/screenshot"),
  {
    url: "https://www.example.com/pricing",
    responseType: "json",
    semanticSnapshot: { detail: "summary", maxNodes: 500 }
  }.to_json,
  "Content-Type" => "application/json",
  "x-api-key" => "YOUR_API_KEY"
)
puts response.body
Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Capture {
    public static void main(String[] args) throws Exception {
        String body = """
            {
                "url": "https://www.example.com/pricing",
                "responseType": "json",
                "semanticSnapshot": {"detail": "summary", "maxNodes": 500}
            }
            """;
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.domscout.io/screenshot"))
            .header("Content-Type", "application/json")
            .header("x-api-key", "YOUR_API_KEY")
            .POST(HttpRequest.BodyPublishers.ofString(body))
            .build();
        HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}
C#
using System.Net.Http.Json;

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY");

var response = await client.PostAsJsonAsync("https://api.domscout.io/screenshot", new {
    url = "https://www.example.com/pricing",
    responseType = "json",
    semanticSnapshot = new { detail = "summary", maxNodes = 500 }
});
Console.WriteLine(await response.Content.ReadAsStringAsync());

Go further

More in AI and agents: Web access for AI agents · llms.txt from your docs · Rendering generated HTML · Coding agents checking their work · Newsletter curation · FAQ drafts from documentation · All use cases

Give your product a browser.

Get clean web content and visual proof into your workflow in minutes.