ScreenshotNeo

BlogEngineering

How Much Does It Cost to Screenshot 10,000 Product Pages a Day?

At 10,000 captures a day, plan for 300,000 a month. Your cost depends on what each provider bills for: screenshots, browser time, concurrency, or compute.

By the ScreenshotNeo team4 October 20269 min read

Short answer: 10,000 product-page screenshots a day is 300,000 captures in a 30-day month. One published quota-based comparison point is BrowserCloud’s $249 monthly plan, which lists 600,000 screenshots. That is a plan price, not a guaranteed total cost for your workload. Browserless and Cloudflare Browser Run meter browser time or concurrency, so their costs depend on how long pages take and how much parallel capacity you use. Self-hosting adds compute, storage, networking, and engineering costs.

There is no defensible single price from screenshot count alone. First measure the workload on representative pages, then compare equivalent billing units, failure and retry rules, and operational costs. The estimates below use published pricing details from the research sources; plan terms can change, so verify them before purchase.

1. Convert daily volume into monthly volume

For a 30-day planning month:

10,000 captures/day × 30 days = 300,000 captures/month

At 31 operating days, the volume is 310,000. If the workload runs only on weekdays, use actual operating days instead. Keep the capture count separate from retries: a service may bill a retry, a successful result, elapsed browser time, or some combination.

2. Compare the published pricing models

Approach Published pricing detail What it says about 300,000 monthly captures
Quota-based screenshot API BrowserCloud lists $99/month for 200,000 screenshots and $249/month for 600,000 screenshots. A screenshot uses five credits. The listed 600,000 screenshot quota is a comparison point above this workload. Confirm how the exact endpoint consumes credits and whether proxy traffic or other usage adds cost. This is not a tested bill.
Hosted browser connections Browserless defines a unit as up to 30 seconds per browser connection. Its Starter plan lists 180,000 units/month at $140/month and $0.0017 per overage unit; Scale lists 500,000 units/month at $350/month and $0.0015 per overage unit. The listed prices are billed annually. If every capture used exactly one unit, 300,000 captures would exceed Starter’s included units. Actual use depends on connection duration, reconnects, and plan behavior; longer connections can consume additional units.
Managed browser platform Cloudflare Browser Run Workers Paid includes 10 browser hours/month, then lists $0.09 per additional hour. Browser Sessions include 10 concurrent browsers; additional concurrency is listed at $2 per browser, calculated using monthly average daily peak concurrency. Estimate total browser hours from measured duration. If using Browser Sessions, estimate average daily peak concurrency too. Screenshot count alone is insufficient.
Self-managed cloud rendering AWS Lambda charges by request and execution duration. The cited pricing page lists $0.20 per million requests and $0.0000166667 per GB-second for the referenced Lambda Functions pricing section; configuration, region, and current terms affect rates. Lambda’s request charge is only one component. Add browser runtime compute, storage, networking, queues, monitoring, and operations. Lambda pricing is not a browser screenshot benchmark.

Sources: BrowserCloud pricing, Browserless pricing, Cloudflare Browser Run pricing, and AWS Lambda pricing.

3. Estimate time-metered costs with an explicit assumption

For browser-time billing, use this formula:

monthly browser hours = monthly captures × mean billable seconds per capture ÷ 3,600

For 300,000 captures, illustrative durations produce these totals:

Mean billable time per capture Monthly browser time
5 seconds 416.7 hours
10 seconds 833.3 hours
20 seconds 1,666.7 hours
30 seconds 2,500 hours

These are arithmetic scenarios, not measured performance. Do not treat them as predicted page load times or provider bills. For Cloudflare’s listed Workers Paid browser-hour rate, the simple incremental calculation is max(0, monthly browser hours − 10) × $0.09, before considering the underlying Workers plan and any Browser Sessions concurrency charge. Cloudflare rounds monthly browser-hour usage according to its published billing rules.

For Browserless, count connection units rather than assuming that each URL equals one unit. One unit covers up to 30 seconds per browser connection, with another unit for each additional 30 seconds. Multiply measured units by the plan’s overage rate only after checking which included allowance and annual-billing terms apply.

4. Measure a representative sample before committing

Pick a sample that reflects your real catalog: simple and complex layouts, different image counts, variants, regions, consent states, and pages that load content dynamically. Fix the viewport, locale, wait condition, and capture format so the comparison is meaningful. The code below measures local Playwright browser time for a CSV of URLs. It is a sizing aid, not a provider benchmark, and local timing may differ from hosted infrastructure.

Run the sample with Playwright

  1. Install Node.js and create a project directory.
  2. Install Playwright and its Chromium browser.
  3. Save one URL per line in urls.txt.
  4. Run the script and use the reported mean and percentile durations in the billing formulas. Increase sample size if the pages vary substantially.
npm init -y
npm install playwright
npx playwright install chromium
// measure.mjs
import { chromium } from 'playwright';
import { readFile } from 'node:fs/promises';

const urls = (await readFile('urls.txt', 'utf8'))
  .split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
const concurrency = Number(process.env.CONCURRENCY || 4);
const timeoutMs = Number(process.env.TIMEOUT_MS || 45000);
const durations = [];
const failures = [];
let next = 0;

async function worker() {
  const browser = await chromium.launch({ headless: true });
  try {
    while (true) {
      const index = next++;
      if (index >= urls.length) break;
      const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
      const start = performance.now();
      try {
        await page.goto(urls[index], { waitUntil: 'domcontentloaded', timeout: timeoutMs });
        // Replace or supplement this with a product-specific selector when needed.
        await page.waitForTimeout(1000);
        durations.push((performance.now() - start) / 1000);
      } catch (error) {
        failures.push({ url: urls[index], error: String(error) });
      } finally {
        await page.close();
      }
    }
  } finally {
    await browser.close();
  }
}

await Promise.all(Array.from({ length: Math.min(concurrency, urls.length) }, worker));
durations.sort((a, b) => a - b);
const percentile = (p) => durations.length ? durations[Math.min(durations.length - 1, Math.ceil(p * durations.length) - 1)] : null;
const mean = durations.length ? durations.reduce((a, b) => a + b, 0) / durations.length : null;
console.log(JSON.stringify({
  attempted: urls.length,
  successful: durations.length,
  failed: failures.length,
  meanSeconds: mean,
  p50Seconds: percentile(0.50),
  p95Seconds: percentile(0.95),
  failures,
}, null, 2));

domcontentloaded means the initial document has been parsed; it does not guarantee that product images, prices, or client-rendered variants are ready. For a real capture, wait for a reliable product-specific selector or a defined network and page readiness condition. A fixed delay is simple but can waste time on fast pages and miss slow ones.

5. Calculate concurrency and throughput

If the daily workload is spread across a window of W hours, the average arrival rate is 10,000 ÷ (W × 3,600) captures per second. At an average browser duration of S seconds, a first-pass concurrency estimate is:

average concurrent browsers ≈ captures per second × mean browser seconds

For example, spreading 10,000 captures over 10 hours is about 0.278 captures per second. At 10 seconds each, that implies roughly 2.8 browsers on average. Real systems need headroom for bursts, slow-tail pages, retries, rate limits, and queue draining. A daily peak can be much higher than the average.

Set a concurrency cap and queue work rather than launching all pages at once. Confirm provider limits and per-second launch limits. Browser startup overhead, session reuse, and whether each page gets its own connection affect both throughput and cost.

6. Include the costs outside the screenshot line item

  • Failures and retries: decide which failures retry, the maximum attempts, and whether each attempt incurs a charge. Use exponential backoff with jitter for transient errors, and send persistent failures to a review queue.
  • Network and proxies: estimate egress, proxy traffic, and geographic routing separately. Retail sites may serve different content by location or reject automated traffic.
  • Output size and retention: PNG, JPEG, and WebP have different storage characteristics. Estimate image bytes per capture, retention period, replicas, and transfer to downstream consumers.
  • Orchestration: include queues, job state, webhook delivery, database writes, logging, and monitoring where applicable.
  • Engineering and operations: self-managed browsers need capacity management, browser updates, crash recovery, alerting, and maintenance. Assign a value to this work when comparing with managed services.
  • Data and policy requirements: decide whether screenshots may contain personal or account data, who can access them, and how long they should be retained.

A screenshot is not automatically a complete or consistent product record. Define viewport, locale, currency, wait condition, and retention rules. Product pages can change during the day or show different content by region, session, or consent state.

7. Where ScreenshotNeo fits

ScreenshotNeo is a website screenshot API and MCP server. Its Business plan is $249 for 1,000,000 shots, which covers a 300,000-capture planning month by listed quota. The service bills only clean shots: bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. A response includes page-verdict and billing headers. Every feature is on every plan; the free tier includes 1,000 shots/month without a card, and paid plans start at $5 for 3,000 shots. Yearly billing gives two months free. Check the current plan and quota before production use.

Or skip the browser setup

A single request returns a screenshot. See the ScreenshotNeo API documentation for options and limits.

cURL

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

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

8. Troubleshooting cost estimates

The estimate is far below the actual bill

Check whether you counted browser connection units or hours correctly, included retries, and added proxy, storage, data transfer, and platform charges. Reconcile measured provider usage with successful captures and attempted captures.

Pages time out or the measured duration varies widely

Product pages can load different scripts, media, consent interfaces, and bot checks. Use a representative sample, consistent readiness criteria, and a timeout appropriate to the workflow. Segment slow pages instead of letting a small tail determine every capture’s wait period.

Concurrency charges are unexpectedly high

For services that meter concurrency, inspect peak usage by day and whether the billing rule averages daily peaks. Queue work and cap simultaneous browser sessions. Avoid creating a fresh browser for every small action if session reuse is supported and safe for the workload.

Retries inflate volume or do not clear failures

Classify transient network errors separately from bot checks, invalid URLs, and content that does not meet your selector condition. Retry transient errors with bounded backoff; do not retry permanent failures indefinitely. Confirm each provider’s billing treatment for failed calls and retries.

The capture succeeds but misses price, images, or variants

A navigation event is not a guarantee that the required product content rendered. Wait for the selector that identifies the data you need, or use a bounded additional wait. Define whether lazy-loaded images and below-the-fold content must be present.

A self-hosted estimate assumes Lambda is the whole cost

Lambda’s request and duration rates do not include the full rendering pipeline. Add browser packaging and memory requirements, storage, network traffic, queues, logs, and operational labor. Compare against measured end-to-end costs, not the invocation charge alone.

9. Reliability and performance checklist

  • Use a queue with a controlled worker pool and a documented concurrency ceiling.
  • Make jobs idempotent; record URL, viewport, locale, wait condition, attempt count, and result status.
  • Set bounded navigation and total-job timeouts; capture enough error detail to diagnose page-specific failures.
  • Use a readiness selector or stable condition for important product data. Avoid unbounded network-idle waits on sites with persistent connections.
  • Track p50 and p95 duration, successful captures, failure categories, retry count, image size, and billable units or browser time.
  • Store outputs with an explicit retention policy and a stable key derived from product identity and capture configuration.
  • Run a small pilot after any meaningful change to browser version, viewport, page readiness logic, or provider configuration.

At 10,000 per day, evenly distributed work is only about 6.9 captures per minute, but an hourly or batch schedule creates a much larger short-term rate. Design for the actual schedule and provider limits, not just the daily total.

10. Frequently asked questions

Is 10,000 screenshots a day the same as 300,000 a month?

Only for a 30-day month with captures every day. A 31-day month is 310,000; use the actual operating calendar for a budget.

Can I determine a reliable price from page count alone?

No. You also need each provider’s billing unit and the workload’s measured browser duration, retry rate, concurrency, and ancillary usage.

Does the Browserless Starter price cover 300,000 screenshots?

Its published Starter allowance is 180,000 30-second units per month, not 180,000 screenshots. Whether a capture consumes one unit depends on connection duration and retries.

Should I use self-hosted browsers for this volume?

Volume alone does not decide it. Compare measured infrastructure and operations cost with the value of browser control, and account for reliability work and peak capacity.

What should I validate before signing an annual plan?

Confirm current rates, annual billing terms, included quota, overage behavior, failed-job billing, concurrency limits, support, retention, and any proxy or geography charges against your pilot results.