Use Poltergeist for the Capybara integration, then configure the underlying PhantomJS page for rendering. In Poltergeist, save_screenshot(path) captures the current viewport; add full: true for the whole page or selector: '#id' for one element. For PDFs, set driver.paper_size. Keep viewport settings (which control responsive layout) separate from paper size (which controls PDF pages).
These examples follow the archived Poltergeist documentation and PhantomJS APIs. Check the versions installed in your test suite before adopting them in a new project.
What Poltergeist and PhantomJS each control
Poltergeist is a Capybara driver that runs tests in a headless PhantomJS browser. Poltergeist exposes test-oriented operations such as save_screenshot, while PhantomJS supplies webpage properties such as viewportSize, paperSize and renderBase64.
- Capture area: Poltergeist chooses the viewport, full document or a CSS-selected element.
- Layout size: PhantomJS
viewportSizedetermines the width and height used for page layout. - PDF page: PhantomJS
paperSizedetermines page dimensions, margins and orientation. - Image encoding: Poltergeist’s
render_base64returns an encoded image buffer; PNG is the default and PNG, GIF and JPEG are documented formats.
Changing PDF orientation does not make a responsive page render as though it had a wider browser window. Set the viewport and paper settings independently.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitches#1 Best Overall
Install and configure the legacy driver
The README documents this basic setup:
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
Poltergeist lists PhantomJS 1.8.1 or later among its requirements and its repository is archived; the README points to the 1.18.1 release documentation. Confirm that the gem, PhantomJS binary and Capybara versions in your environment are compatible before troubleshooting the examples below.
Window and screen defaults
Poltergeist documents a window_size option as a two-item array, with [1024, 768] as the default. It also documents screen_size for the dimensions used when Window#maximize is called. Neither option is the same concept as PhantomJS’s webpage viewportSize.
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(
app,
window_size: [1280, 900],
screen_size: [1920, 1080]
)
end
Capybara.javascript_driver = :poltergeist
Use a registered driver only when you need non-default driver settings. Keep the dimensions explicit in visual tests so a change in a developer’s machine does not alter the result.
Take a viewport screenshot
After visiting a page in a Capybara example, call save_screenshot with a path. With no options, Poltergeist captures what is visible in the current viewport.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
feature 'checkout', js: true do
scenario 'captures the visible state' do
visit '/checkout'
save_screenshot('tmp/checkout-viewport.png')
end
end
The path can be absolute or relative to the process working directory. Create the destination directory first when your test runner does not do so:
FileUtils.mkdir_p('tmp')
save_screenshot('tmp/checkout-viewport.png')
A viewport capture is appropriate for checking a modal, navigation bar or above-the-fold layout. It deliberately excludes content below the current viewport.
Capture the entire page
Pass full: true to request a full-page screenshot:
visit '/article/long-read'
save_screenshot(
'tmp/long-read-full.png',
full: true
)
Full-page mode is useful for regression images of documents and landing pages. It does not change the responsive breakpoint used to lay out the page; that still comes from the viewport/window dimensions. If lazy content appears only after scrolling, make the page load it before capturing, or the resulting image may contain unloaded regions.
Rank #2
Capture one element with a CSS selector
Use selector to bound the image to an element matched by CSS:
visit '/dashboard'
save_screenshot(
'tmp/summary-card.png',
selector: '#summary-card'
)
The selector should identify the intended element in the loaded DOM. A missing or ambiguous selector can produce an error or an unexpected target, so assert the element first:
expect(page).to have_css('#summary-card')
save_screenshot('tmp/summary-card.png', selector: '#summary-card')
Element capture is different from hiding everything else with CSS: the screenshot bounds are derived from the selected element, while the page itself still renders normally.
Choose an image format or return Base64
Save PNG, GIF or JPEG
The documented screenshot examples write an image file. For lower-level access, Poltergeist exposes page.driver.render_base64(format, options). PNG is the default; PNG, GIF and JPEG are documented.
visit '/status'
encoded = page.driver.render_base64('png', full: true)
File.binwrite('tmp/status.png', Base64.decode64(encoded))
Require Ruby’s Base64 library before decoding:
require 'base64'
Use the same capture options you would pass to a screenshot where supported, such as full: true or a selector. Verify the option behavior against the installed Poltergeist release because the project is no longer actively maintained.
PhantomJS’s native renderBase64 API
At the PhantomJS page level, the documented method is page.renderBase64(format):
var page = require('webpage').create();
page.open('https://example.com', function (status) {
if (status !== 'success') {
console.log('open failed: ' + status);
phantom.exit(1);
}
console.log(page.renderBase64('png'));
phantom.exit();
});
The PhantomJS API documents PNG, GIF and JPEG output. Poltergeist’s Ruby driver is usually the easier choice inside Capybara tests; the native script is useful when you need direct PhantomJS page control.
Rank #3
Set viewport dimensions before loading
PhantomJS describes viewportSize as the headless equivalent of a traditional browser window. Set both width and height, and set them before loading the URL so responsive CSS is evaluated at the intended size.
var page = require('webpage').create();
page.viewportSize = { width: 1440, height: 900 };
page.open('https://example.com', function (status) {
if (status === 'success') {
page.render('/tmp/example-1440.png');
}
phantom.exit(status === 'success' ? 0 : 1);
});
PhantomJS specifically warns that height must be included. A width-only assignment can leave the page at an unintended layout size.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Viewport choices in a Poltergeist test
When using Poltergeist, set the driver-level window size for the test session, then capture the desired area:
Capybara.register_driver :wide_poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, window_size: [1440, 900])
end
Capybara.javascript_driver = :wide_poltergeist
Use a separate driver configuration for mobile-like widths. Do not use PDF orientation as a substitute for a viewport change.
Configure PDF output with paper size
Poltergeist advises assigning driver.paper_size= for PDF rendering. The value follows PhantomJS’s paperSize settings.
driver = page.driver
driver.paper_size = {
format: 'A4',
orientation: 'portrait',
margin: '1cm'
}
page.save_page('tmp/report.pdf')
Use the exact PDF-saving method supported by your installed Poltergeist version; the important setting is the assignment to paper_size before rendering. PhantomJS documents named formats including A3, A4, A5, Legal, Letter and Tabloid. Portrait is the documented default, and landscape is also supported.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Named formats and custom dimensions
A standard format is predictable for printing:
driver.paper_size = {
format: 'Letter',
orientation: 'landscape',
margin: {
top: '12mm',
left: '12mm',
bottom: '12mm',
right: '12mm'
}
}
For a custom page, provide width and height. PhantomJS accepts mm, cm, in and px; unitless dimensions are treated as pixels.
driver.paper_size = {
width: '5in',
height: '7in',
margin: {
top: '0.25in',
left: '0.25in',
bottom: '0.25in',
right: '0.25in'
}
}
A single margin measurement is also documented. An object with individual top, left, bottom and right margins gives you independent control. The documented default margin is zero.
Headers and footers
PhantomJS permits a repeating header or footer with a height and callback-based contents. Use this only when your Poltergeist release exposes the corresponding paper-size fields; older driver versions may not pass every PhantomJS option through unchanged.
Viewport size versus PDF paper size
| Decision | Setting | What it changes | Typical use |
|---|---|---|---|
| Browser layout | viewportSize or Poltergeist window settings |
CSS breakpoints, available layout width and visible window height | Responsive screenshots and visual tests |
| Capture area | save_screenshot options |
Viewport, full document or selected element | Focused image or complete page image |
| PDF page geometry | paperSize/paper_size |
Paper format, custom dimensions, margins and orientation | Printable PDF reports |
For a landscape report, set landscape in paperSize. If the page must also switch to a desktop breakpoint, set a wider viewport separately before navigation.
Free tools Windows power users keep installed
One-click scans. No signup required.
A complete Capybara example
This example fixes the driver window, waits for the page state through normal Capybara assertions, captures both an element and the full page, and configures PDF paper settings:
require 'capybara/rspec'
require 'capybara/poltergeist'
require 'fileutils'
Capybara.register_driver :poltergeist_visual do |app|
Capybara::Poltergeist::Driver.new(app, window_size: [1280, 900])
end
Capybara.javascript_driver = :poltergeist_visual
RSpec.describe 'invoice rendering', type: :feature do
it 'captures image and PDF states', js: true do
FileUtils.mkdir_p('tmp/renders')
visit '/invoices/42'
expect(page).to have_css('#invoice')
save_screenshot('tmp/renders/invoice-element.png', selector: '#invoice')
save_screenshot('tmp/renders/invoice-full.png', full: true)
page.driver.paper_size = {
format: 'A4',
orientation: 'portrait',
margin: '1cm'
}
page.save_page('tmp/renders/invoice.pdf')
end
end
If your release uses a different PDF helper, keep the navigation, assertions and paper_size assignment, then use that release’s documented PDF method.
Troubleshoot unexpected renders
The image is cropped at the fold
That is the default viewport behavior. Add full: true for the document or use selector for a bounded component.
The page uses the wrong responsive breakpoint
Set both viewport dimensions before navigation. In native PhantomJS, assign page.viewportSize = { width: ..., height: ... } before page.open. In Poltergeist, verify the driver’s window_size and remember that screen_size affects maximize behavior instead.
Recommended Free Tools
The PDF has the wrong margins or orientation
Inspect driver.paper_size. Use a named format for standard paper, or explicit width/height for custom pages. Set margins in the paper-size object; changing viewport dimensions will not change PDF paper geometry.
A selector capture fails or is empty
Assert that the selector exists after the page has reached its ready state. Check for duplicate IDs, frames and content that is inserted asynchronously. Capture the full page temporarily to determine whether the element is outside the expected document.
Images or charts are missing
Capture only after the page has loaded the required assets. If the application lazy-loads content on scroll, trigger the relevant interaction before taking a full-page image. PhantomJS is an old browser engine, so modern JavaScript or CSS can also render differently; isolate that possibility by comparing a simple static page.
The API works locally but not in CI
Print the installed Poltergeist and PhantomJS versions, use an absolute output path, and make the viewport dimensions explicit. Confirm that the CI image contains the PhantomJS executable and that the test process can write to the destination directory.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallPerformance and reliability considerations
- Use element or viewport captures when a full document is unnecessary; they produce smaller artifacts and reduce visual-diff noise.
- Keep one fixed driver size per visual test suite. Mixing implicit defaults makes failures difficult to reproduce.
- Separate image tests from PDF tests so a paper-size change cannot silently alter screenshot expectations.
- Store the exact options beside the test. A future maintainer needs to know whether a failure concerns viewport dimensions, capture area or paper geometry.
- Because Poltergeist and PhantomJS are legacy projects, validate output after dependency or operating-system changes rather than assuming browser behavior is current.
Or skip the browser setup
If you need a current website screenshot rather than a legacy Capybara test, ScreenshotNeo provides a single HTTP request and an MCP server for AI clients. It removes cookie and consent banners, newsletter popups and chat widgets before capture. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and each response identifies the result with X-Page-Verdict and X-Billed headers.
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)
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}`);
See the ScreenshotNeo API documentation for the 63 capture options, including full-page and CSS-selector captures, device and viewport settings, retina scale, PDF paper controls, custom CSS and JavaScript, waits, request blocking, cookies and headers, geolocation, caching, signed links, asynchronous jobs and bulk capture. Its MCP tools—take_screenshot, get_page_info and capture_pdf—work with Claude, Cursor and other MCP clients.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan, and yearly billing gives two months free. Create a free ScreenshotNeo account.
Frequently Asked Questions
Is Poltergeist still maintained?
Its repository is archived and points readers to the 1.18.1 release documentation, so verify all examples against the versions already installed in your suite.
Can I use paperSize to force a desktop responsive layout?
No. paperSize controls PDF page geometry. Set the browser viewport or Poltergeist window size separately to select a responsive breakpoint.
Which formats does renderBase64 support?
The PhantomJS documentation lists PNG, GIF and JPEG; PNG is the default documented format.
Why does a full-page capture still miss lazy content?
Full mode captures the rendered document, but content that your application loads only after scrolling or another interaction must be triggered before capture.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

