Fail a capture on unwanted page content

Stop a screenshot when the page shows an error, a sign-in wall or a bot check, with failIfContains. The request fails with content_matched and is not charged.

Updated

A screenshot of an error page or a bot check is a wrong result that looks like a right one. This guide shows how failIfContains turns such a page into an error that your code can see, at no cost.

Reject a page by its text

curl -X POST https://api.wayfern.com/api/v1/screenshot \
  -H "Authorization: Bearer $WAYFERN_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/account/orders",
    "capture": {
      "failIfContains": ["Access denied", "Verify you are human", "Sign in to continue"]
    }
  }'

When the page text contains one of the terms, the answer is 422:

{
  "error": "content_matched",
  "code": 422,
  "request_id": "3b7c1d0e-9f2a-4c58-8d31-6e0a5b4c7d92",
  "message": "The page contains \"Access denied\", which failIfContains rejects",
  "reason": "https://example.com/account/orders"
}

message names the term that matched, as you wrote it. reason is the URL of the page. The response also has an X-Request-ID header.

When no term matches, the capture continues and the response is the usual one, at 5 credits.

Not charged

A content_matched failure is not charged. Wayfern debits a capture only after it has an image to return, and this check runs before the image is taken. No image is stored.

How the text is matched

  • The check reads the visible text of the page, the text that a person can see. Text in hidden elements and inside frames does not count.
  • Matching ignores case. access denied matches Access Denied and ACCESS DENIED.
  • Any run of spaces, tabs and line breaks counts as one space. Verify you are human matches text that the layout broke over two lines.
  • A term matches anywhere in the text, also inside a longer word. Choose terms that do not appear on a good page.
  • The first term in your list that matches is the one in the message.

When the check runs

The check is the last step before the capture. It runs after cookie banner cleanup, blockAds, hideSelectors, styles, click, scripts, the lazy-load scroll and settleMs. So:

  • Text that hideSelectors hides is not checked. You can hide a footer that mentions “access denied” in its help links.
  • Text that click or scripts add is checked.
  • Content that loads during the scroll of a full page is checked.

Limits

  • At most 20 terms.
  • Each term is 1 to 256 characters, after spaces at the ends are removed.
  • failIfContains is a Screenshot API option. A scrape rejects it with 400.

The MCP tool capture_screenshot takes the same check as fail_if_contains.

Handle the error in code

Treat content_matched as a result about the page, not as a temporary failure. Retrying at once usually shows the same page. Possible next steps:

  • Try another exit. With proxy: "residential" the page is loaded through a residential exit, and country picks its country.
  • Wait and retry later, for a page that shows a temporary maintenance notice.
  • Mark the URL as failed in your own records.
const res = await fetch("https://api.wayfern.com/api/v1/screenshot", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.WAYFERN_API_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url,
    capture: { failIfContains: ["Access denied", "Verify you are human"] },
  }),
});
const body = await res.json();
if (res.status === 422 && body.error === "content_matched") {
  console.log("Rejected page:", body.message);
} else if (res.ok) {
  console.log("Image:", body.data.screenshot.url);
}

Other error codes are listed in the Web Data errors table and the errors guide.