NewIntroducing semantic snapshotsPair every capture with structured DOM data →

For teams that run public websites

Notice injected spam links or a defaced page before visitors do

Watch your key pages from outside and get a webhook when their links, text or title change with no deploy to explain it.

The problem

A compromised plugin adds forty links to an online pharmacy in your footer, or replaces the home page's headline. The server logs look normal, the CMS shows editors the right content, and the first report comes from a customer or a search engine warning weeks later.

How domscout handles it

A monitor loads the page on a schedule the way a visitor's browser does and compares each run with the last. checkLinks reports a change when the set of links on the page changes, which is how injected spam links show up; checkMarkdown catches changed text and checkTitle a replaced title. A change sends a signed webhook naming the run and the two captures, and both captures are saved, so you can open the before and after and see exactly what appeared. A change right after one of your own deploys is expected; one at three in the morning is worth a look.

Where it shows up

  • Integrity checks on the home page, the footer and the login page.
  • An alert routed to the on-call channel rather than a marketing inbox.
  • A before-and-after record for the incident report.

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.

cURL
curl -X POST https://api.domscout.io/monitors \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Homepage integrity",
    "targetUrl": "https://www.example.com/",
    "intervalMinutes": 60,
    "notifyWebhookUrl": "https://your-app.example/hooks/domscout",
    "checkLinks": true,
    "checkMarkdown": true,
    "checkTitle": 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: "Homepage integrity",
    targetUrl: "https://www.example.com/",
    intervalMinutes: 60,
    notifyWebhookUrl: "https://your-app.example/hooks/domscout",
    checkLinks: true,
    checkMarkdown: true,
    checkTitle: 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": "Homepage integrity",
        "targetUrl": "https://www.example.com/",
        "intervalMinutes": 60,
        "notifyWebhookUrl": "https://your-app.example/hooks/domscout",
        "checkLinks": True,
        "checkMarkdown": True,
        "checkTitle": True
    },
)
print(response.json())
Go
package main

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

func main() {
	body, _ := json.Marshal(map[string]any{
		"name": "Homepage integrity",
		"targetUrl": "https://www.example.com/",
		"intervalMinutes": 60,
		"notifyWebhookUrl": "https://your-app.example/hooks/domscout",
		"checkLinks": true,
		"checkMarkdown": true,
		"checkTitle": 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' => 'Homepage integrity',
        'targetUrl' => 'https://www.example.com/',
        'intervalMinutes' => 60,
        'notifyWebhookUrl' => 'https://your-app.example/hooks/domscout',
        'checkLinks' => true,
        'checkMarkdown' => true,
        'checkTitle' => 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: "Homepage integrity",
    targetUrl: "https://www.example.com/",
    intervalMinutes: 60,
    notifyWebhookUrl: "https://your-app.example/hooks/domscout",
    checkLinks: true,
    checkMarkdown: true,
    checkTitle: 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": "Homepage integrity",
                "targetUrl": "https://www.example.com/",
                "intervalMinutes": 60,
                "notifyWebhookUrl": "https://your-app.example/hooks/domscout",
                "checkLinks": true,
                "checkMarkdown": true,
                "checkTitle": 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 = "Homepage integrity",
    targetUrl = "https://www.example.com/",
    intervalMinutes = 60,
    notifyWebhookUrl = "https://your-app.example/hooks/domscout",
    checkLinks = true,
    checkMarkdown = true,
    checkTitle = 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 · Tracking silent edits · Marketing page records · All use cases

Give your product a browser.

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