ScreenshotNeo

BlogHow-to

How to Use ApiFlash for Visual Regression Testing

Use ApiFlash to capture repeatable screenshots, then compare them with approved baselines using a separate image-diff step in your test workflow.

By the ScreenshotNeo team4 October 20269 min read

ApiFlash can capture screenshots of your pages for visual regression testing, but the cited ApiFlash documentation does not describe a built-in visual-diff engine, baseline approval workflow, or CI pass/fail gate. Use it as the capture step: request each page under repeatable conditions, then compare the returned images with approved reference screenshots using a separate comparison tool.

This guide shows the workflow, runnable requests, reproducibility settings, and failure handling. ApiFlash settings and service limits can change, so confirm volatile details in its current documentation before relying on them in CI.

1. Separate screenshot capture from visual comparison

A visual regression test has two distinct jobs:

  1. Capture: render a URL at a known viewport and state, then save the screenshot.
  2. Compare: compare that image to an approved baseline, report differences, and apply your team’s review policy.

ApiFlash performs the capture job. The comparison job belongs to a separate image-diff or screenshot-testing tool. The general golden-image model is to compare a newly captured image with an approved reference; see Android Developers’ screenshot testing guidance for that model. It does not imply that ApiFlash integrates with Android tooling.

A practical loop is:

  1. Choose the important URLs, page states, and viewport sizes.
  2. Capture and review reference images under the same conditions future runs will use.
  3. Store approved baselines with your project artifacts or version control.
  4. After a code or content change, capture those same cases again.
  5. Compare each new image to its baseline and report changed cases for review.
  6. Update a baseline only after a person or an explicit team policy approves the change.

Test desktop and mobile layouts as separate cases. A viewport change can alter wrapping, navigation, and content visibility even if the underlying page is otherwise identical.

2. Define repeatable cases and capture settings

For each case, record the URL, viewport width and height, capture state, output format, scale factor, and readiness condition. Keep them fixed between baseline creation and later runs. ApiFlash documents a default viewport of 1920 × 1080 and JPEG output; set the values explicitly for test cases so an implicit default change does not silently change your captures.

Setting How to use it for regression tests
URL Use the same fully qualified http:// or https:// URL and the same test data or page state.
Viewport Specify width and height for each desktop or mobile case.
Full page Enable full-page capture when below-the-fold content is part of the case.
Element Capture a specific CSS selector when the component, rather than the whole page, is the test target.
Format Choose JPEG, PNG, or WebP consistently. PNG is often convenient for pixel comparisons; use the same choice for baselines and new captures.
Scale factor Keep the documented scale factor at 1 or 2 consistent across runs.
Readiness Prefer documented wait_for or wait_until conditions over a guessed fixed delay when possible.
Freshness and cache Account for the documented cache TTL default of 86,400 seconds. The fresh option requests a fresh capture, but the FAQ cautions that it does not invalidate an existing cached screenshot.
Lazy content Use the documented page-scrolling option where needed to trigger lazy-loaded content or animations, and keep that behavior consistent.

ApiFlash supports GET and POST at https://api.apiflash.com/v1/urltoimage. A valid access key is required. By default the response is the image itself; response_type=json returns JSON with links to the resulting screenshot. The examples below use GET and request PNG output. Check the documentation for the exact parameter names and supported values for the options you need.

3. Capture a screenshot with cURL

Set the access key in your shell environment and capture a page. Use a test URL that is reachable by ApiFlash.

export APIFLASH_ACCESS_KEY='YOUR_ACCESS_KEY'
curl --fail --silent --show-error --get 'https://api.apiflash.com/v1/urltoimage' \
  --data-urlencode "access_key=${APIFLASH_ACCESS_KEY}" \
  --data-urlencode 'url=https://example.com' \
  --data-urlencode 'format=png' \
  --data-urlencode 'width=1365' \
  --data-urlencode 'height=900' \
  --output current.png

For a full-page image, element capture, scale factor, readiness condition, or other supported setting, add the corresponding documented parameter and keep it identical for baseline and current captures. Do not assume an undocumented threshold or diff option is provided by ApiFlash.

4. Capture with Python

This example uses requests, checks for HTTP errors, and writes the binary response as an image. Install the dependency with python -m pip install requests.

import os
import requests

access_key = os.environ["APIFLASH_ACCESS_KEY"]
params = {
    "access_key": access_key,
    "url": "https://example.com",
    "format": "png",
    "width": 1365,
    "height": 900,
}

response = requests.get(
    "https://api.apiflash.com/v1/urltoimage",
    params=params,
    timeout=90,
)
response.raise_for_status()

content_type = response.headers.get("Content-Type", "")
if not content_type.startswith("image/"):
    raise RuntimeError(f"Expected an image response, got {content_type!r}")

with open("current.png", "wb") as image_file:
    image_file.write(response.content)

5. Capture with Node.js

This example uses the built-in fetch available in modern Node.js releases. It checks the status and response content type before saving the bytes.

import { writeFile } from 'node:fs/promises';

const accessKey = process.env.APIFLASH_ACCESS_KEY;
if (!accessKey) throw new Error('Set APIFLASH_ACCESS_KEY');

const params = new URLSearchParams({
  access_key: accessKey,
  url: 'https://example.com',
  format: 'png',
  width: '1365',
  height: '900',
});

const response = await fetch(
  `https://api.apiflash.com/v1/urltoimage?${params}`,
  { signal: AbortSignal.timeout(90_000) },
);
if (!response.ok) {
  throw new Error(`ApiFlash returned HTTP ${response.status}: ${await response.text()}`);
}
const contentType = response.headers.get('content-type') ?? '';
if (!contentType.startsWith('image/')) {
  throw new Error(`Expected an image response, got ${contentType}`);
}
await writeFile('current.png', Buffer.from(await response.arrayBuffer()));

6. Add a separate image-diff step

Once you have a baseline and a current image, compare them with the visual testing or image comparison tool selected by your team. The tool should tell CI whether the images differ according to your chosen policy, and should make both images available for review. ApiFlash’s cited pages document screenshot capture, not the comparison threshold or the approval policy; those are your project’s decisions.

A clear CI arrangement is:

  • Keep the baseline at a stable, versioned path keyed by page and viewport.
  • Write each new capture to a separate artifact path so it cannot overwrite the baseline.
  • Run the comparison only after capture succeeds and the file is verified as an image.
  • Publish the baseline, current image, and diff output as CI artifacts for review.
  • Make baseline updates an explicit reviewed action, not an automatic consequence of any failing run.

If the comparison tool supports masking or tolerances, define them for known dynamic areas and document the reason. No universal pixel-difference threshold is established by the sources here, and no such default should be attributed to ApiFlash.

7. Handle authentication, concurrency, and credentials

For authenticated pages, the ApiFlash guides describe capture patterns involving headers or cookies. Use the current guide for the exact parameter syntax and scope credentials to the test account. Keep the access key and session credentials on the server or in CI secrets; do not put a production key in browser-side code or commit it to the repository.

The guides also cover concurrent calls and proxy patterns for Nginx and Cloudflare Workers. A proxy can keep the access key out of client code; parallel requests can reduce wall-clock time for a suite, but should be paced within service limits. The documentation currently describes a leaky-bucket rate limit of 20 requests per second with burst capacity of 400. Requests beyond the regular rate may be delayed, and requests exceeding the burst may receive HTTP 429. Check the live documentation before choosing concurrency because these limits are changeable.

8. Troubleshooting ApiFlash captures

Symptom or status Likely cause What to do
HTTP 400 Invalid parameter, malformed URL, or target that cannot be captured. Check the full URL including scheme, parameter spelling and values, and whether the page is reachable from the capture service.
HTTP 401 Invalid or revoked access key. Rotate or correct the key in your CI secret store; avoid printing it in logs.
HTTP 402 Quota exhausted. Inspect usage and plan capacity, then reduce unnecessary captures or adjust the plan.
HTTP 403 A requested feature is not available on the account’s plan. Verify feature availability for the current plan and remove or change the unsupported option.
HTTP 429 Rate or burst limit exceeded. Reduce parallelism and retry with backoff; read quota and reset headers before scheduling another run.
HTTP 500 Capture failure. Retry a transient failure with bounded backoff, then inspect the URL, readiness condition, and service response if it persists.
Image differs on every run Dynamic content, changing data, animation, or inconsistent load timing. Use deterministic test data, wait for a meaningful selector or page state, and handle known dynamic regions in the comparison stage.
Text shifts between local baseline and API capture Rendering environment or fonts differ. Generate both baselines and later captures in the same environment. ApiFlash’s FAQ says capture uses Chrome on Linux and its system fonts differ from Windows and macOS.
Unexpected old screenshot Cache behavior or an existing cached image. Account for the configured cache TTL. The FAQ says fresh requests a fresh capture but does not invalidate an existing cached screenshot; verify current behavior and avoid treating this flag as cache purging.
Blank or incomplete capture Page is not ready, content needs scrolling, or navigation/loading failed. Use a readiness option, review the target’s accessibility from the service, and enable consistent scrolling for lazy content where appropriate.
JSON appears where an image was expected response_type=json was requested or response handling is wrong. Remove that option for direct image bytes, or parse the JSON response and fetch the screenshot URL as documented.

Successful responses expose quota headers for limit, remaining calls, and reset time. Read these in automation instead of assuming the monthly allowance is available. The ApiFlash FAQ says cached and failed screenshots do not count toward monthly quota, but verify current billing and quota terms before depending on that behavior.

9. Performance, reliability, and cost

Suite time depends on page load and capture time, number of cases, and concurrency. Capturing only meaningful URLs and component states controls work; splitting desktop and mobile cases keeps layout coverage explicit. Parallelize only within the documented service limits, handle 429 responses, and cap retries so a failing page does not stall a pipeline indefinitely.

Reproducibility is also an operational reliability concern. ApiFlash’s FAQ says captures use Chrome on Linux and notes its system fonts differ from Windows and macOS. A local screenshot compared with a remote capture can therefore show font rendering differences unrelated to an application regression. Create reference images through the same capture environment used in later runs where possible.

The research checked the ApiFlash homepage on 2026-10-03, when it displayed a free tier of 100 screenshots per month, Lite at $7/month for 1,000, Medium at $35/month for 10,000, and Large at $180/month for 100,000. These are time-sensitive listed prices, not a guarantee; check the ApiFlash site before budgeting. Cached and failed capture quota treatment is described in its FAQ and should be rechecked. A visual regression workflow also has costs outside capture, including baseline storage, comparison tooling, and review time.

10. Or skip the browser setup

ScreenshotNeo is a screenshot API and MCP server from Yorker Media. It provides screenshot capture, while your visual regression workflow still compares new images with approved baselines. One call can capture a URL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for options and response details. Before the capture, it accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and each response identifies the page verdict and billing status in headers. Its MCP server has take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

Sign up free for ScreenshotNeo: 1,000 screenshots a month, no card required.

FAQ

Does ApiFlash compare screenshots or fail a deployment when pixels change?

The cited ApiFlash documentation describes capture, but does not establish a built-in visual-diff engine, baseline approval flow, or deployment gate. Add a separate comparison step and define your team’s review policy.

Can I use ApiFlash for mobile and full-page checks?

Yes. Its documentation describes viewport width and height settings and full-page capture. Treat each viewport as its own case and keep its settings consistent with the corresponding baseline.

Should I use a fixed sleep before capture?

Prefer the documented wait_for or wait_until options when they fit the page; ApiFlash recommends these over a simple delay for more reliable readiness.

Can I compare a Windows screenshot with an ApiFlash capture?

You can, but differences in Chrome and system fonts may add noise. ApiFlash’s FAQ describes Linux Chrome captures and font differences from Windows and macOS, so use a consistent environment when possible.

Does the fresh option clear ApiFlash’s screenshot cache?

The FAQ cautions that it requests a fresh capture but does not invalidate an existing cached screenshot. Check the current documentation for the exact cache controls before designing around freshness.