1.Use an API for captures, a browser session for workflows
Use a screenshot API when the job is independent: open one URL, reach a known visual state, capture it, and close. This fits scheduled page archives, marketplace evidence, visual monitoring, report thumbnails, and screenshots attached to data-quality alerts. Your worker makes an HTTP request and stores the returned image rather than managing Chromium processes.
Use Playwright or Puppeteer directly when the screenshot is one step inside a longer interactive flow. A login followed by navigation through several screens, an OTP prompt, or a stateful checkout simulation needs a live browser session. The Playwright screenshot documentation confirms that the library supports page, full-page, element, and in-memory buffer captures; OmniScrape's Browser-as-a-Service page is the relevant product when you need that interaction model remotely.
2.Choose viewport, full-page, or element capture
Match the capture scope to the downstream question. A larger image is not automatically more useful.
- Viewport — capture what a user initially sees. Use it for above-the-fold monitoring, landing-page reviews, and alert evidence.
- Full page — capture the complete scrollable document. Use it for page archives, long-form content records, and compliance review where below-the-fold sections matter.
- Element — crop to one selector. Use it for charts, price cards, product availability panels, or a stable component that feeds a report.
- Persistent browser screenshot — use BaaS when the image depends on a multi-step authenticated or interactive state that cannot be represented by one capture request.
3.Capture a full-page PNG with Python
The current OmniScrape Web Unlocker documentation defines three screenshot types: viewport, fullpage, and element. A successful request returns a base64-encoded PNG in data.screenshot. Keep the API key in an environment variable and use a safe demonstration target while building the integration.
123456789101112131415161718192021222324252627282930313233343536import base64
import os
from pathlib import Path
import requests
response = requests.post(
"https://api.omniscrape.io/v1/scrape",
headers={"X-API-Key": os.environ["OMNISCRAPE_KEY"]},
json={
"url": "https://example.com/",
"mode": "auto",
"output_format": "screenshot",
"screenshot": True,
"screenshot_type": "fullpage",
},
timeout=120,
)
response.raise_for_status()
body = response.json()
if not body.get("success"):
raise RuntimeError(body.get("error", "screenshot failed"))
encoded = body.get("data", {}).get("screenshot")
if not encoded:
raise RuntimeError("response did not contain data.screenshot")
if encoded.startswith("data:image/png;base64,"):
encoded = encoded.split(",", 1)[1]
png = base64.b64decode(encoded, validate=True)
if not png.startswith(b"\x89PNG\r\n\x1a\n"):
raise RuntimeError("response is not a valid PNG")
Path("example-fullpage.png").write_bytes(png)
4.Wait for content, not an arbitrary number of seconds
A screenshot is only correct if the page has reached the state your evidence requires. The load event can fire before a React component receives its data, while network-idle heuristics can wait forever on analytics or live connections. Prefer a stable selector that appears when the target content is ready.
The OmniScrape scrape endpoint reference documents js_wait_selector for this purpose. Set it to the element that proves the page has rendered, such as a product card or chart container. For an element screenshot, use screenshot_type element and provide screenshot_selector for the node to crop. The readiness selector and capture selector may be the same, but they solve different problems: one controls timing and the other controls the image bounds.
123456789{
"url": "https://example.com/",
"mode": "js_rendering",
"output_format": "screenshot",
"screenshot": true,
"screenshot_type": "element",
"screenshot_selector": "h1",
"js_wait_selector": "h1"
}
5.Make recurring screenshots comparable
Visual monitoring fails when expected noise overwhelms meaningful change. Timestamps, rotating banners, animated carousels, personalized recommendations, cookie dialogs, and A/B tests can produce a different image on every run even when the page is healthy.
Pixel equality is usually too strict for third-party sites. Compare within a region of interest or use perceptual thresholds, then send uncertain changes for human review. The Playwright visual comparison guide also recommends stabilizing volatile visual content and shows how screenshot assertions use configurable difference limits.
6.Screenshot troubleshooting matrix
Classify the symptom before retrying. Repeating the same capture without changing timing, scope, or identity rarely fixes a deterministic problem.
- Blank or skeleton image — the page had not hydrated. Add js_wait_selector for a stable data-bearing element.
- Element capture fails — screenshot_selector matched nothing or the node was detached during rendering. Verify the selector against the returned layout and retry only after fixing it.
- Wrong language, price, or inventory — the capture used the wrong geography or session. Set the intended country and validate a locale marker.
- Cookie banner covers the page — handle consent only when authorized, or crop to an unaffected element. Do not bypass an access control disguised as a dialog.
- Full-page image repeats a sticky header — capture a smaller region or element when the repeated chrome is not part of the evidence.
- Image changes every run — isolate dynamic regions, make session inputs consistent, and use a review threshold instead of exact pixel equality.
- HTTP succeeded but screenshot is missing — check body.success and data.screenshot, then log the response error without storing credentials or cookies.
7.Store screenshots as evidence, not anonymous blobs
Use a deterministic object key such as source, normalized URL hash, locale, capture type, and timestamp. Store metadata beside the PNG: requested URL, final URL, capture time, selector, screenshot type, job ID, and a content hash. That makes deduplication, audit, and deletion possible without opening every image.
Screenshots are not a substitute for structured data when a downstream system needs prices, names, or dates. Use CSS extraction for machine-readable fields and keep the screenshot as supporting evidence. This separation makes the data queryable while preserving a visual record for disputes or debugging.
8.Implementation checklist
Start with one authorized URL and one capture type. Confirm the rendered state and response contract before adding batches or visual comparison.
- Use an environment variable or secrets manager for the API key
- Choose viewport, fullpage, or element based on the downstream question
- Set a readiness selector for JavaScript-rendered content
- Validate body.success, data.screenshot, base64 decoding, and the PNG signature
- Record URL, final URL, locale, selector, type, timestamp, and content hash
- Separate transient transport failures from deterministic selector failures
- Define retention and access controls before collecting screenshots at scale
- Respect applicable law, website terms, robots directives, data rights, and published rate limits
9.Start with Web Unlocker screenshot capture
If your job is one URL to one image, try Web Unlocker screenshot capture with a representative authorized page and the smallest useful scope. Use viewport for initial-state evidence, fullpage only when the complete document matters, and element when one component carries the signal.
Move to Browser-as-a-Service when the screenshot depends on a persistent multi-step interaction. That boundary keeps simple captures in an HTTP workflow while preserving full browser control for the cases that genuinely need it.
Frequently asked questions
What does a website screenshot API return?
OmniScrape returns a base64-encoded PNG in data.screenshot. Decode it, validate the PNG signature, and store it with the requested URL, final URL, capture type, selector, locale, and timestamp.
Should I use a viewport or full-page screenshot?
Use viewport when the initial visible state is the evidence you need. Use full page when below-the-fold content is part of the record. For one chart, product card, or component, element capture is usually more precise.
How do I screenshot one element?
Set screenshot_type to element and provide screenshot_selector with a stable CSS selector. Add js_wait_selector when the element appears only after JavaScript rendering so capture begins after the content is ready.
Why is my website screenshot blank or incomplete?
The page probably had not reached the required rendered state. Wait for a stable element that proves the target data is present instead of relying only on navigation completion or a fixed delay.
When should I use Playwright instead of a screenshot API?
Use Playwright or Puppeteer when the image is part of a persistent interactive workflow, such as an authorized login and several dependent navigation steps. Use a screenshot API for independent URL-to-image jobs.
Related guides
- Playwright Web Scraping: Practical Patterns for Protected Sites
- Puppeteer Web Scraping: Patterns, Anti-Bot Limits, and BaaS Integration
- Headless Browser Scraping: When to Use It and How to Do It Right
- Remote Browsers over CDP with Playwright and Puppeteer
- Web Scraping API: Endpoint, Modes, Output Formats & Integration Patterns
- Kimono Labs Alternative: Rebuilding a Point-and-Click Scraper