NewIntroducing semantic snapshotsPair every capture with structured DOM data →

For journalists and researchers

Catch the statement that was quietly edited after publication

Watch a published page, keep the picture and the text of every version, and get told when the wording changes.

The problem

A press release loses a sentence, a public statement softens a commitment, an article's correction never gets a note. Unless someone saved the original, the edit leaves no trace, and the people who noticed it cannot show it.

How domscout handles it

A monitor checks the page on a schedule and compares its rendered text and title with the previous run. When the wording changes, a signed webhook names both captures. Each run is saved with a full-page image and the page's Markdown, so the two versions can be compared line by line and shown as they appeared, each with the date it was captured.

Where it shows up

  • A watch on the statements, policies or articles you have reported on.
  • A version history of a page whose wording matters.
  • Dated before-and-after images to publish alongside a story.

The request

POST /monitors. Monitors start at Pro: 10 monitors, checked as often as every 60 minutes. Business allows 100 every 15 minutes and Enterprise 500 every 5. Each run is billed as a capture; creating and managing a monitor is free. fullPage adds 1 credit to each run. Saved captures are kept for 30 days on Pro, 90 on Business and 365 on Enterprise. Download the versions you need to keep longer.

cURL
curl -X POST https://api.domscout.io/monitors \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Statement on service changes",
    "targetUrl": "https://www.example.gov/news/statement",
    "intervalMinutes": 60,
    "notifyWebhookUrl": "https://your-app.example/hooks/domscout",
    "checkMarkdown": true,
    "checkTitle": true,
    "checkLinks": false,
    "captureParams": {"fullPage": true}
  }'
Node.js
const response = await fetch("https://api.domscout.io/monitors", {
  method: "POST",
  headers: { "Content-Type": "application/json", "x-api-key": "YOUR_API_KEY" },
  body: JSON.stringify({
    name: "Statement on service changes",
    targetUrl: "https://www.example.gov/news/statement",
    intervalMinutes: 60,
    notifyWebhookUrl: "https://your-app.example/hooks/domscout",
    checkMarkdown: true,
    checkTitle: true,
    checkLinks: false,
    captureParams: { fullPage: true }
  }),
});
console.log(await response.json());
Python
import requests

response = requests.post(
    "https://api.domscout.io/monitors",
    headers={"x-api-key": "YOUR_API_KEY"},
    json={
        "name": "Statement on service changes",
        "targetUrl": "https://www.example.gov/news/statement",
        "intervalMinutes": 60,
        "notifyWebhookUrl": "https://your-app.example/hooks/domscout",
        "checkMarkdown": True,
        "checkTitle": True,
        "checkLinks": False,
        "captureParams": {"fullPage": True}
    },
)
print(response.json())
Go
package main

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

func main() {
	body, _ := json.Marshal(map[string]any{
		"name": "Statement on service changes",
		"targetUrl": "https://www.example.gov/news/statement",
		"intervalMinutes": 60,
		"notifyWebhookUrl": "https://your-app.example/hooks/domscout",
		"checkMarkdown": true,
		"checkTitle": true,
		"checkLinks": false,
		"captureParams": map[string]any{"fullPage": true},
	})
	req, _ := http.NewRequest("POST", "https://api.domscout.io/monitors", 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/monitors');
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([
        'name' => 'Statement on service changes',
        'targetUrl' => 'https://www.example.gov/news/statement',
        'intervalMinutes' => 60,
        'notifyWebhookUrl' => 'https://your-app.example/hooks/domscout',
        'checkMarkdown' => true,
        'checkTitle' => true,
        'checkLinks' => false,
        'captureParams' => ['fullPage' => true]
    ]),
]);
$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/monitors"),
  {
    name: "Statement on service changes",
    targetUrl: "https://www.example.gov/news/statement",
    intervalMinutes: 60,
    notifyWebhookUrl: "https://your-app.example/hooks/domscout",
    checkMarkdown: true,
    checkTitle: true,
    checkLinks: false,
    captureParams: { fullPage: true }
  }.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 = """
            {
                "name": "Statement on service changes",
                "targetUrl": "https://www.example.gov/news/statement",
                "intervalMinutes": 60,
                "notifyWebhookUrl": "https://your-app.example/hooks/domscout",
                "checkMarkdown": true,
                "checkTitle": true,
                "checkLinks": false,
                "captureParams": {"fullPage": true}
            }
            """;
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.domscout.io/monitors"))
            .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/monitors", new {
    name = "Statement on service changes",
    targetUrl = "https://www.example.gov/news/statement",
    intervalMinutes = 60,
    notifyWebhookUrl = "https://your-app.example/hooks/domscout",
    checkMarkdown = true,
    checkTitle = true,
    checkLinks = false,
    captureParams = new { fullPage = true }
});
Console.WriteLine(await response.Content.ReadAsStringAsync());

Go further

More in Security, evidence and compliance: Web archiving and evidence · Third-party script audit · Suspicious link checks · Hacked site detection · Marketing page records · All use cases

Give your product a browser.

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