NewIntroducing semantic snapshotsPair every capture with structured DOM data →

For QA engineers and automation builders

Get ranked, stable selectors for every element on a page

Get every element on the rendered page with ranked selector candidates, from test IDs to roles and names.

The problem

A test written against .btn-3a7f breaks the next time the styles are rebuilt. Writing good locators means opening the developer tools for every element and guessing which attribute will still be there next month.

How domscout handles it

A semantic snapshot lists the page's elements with their role, accessible name, text and form state, and gives each one ranked selector candidates: CSS, XPath, text, ARIA role and name, ID, name, label and test ID. stableKey identifies an element by persistent attributes or its position in the structure rather than its text, so it survives copy changes. Use the snapshot to choose locators, then use them as action targets, where a locator that matches nothing or more than one element fails with its own code.

Where it shows up

  • Seeding a new end-to-end suite with locators.
  • Choosing selectors for a scraper or an extract request.
  • Finding elements that lack a test ID or an accessible name.

The request

POST /scrape. semanticSnapshot starts at Pro, and each page costs 2 credits. Through the MCP server, domscout_inspect_page gives an assistant the same snapshot before it automates a page.

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

response = requests.post(
    "https://api.domscout.io/scrape",
    headers={"x-api-key": "YOUR_API_KEY"},
    json={
        "url": "https://www.example.com/signup",
        "extractMarkdown": False,
        "semanticSnapshot": {"detail": "summary", "selectorBundles": True, "maxNodes": 300}
    },
)
print(response.json()["analysis"])
Go
package main

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

func main() {
	body, _ := json.Marshal(map[string]any{
		"url": "https://www.example.com/signup",
		"extractMarkdown": false,
		"semanticSnapshot": map[string]any{
			"detail": "summary",
			"selectorBundles": true,
			"maxNodes": 300,
		},
	})
	req, _ := http.NewRequest("POST", "https://api.domscout.io/scrape", 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()

	var result map[string]any
	json.NewDecoder(res.Body).Decode(&result)
	fmt.Println(result["analysis"])
}
PHP
<?php
$ch = curl_init('https://api.domscout.io/scrape');
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/signup',
        'extractMarkdown' => false,
        'semanticSnapshot' => [
            'detail' => 'summary',
            'selectorBundles' => true,
            'maxNodes' => 300
        ]
    ]),
]);
$response = curl_exec($ch);
if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}
$result = json_decode($response, true);
print_r($result['analysis']);
Ruby
require "json"
require "net/http"

response = Net::HTTP.post(
  URI("https://api.domscout.io/scrape"),
  {
    url: "https://www.example.com/signup",
    extractMarkdown: false,
    semanticSnapshot: { detail: "summary", selectorBundles: true, maxNodes: 300 }
  }.to_json,
  "Content-Type" => "application/json",
  "x-api-key" => "YOUR_API_KEY"
)
puts JSON.parse(response.body)["analysis"]
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/signup",
                "extractMarkdown": false,
                "semanticSnapshot": {
                    "detail": "summary",
                    "selectorBundles": true,
                    "maxNodes": 300
                }
            }
            """;
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.domscout.io/scrape"))
            .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 System.Text.Json;

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

var response = await client.PostAsJsonAsync("https://api.domscout.io/scrape", new {
    url = "https://www.example.com/signup",
    extractMarkdown = false,
    semanticSnapshot = new { detail = "summary", selectorBundles = true, maxNodes = 300 }
});
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(result.GetProperty("analysis"));

Go further

More in Testing and QA: Responsive layout checks · Visual regression testing · JavaScript error checks · Signup and checkout flow checks · Hover, focus and dark mode screenshots · Localization screenshots · Unlabelled control checks · A screenshot of every step · Embedded widget checks · Screenshots for support tickets · Ad landing page checks · Before and after hydration · Print layout checks · All use cases

Give your product a browser.

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