NewIntroducing semantic snapshotsPair every capture with structured DOM data →

For product and pricing teams

Read a competitor's plan names and prices as numbers

Read a competitor's plan names and prices off the rendered page as values, and keep the history yourself.

The problem

A competitor drops a tier, renames another and raises its entry price. A text comparison of their pricing page says that something changed somewhere in a long block of copy; what the pricing team needs is the table: which plan, from what, to what.

How domscout handles it

Two extract fields read the plan names as a list and the prices with type number and all: true, which drops currency symbols and thousands separators before parsing. Run the request on your schedule and store each result, and comparing two rows of numbers tells you exactly what moved. Prices that appear only after JavaScript runs are there to read because the page is rendered, and a click action can flip a monthly and annual toggle first.

Where it shows up

  • A weekly table of every competitor's plans and prices.
  • An alert when an entry-level price moves.
  • Price history for a pricing review.

The request

POST /scrape. extract starts at Pro and costs 2 credits a page. A monitor can watch the same page and alert on any change to its text, but monitors compare text, links and title rather than extracted values, so the price comparison stays in your code.

cURL
curl -X POST https://api.domscout.io/scrape \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://competitor.example.com/pricing",
    "extractMarkdown": false,
    "extract": {
      "fields": {
        "plans": {"selector": ".plan-name", "type": "list"},
        "prices": {"selector": ".plan-price", "type": "number", "all": true}
      }
    }
  }'
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://competitor.example.com/pricing",
    extractMarkdown: false,
    extract: {
      fields: {
        plans: { selector: ".plan-name", type: "list" },
        prices: { selector: ".plan-price", type: "number", all: true }
      }
    }
  }),
});
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://competitor.example.com/pricing",
        "extractMarkdown": False,
        "extract": {
            "fields": {
                "plans": {"selector": ".plan-name", "type": "list"},
                "prices": {
                    "selector": ".plan-price",
                    "type": "number",
                    "all": True
                }
            }
        }
    },
)
print(response.json()["analysis"])
Go
package main

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

func main() {
	body, _ := json.Marshal(map[string]any{
		"url": "https://competitor.example.com/pricing",
		"extractMarkdown": false,
		"extract": map[string]any{
			"fields": map[string]any{
				"plans": map[string]any{"selector": ".plan-name", "type": "list"},
				"prices": map[string]any{
					"selector": ".plan-price",
					"type": "number",
					"all": true,
				},
			},
		},
	})
	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://competitor.example.com/pricing',
        'extractMarkdown' => false,
        'extract' => [
            'fields' => [
                'plans' => ['selector' => '.plan-name', 'type' => 'list'],
                'prices' => [
                    'selector' => '.plan-price',
                    'type' => 'number',
                    'all' => true
                ]
            ]
        ]
    ]),
]);
$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://competitor.example.com/pricing",
    extractMarkdown: false,
    extract: {
      fields: {
        plans: { selector: ".plan-name", type: "list" },
        prices: { selector: ".plan-price", type: "number", all: true }
      }
    }
  }.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://competitor.example.com/pricing",
                "extractMarkdown": false,
                "extract": {
                    "fields": {
                        "plans": {"selector": ".plan-name", "type": "list"},
                        "prices": {
                            "selector": ".plan-price",
                            "type": "number",
                            "all": true
                        }
                    }
                }
            }
            """;
        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://competitor.example.com/pricing",
    extractMarkdown = false,
    extract = new {
        fields = new {
            plans = new { selector = ".plan-name", type = "list" },
            prices = new {
                selector = ".plan-price",
                type = "number",
                all = true
            }
        }
    }
});
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(result.GetProperty("analysis"));

Go further

More in Monitoring and alerts: Website change monitoring · A feed for a site without RSS · Minimum advertised price checks · New job posting alerts · Vendor changelog watching · Tender, grant and notice alerts · All use cases

Give your product a browser.

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