Scout · Endpoints

Assert

Batch website verification — one page load, many customer-supplied expectations, one passed boolean. Scout still returns raw evidence per rule; it does not invent quality scores.

POST/v1/assertAPI key

Run assert[] against a URL. Credits: 3 + 1 per assert after the first (max 25 rules).

Why assert beats many visibility calls
Each rule reuses the same browser session. Prefer this for CI release gates, pricing-page checks, and badge verification. Single-selector occlusion detail remains on POST /v1/checks/visibility.

Request

NameTypeRequiredDescription
urlstringrequiredPage to open.
assertobject[]required1–25 rules, each with selector + operators.
scroll_into_viewbooleanoptionalScroll first match into view before visibility sampling (default true).
ignore_selectorsstring[]optionalOverlays to ignore for not_covered.
dismiss_cookie_banner / wait_for_selector / device / …optionalStandard browse options.

Operators per rule

FieldMeaning
existsElement present / absent
visibleCSS-visible + size (same sampling spirit as visibility)
not_coveredNot occluded (elementsFromPoint)
count / count_min / count_maxquerySelectorAll length
contains / text / matchesText content (collapsed whitespace); matches = RegExp source
href_containsAnchor href substring
attr{ name, value } exact attribute match
softFailure reported but does not flip overall passed

Selector-only rules imply exists: true.

Verify a pricing page

One load: CTA visible, price text contains 29, exactly one hero image.

RequestBody
json
{
  "url": "https://example.com/pricing",
  "dismiss_cookie_banner": true,
  "assert": [
    { "selector": "#buy", "visible": true },
    { "selector": ".price", "contains": "29" },
    { "selector": "img.hero", "count": 1 }
  ]
}
Response200 OK
json
{
  "status": "success",
  "url": "https://example.com/pricing",
  "final_url": "https://example.com/pricing",
  "passed": true,
  "failed_count": 0,
  "soft_failed_count": 0,
  "results": [
    {
      "selector": "#buy",
      "ok": true,
      "soft": false,
      "checks": [{ "name": "exists", "expected": true, "actual": true, "ok": true }, { "name": "visible", "expected": true, "actual": true, "ok": true }],
      "evidence": { "count": 1, "text": "Buy now", "href": null, "visible": true, "in_viewport": true, "not_covered": true, "overlap_detected_by": null },
      "error": null
    },
    {
      "selector": ".price",
      "ok": true,
      "soft": false,
      "checks": [{ "name": "exists", "expected": true, "actual": true, "ok": true }, { "name": "contains", "expected": "29", "actual": "€29 / mo", "ok": true }],
      "evidence": { "count": 1, "text": "€29 / mo", "href": null, "visible": true, "in_viewport": null, "not_covered": null, "overlap_detected_by": null },
      "error": null
    },
    {
      "selector": "img.hero",
      "ok": true,
      "soft": false,
      "checks": [{ "name": "count", "expected": 1, "actual": 1, "ok": true }],
      "evidence": { "count": 1, "text": null, "href": null, "visible": null, "in_viewport": null, "not_covered": null, "overlap_detected_by": null },
      "error": null
    }
  ],
  "response_time_ms": 1104,
  "timestamp": "…"
}
curl
curl -X POST https://api.scout.macrocontent.dev/v1/assert \
  -H "Authorization: Bearer sk_scout_…" \
  -H "Content-Type: application/json" \
  -d @assert.json

Response fields

  • passed — true when every non-soft rule is ok
  • results[] — per-rule ok, checks[] (expected/actual), evidence, error
  • failed_count / soft_failed_count