How to Capture a Full-Page Website Screenshot with wkhtmltoimage
Capture a webpage as a full-length image with wkhtmltoimage, choose the right width and wait strategy, and troubleshoot pages it cannot render reliably.
To capture a full-page screenshot with wkhtmltoimage, pass the page URL and an output filename. Its default screen height is calculated from the page content, so you usually do not need to set a fixed height for a full-page attempt.
wkhtmltoimage --width 1280 https://example.com/ page.png
Use a width that gives the page the desktop or mobile layout you want. If the page needs time to populate with JavaScript, add a short delay:
wkhtmltoimage --width 1280 --javascript-delay 1500 https://example.com/ page.png
wkhtmltoimage is a legacy renderer based on Qt WebKit. It may not render modern pages, script-driven content, or content loaded only after scrolling as expected. For pages that need a more current browser automation workflow, see the Playwright option below.
1. Install and run wkhtmltoimage
Install the wkhtmltoimage executable using a package or build appropriate for your operating system, then check that the command is available:
wkhtmltoimage --version
wkhtmltoimage --help
The command takes options, an input page, and an output image path. The input can be a URL or a local HTML file:
wkhtmltoimage [OPTIONS]... <input file> <output file>
For example, to render a local file:
wkhtmltoimage --width 1280 ./report.html ./report.png
The Debian manual documents the command form, options, and defaults in its wkhtmltoimage manual.
2. Choose width, height, and output format
Width controls the page layout
--width sets the screen width used for rendering. The manual describes it as a guide unless smart width is disabled. To force the requested width, use --disable-smart-width:
wkhtmltoimage --width 1280 --disable-smart-width https://example.com/ page.png
A strict width can change responsive behavior, such as which navigation menu or column layout appears. Choose a width that matches the presentation you intend to capture, and inspect the result.
Height usually does not need to be set
The default screen height is calculated from page content. --height sets the screen height; it is not the basic switch for requesting a full-page screenshot. Set it only when you specifically need a particular screen height for rendering:
wkhtmltoimage --width 1280 --height 900 https://example.com/ page.png
Do not assume a height setting will make content that has not loaded or rendered appear in the image.
Pick an image format and quality
Use --format to choose a supported output format. For JPEG output, set --quality from 0 to 100. The format and quality options are documented in the manual.
wkhtmltoimage --width 1280 --format jpg --quality 85 https://example.com/ page.jpg
PNG is useful when sharp text or transparency matters; JPEG can make photographic captures smaller, with quality depending on the chosen value. Confirm the output extension and format agree.
3. Wait for JavaScript content
JavaScript is enabled by default in the documented option list. When a page needs a little time after its initial load, try --javascript-delay and increase it only if inspection shows that the page is not ready:
wkhtmltoimage --width 1280 --javascript-delay 2000 https://example.com/ page.png
A fixed delay is a timing guess. If you control the page, --window-status can wait for a specific status value instead. Have the page set window.status when its content is ready, then wait for that value:
wkhtmltoimage --width 1280 --window-status screenshot-ready https://example.com/ page.png
These options only help when the target page can load and expose the content to this renderer. They do not guarantee that content fetched after scrolling, blocked resources, or browser-dependent features will work.
To disable JavaScript explicitly, use --disable-javascript. This can be useful when scripts are unnecessary, but script-rendered content will not appear.
4. Crop a region when needed
The crop options select coordinates and dimensions in the rendered output. Use them to trim an image after deciding what page content is available; they do not load additional content or replace a full-page capture.
wkhtmltoimage --width 1280 --crop-x 0 --crop-y 0 --crop-w 1280 --crop-h 900 https://example.com/ top-section.png
Relevant options include --crop-x, --crop-y, --crop-w, and --crop-h. Check the rendered result because crop coordinates can exclude content you meant to keep.
5. Troubleshoot incomplete or incorrect screenshots
| Symptom | Likely cause | What to try |
|---|---|---|
| The image shows only part of the page | The page content did not finish rendering, or a fixed height or crop constrained the output. | Remove crop options and the fixed --height setting, then try the default content-based height. Add a JavaScript delay if the page needs time. |
| Text or sections are missing | The page depends on JavaScript or resources that did not load in this renderer. | Keep JavaScript enabled, try --javascript-delay, and check whether the content requires scrolling or a modern browser feature. |
| The layout is too wide or unexpectedly narrow | The chosen screen width affects responsive layout; smart width may adjust the requested width. | Choose an intentional --width. If you need strict width, try --disable-smart-width and inspect the layout again. |
| The page looks different from a current browser | wkhtmltoimage uses Qt WebKit and is a legacy renderer. |
Use a browser automation option such as Playwright for pages that depend on newer browser behavior. |
| The output file is missing or unusable | The command may not be installed, the input may be unreachable, or the output path or format may be wrong. | Check wkhtmltoimage --version, confirm the URL or local file is accessible, use a writable output path, and match the extension to the selected format. |
| A page that loads more content while scrolling is incomplete | Some content is requested only after scrolling; a full-page render does not guarantee that these requests are triggered. | Check the page’s loading behavior. If it requires browser interaction or scroll-triggered loading, use a browser automation workflow that can perform those steps. |
6. Use Playwright when the legacy renderer is not suitable
Playwright documents a fullPage screenshot option that captures the full scrollable page rather than only the visible viewport. This is an alternative when the target page does not work reliably with the older renderer; the two approaches are not presented here as benchmarked against each other. See the Playwright API parameters.
With Node.js, install Playwright and its Chromium browser, then save this as capture.mjs:
npm install playwright
npx playwright install chromium
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.goto('https://example.com/', { waitUntil: 'networkidle' });
await page.screenshot({ path: 'page.png', fullPage: true });
await browser.close();
Run it with node capture.mjs. If network activity never becomes idle, choose a different readiness condition or an explicit wait that fits the page. For content that appears only after scrolling, add the necessary page interaction before taking the screenshot.
7. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF. For this full-page capture, use the documented full_page option. See the ScreenshotNeo API documentation for request parameters and formats.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com/ \
-d full_page=true \
-o page.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={
"access_key": "YOUR_API_KEY",
"url": "https://example.com/",
"full_page": "true",
},
timeout=90,
)
r.raise_for_status()
open("page.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com/',
full_page: 'true',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(({ writeFile }) =>
writeFile('page.webp', Buffer.from(await res.arrayBuffer()))
);
Replace YOUR_API_KEY with your key. The API accepts screenshot parameters, including full-page capture, and the response can be PNG, JPEG, WebP, or PDF. Cookie banners are accepted like a visitor and more than 60 known consent platforms, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
The Free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan. Create a free ScreenshotNeo account to get started.
8. Performance, reliability, and cost considerations
- Rendering time: A longer JavaScript delay adds wait time to every capture. Use the shortest delay that allows the page to be ready, or a window-status signal when you control the page.
- Output size: Long pages and wide viewports create larger images. Choose the width and image format for the actual use case; JPEG quality trades image detail against file size.
- Repeatability: Rendering can vary with scripts, authentication, external resources, and content loaded only after scrolling. Capture at a consistent width and readiness point, and inspect important output.
- Maintenance: The upstream wkhtmltopdf repository is archived and read-only since January 2, 2023. Treat wkhtmltoimage as a legacy choice and assess whether that maintenance status fits your project. The status is visible on the upstream repository.
- Cost: The command-line tool has no per-capture API pricing in the documented procedure, but you maintain its runtime and integration. A hosted API shifts the capture request to a service; ScreenshotNeo’s stated plans range from 1,000 free monthly shots to paid tiers, with details on its site.
9. FAQ
Do I need to set a height for a full-page screenshot?
Usually no. The documented default calculates screen height from page content. A fixed height sets screen height and may constrain what appears.
Does wkhtmltoimage capture content that loads when I scroll?
Not necessarily. Content loaded only after scrolling may not be requested during rendering. The tool does not promise to trigger every page’s lazy-loading behavior.
Can I use a local HTML file as input?
Yes. The command accepts an input file as well as a URL; provide the local HTML path followed by the output image path.
When should I switch to Playwright?
Consider it when the page depends on browser behavior that the legacy Qt WebKit renderer does not handle reliably, or when you need browser automation before taking the screenshot.


