Browserless Alternatives for Full-Page Website Screenshots
Compare Browserless with ScreenshotNeo, ScreenshotOne, Urlbox, and Playwright for full-page captures, lazy-loaded content, and control over browser infrastructure.
For hosted full-page screenshot APIs, ScreenshotNeo is the first alternative to consider: cookie banners, popups, and chat widgets are removed before capture, and only clean screenshots are billed. ScreenshotOne and Urlbox are also documented hosted options. If you want browser-level control and are willing to run the browser workflow yourself, Playwright can capture a full page locally.
The key decision is how each option handles content that appears only while scrolling. A fullPage setting can capture beyond the visible viewport, but it does not guarantee that lazy-loaded images or scroll-triggered content have appeared. Compare representative pages at your target viewport before choosing a capture method.
At a glance
| Option | Capture approach | Useful when | Consider |
|---|---|---|---|
| 1. ScreenshotNeo | Hosted screenshot API; supports full-page captures with lazy images loaded. | You want a single request, clean captures, and billing that excludes bot checks, blank pages, failed loads, and cache hits. | Review the API documentation for the options your pages need. |
| 2. ScreenshotOne | Hosted API with full_page=true; its optional by_sections algorithm scrolls and combines sections. |
You want a hosted API and want to evaluate section-based capture and its tuning options. | Its documentation says quality tuning can reduce performance. That is a product caveat, not an independent benchmark. |
| 3. Urlbox | Hosted API with full_page=true; offers stitch and native modes. |
You want to choose between scroll-and-stitch behavior and the browser’s native full-page capture. | Urlbox describes native mode as faster but less reliable on some sites. Treat this as a vendor description and test your own pages. |
| 4. Playwright | Code-driven browser automation; page.screenshot({ fullPage: true }) captures beyond the viewport. |
You want to control navigation, scrolling, waiting, and capture in your own code. | You operate the browser workflow. The Browserless Playwright example connects to Browserless, so that example alone does not establish a self-hosted alternative. |
These are documented capabilities, not results from a comparative test. The research does not establish comparative pricing, measured reliability, or independent speed results for ScreenshotOne and Urlbox. Check current vendor terms before making a purchasing decision.
What makes a full-page screenshot difficult?
A page may be taller than the viewport, and its content may change as the browser scrolls. Images can load lazily; sections can appear after an intersection event; fixed headers can repeat in a stitched image; and animations or live data can change between scroll steps. A capture method that simply enlarges the viewport may behave differently from one that scrolls and joins sections.
- Lazy content: scrolling can trigger image and component loading. A full-page flag alone may not trigger it.
- Sticky and fixed elements: a sticky bar can appear in unexpected places or repeat in a long capture. Stitching implementations may freeze such elements, but verify on your templates.
- Dynamic pages: infinite feeds, carousels, ads, and live updates can make page height or content unstable.
- Very tall pages: large captures take more time and memory, and browser or service limits may apply. Split long content into sections if a single image is unwieldy.
How to choose an alternative
- Decide whether to operate a browser. A hosted API removes browser provisioning and maintenance from your application. Playwright gives you code-level control, but you need to run it in an environment with the required browser binaries and resources.
- Check how lazy content is triggered. Determine whether the service scrolls, supports scrolling controls, or captures via native full-page behavior. Test pages with images and sections that load on scroll.
- Inspect sticky elements and page boundaries. Compare the top, middle, and bottom of the result against the live page at the same viewport.
- Set a consistent viewport and wait condition. Use the same viewport, wait strategy, and representative page state when comparing tools. A fixed delay can be insufficient on slow pages or wasteful on fast ones.
- Estimate cost from your real workload. Include retries, output format, capture frequency, and whether failed or cached requests are charged. Confirm current plans directly with each vendor; this research does not provide competitor prices.
DIY: capture a full page with Playwright
This Node.js example runs a local Chromium browser, scrolls through the page to trigger common lazy-loading behavior, waits for images to finish or fail, then saves a full-page PNG. Scrolling is best effort: pages that load content only after a particular interaction may need site-specific steps.
npm init -y
npm install playwright
npx playwright install chromium
Save as screenshot.mjs:
import { chromium } from 'playwright';
const target = process.argv[2] ?? 'https://example.com';
const browser = await chromium.launch({ headless: true });
try {
const page = await browser.newPage({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1,
});
const response = await page.goto(target, {
waitUntil: 'domcontentloaded',
timeout: 60_000,
});
if (!response) {
throw new Error('Navigation returned no main resource response');
}
if (!response.ok()) {
throw new Error(`Navigation returned HTTP ${response.status()}`);
}
// Scroll in viewport-sized steps so common lazy loaders can run.
await page.evaluate(async () => {
const step = Math.max(1, window.innerHeight - 100);
for (let y = 0; y < document.documentElement.scrollHeight; y += step) {
window.scrollTo(0, y);
await new Promise(resolve => setTimeout(resolve, 150));
}
window.scrollTo(0, 0);
});
// Do not let a broken image hang the entire capture.
await page.evaluate(async () => {
await Promise.race([
Promise.all([...document.images].map(img => {
if (img.complete) return Promise.resolve();
return new Promise(resolve => {
img.addEventListener('load', resolve, { once: true });
img.addEventListener('error', resolve, { once: true });
});
})),
new Promise(resolve => setTimeout(resolve, 10_000)),
]);
});
await page.screenshot({ path: 'page.png', fullPage: true });
console.log('Saved page.png');
} finally {
await browser.close();
}
Run it with node screenshot.mjs https://example.com. Use a URL you are authorized to access. The script deliberately checks the main document response; if a site intentionally returns an error status while rendering useful content, adjust that check for your use case.
Useful Playwright adjustments
- Wait for a known element: use
await page.locator('main').waitFor({ state: 'visible' })or another page-specific selector after navigation. - Wait for network activity:
waitUntil: 'networkidle'is available, but analytics, polling, or persistent requests can prevent it from completing. Prefer a meaningful selector for those pages. - Use a different format: set
type: 'jpeg'and optionallyquality: 85; PNG is lossless. Playwright supports PNG and JPEG screenshots through this API. - Capture a viewport instead: omit
fullPageor set it tofalse. - Handle a page-specific consent layer: use a locator and click its accept button before capture. Avoid clicking arbitrary page controls; they can navigate away or change the content.
- Constrain a runaway page: add application-level navigation and job timeouts, and impose a maximum page height or section strategy for pages that continuously append content.
Hosted alternatives and their documented capture behavior
ScreenshotOne
ScreenshotOne documents full-page screenshots and an optional section-based by_sections algorithm that scrolls and combines sections. Its documentation notes that tuning for better quality may reduce performance. If you evaluate it, compare the default behavior with the section-based option on pages with lazy-loaded content and sticky elements, then review the current options documentation for supported parameters.
Urlbox
Urlbox documents a default stitch mode that scrolls, triggers lazy-loaded content, freezes fixed and sticky elements, and combines sections. It also offers native mode, which uses the browser’s native full-page screenshot functionality and is described as faster but less reliable on some sites. Choose based on how your actual page templates render, rather than treating those descriptions as independent comparative measurements.
Browserless and a Playwright workflow
Browserless’s screenshot API accepts a URL and screenshot options; its documentation says fullPage: true captures beyond the visible viewport. It also documents scrollPage: true for cases where scrolling is needed to reveal lazy-loaded content. Browserless provides a Playwright connection example. That is a way to use Playwright with Browserless, not evidence by itself of a self-hosted deployment path.
Primary documentation: Browserless Screenshot API and Browserless screenshot example; ScreenshotOne full-page screenshots and ScreenshotOne options; Urlbox screenshots.
Or skip the browser setup
ScreenshotNeo takes a URL in one request and returns a screenshot. Its full-page capture loads lazy images. Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, timeouts, failed loads, and cache hits are never billed; the response includes X-Page-Verdict and X-Billed headers. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents.
See the ScreenshotNeo API docs. 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);
These examples use the API’s default output; see the docs for capture options and response details. ScreenshotNeo includes 1,000 screenshots a month free with no card, and paid plans start at $5 for 3,000. Every feature is on every plan. Create a free account and get 1,000 screenshots a month with no card.
Testing checklist before you switch
- Capture the same set of representative pages at an identical viewport.
- Include a page with lazy images, one with a sticky header, and one with dynamic or scroll-triggered content.
- Check that content at the bottom is present and that fixed elements are not duplicated or misplaced.
- Record output format, dimensions, completion time, and failures across repeated runs. This gives you a reproducible comparison for your workload; it is not a general benchmark.
- Check current pricing, limits, and terms with the vendors before committing. The research does not establish comparative prices or reliability measurements.
Troubleshooting
| Symptom | Likely cause | What to try |
|---|---|---|
| Images or sections are missing near the bottom | They load only after scrolling or after a site-specific trigger. | Use a scroll-and-stitch mode or explicitly scroll before capture. In Playwright, wait for a known selector or image completion; add page-specific interaction if needed. |
| Sticky bars appear more than once or in odd positions | The capture method combines multiple scroll positions while fixed content remains active. | Try a stitch implementation that handles fixed elements, or hide the sticky selector in your own workflow. Verify the result on the real template. |
| Playwright reports a navigation timeout | The page is slow, or a chosen network-idle condition never occurs because the page keeps making requests. | Use domcontentloaded followed by a selector-specific wait, or raise the navigation timeout for known slow pages. |
| The capture has blank or incomplete content despite successful navigation | Rendering may continue after the document event, or content needs scrolling, consent acceptance, or another interaction. | Wait for the relevant element, scroll through the page, and perform only the required interaction before capturing. |
| A very tall page takes too long or creates an unwieldy file | Full-page output has many pixels, or the page grows while scrolling. | Limit the page height, capture sections, reduce device scale where supported, or choose a viewport capture if that meets the requirement. |
| Hosted output differs from local Playwright | Viewport, device scale, browser behavior, wait conditions, or capture algorithm differs. | Align the viewport and page state, then compare the same URL and relevant capture settings. Different native and stitch strategies can produce different results. |
| Playwright cannot launch Chromium | The browser binary may not have been installed, or the runtime environment may lack required dependencies. | Run npx playwright install chromium in the deployment environment and follow Playwright’s official installation guidance for that environment. |
Performance, reliability, and cost
Full-page captures process more pixels than viewport captures. Scroll-and-stitch methods also need to visit page sections, which can trigger additional loading and make content state-dependent. Native full-page capture avoids the same stitching sequence but may behave differently on some sites. There is no universal winner in the cited documentation; measure on the page types, viewport, output format, and repeat rate that matter to your team.
For reliability, set explicit timeouts, wait for a meaningful page condition, and keep a record of status and output dimensions. In a production pipeline, retry transient failures with a limit and avoid retrying permanent problems such as an invalid URL. With ScreenshotNeo, inspect the page-verdict and billed headers when handling a response. For self-run Playwright, ensure browser cleanup happens even when navigation or capture fails, as in the example’s finally block.
For cost, include browser compute and maintenance if you run Playwright, plus hosted request charges and any applicable limits if you use a service. The dossier does not establish ScreenshotOne or Urlbox pricing or comparative operating cost. ScreenshotNeo’s stated plans are free for 1,000 shots per month, then Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free.
FAQ
Does fullPage: true guarantee lazy-loaded images appear?
No. It requests a capture beyond the viewport, but lazy content may need scrolling or additional waiting first.
Is Playwright itself a hosted screenshot service?
No. It is a browser automation library. You provide and operate the runtime, unless you connect it to a hosted browser service.
Which capture mode should I choose: native or stitch?
Test both against your page layouts. Stitching can trigger scroll-based loading and handle sticky elements; native capture can be faster according to Urlbox, with site-specific reliability caveats.
Can this comparison tell me which service is fastest?
No. The cited documentation contains vendor feature descriptions, not an independent benchmark. Run a repeatable comparison on your own pages.
