Use Paged.js in Rails in one of two ways: load its browser polyfill when users need an interactive paginated preview and can print from the browser, or run the Paged.js CLI with a headless browser when your application must create PDFs unattended. Rails supplies the HTML, print CSS and JavaScript through the asset setup your application already uses. The official documentation describes Rails asset delivery and Paged.js workflows separately, so treat the wiring below as an integration to test against your Rails and Paged.js versions.
Choose the rendering architecture first
| Decision | Browser polyfill | CLI/headless workflow |
|---|---|---|
| Best for | Interactive preview and a user-triggered print-to-PDF flow | Automated PDF creation from jobs, controllers or deployment scripts |
| Runs in | A browser loading the Rails document, script and stylesheets | A command-line process using a headless browser |
| Main integration work | Serve paged.polyfill.js, HTML and print CSS from Rails |
Install the CLI dependencies and make the rendered page and assets reachable to the renderer |
| Important limitation | The browser’s Save as PDF dialog controls paper, margins and other print settings | Deployment, asset URLs and Rails orchestration are application-specific |
Paged.js describes itself as an open-source library that transforms HTML and print CSS into paginated, print-ready output. Its overview and getting-started documentation explain both the browser preview and command-line approaches (project overview; getting started).
Prepare a Rails document for pagination
Keep print structure in the view
Render the report, invoice or book chapter as ordinary HTML. Use semantic elements for headings, tables and figures, then put page-oriented rules in a print stylesheet. A minimal Rails view might be:
<article class="report">
<header class="report-cover">
<h1><%= @report.title %></h1>
<p>Prepared <%= l(@report.created_at.to_date) %></p>
</header>
<section class="chapter">
<h2>Summary</h2>
<%= sanitize @report.summary_html %>
</section>
</article>
Use CSS for most layout decisions:
@page { size: A4; margin: 18mm 16mm 20mm; }
@media print {
.report-cover { break-after: page; }
h1, h2, h3 { break-after: avoid; }
table, figure { break-inside: avoid; }
.running-footer { position: running(footer); }
}
@page {
@bottom-center { content: element(footer); }
}
Test the rules in the browser and in the CLI renderer. Browser support for advanced paged-media features can differ from the output path, so do not assume that a successful preview guarantees an identical automated PDF.
#1 Best Overall
Expose a dedicated print endpoint
A dedicated action prevents navigation, authentication and interactive application chrome from becoming part of the document:
# config/routes.rb
get "/reports/:id/print", to: "reports#print", as: :print_report
# app/controllers/reports_controller.rb
def print
@report = current_user.reports.find(params[:id])
render layout: "print"
end
The print layout should include only the stylesheet and scripts needed by the document. If the endpoint requires authentication, the browser preview can use the user’s session; a background CLI process will need an intentionally designed access method such as a signed, short-lived URL or suitable request headers. Do not expose private reports through an unprotected URL.
Deliver Paged.js through Rails
Rails applications commonly use import maps or a JavaScript bundler, while the asset pipeline serves static assets and build output. Follow the stack already present in your application rather than introducing a second JavaScript delivery system. See the Rails JavaScript guide and Asset Pipeline guide.
Bundler-based application
Install the Paged.js package using the package manager and import it from the entry point produced by your existing bundler. The exact package and export shape can change, so verify the current Paged.js installation instructions before pinning it. Ensure the resulting build is written to the directory your Rails asset configuration serves (for example, app/assets/builds when using jsbundling-rails).
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →// app/javascript/application.js
// Keep this import aligned with the Paged.js distribution selected by your app.
import "./paged-print";
Then include the compiled entry in the print layout with your application’s normal Rails helper, commonly javascript_include_tag for an asset-pipeline file.
Rank #2
Import-map application
Import maps deliver browser modules without a bundling step. Pin a distribution only after confirming that it is an ES module suitable for your browser targets; the reviewed Rails and Paged.js pages do not certify a particular import-map pin. If the distribution is not import-map compatible, serve a standalone script as a Rails asset instead.
Standalone script asset
Place the chosen Paged.js browser script where the asset pipeline can serve it, precompile it as required by your deployment, and include it only on the print page. The getting-started guide calls for loading paged.polyfill.js in a document served by a web server, because the polyfill must fetch the document’s CSS.
Browser preview with the polyfill
- Create the print endpoint and stylesheet.
- Make the page reachable over HTTP(S); opening a local file directly can prevent CSS and font requests from working.
- Load the Paged.js polyfill after the document’s stylesheets, using the delivery method selected for your Rails app.
- Open the endpoint in a browser and wait for pagination to finish. Inspect page breaks, missing assets and console errors.
- Use the browser’s Print or Save as PDF command. Select the intended paper size, margins, scale and background options in that dialog.
Paged.js performs its transformation in the page, so images, fonts and CSS must resolve from URLs the browser can access. Use absolute or correctly rooted asset URLs when the page may be rendered outside the normal Rails host.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Optional readiness indicator
Do not make a controller assume that the document is paginated merely because the initial HTML loaded. Add a small client-side indicator or disable the print button until the polyfill has completed, using the event or API exposed by the Paged.js version you installed. Confirm that API against the package documentation; event names are version-sensitive.
Automated PDFs with the Paged.js CLI
The CLI guide documents installing pagedjs-cli and pagedjs, then invoking a command such as:
pagedjs-cli index.html -o result.pdf
The CLI launches a headless browser and runs Paged.js automatically. The guide is dated 2019, so check current package installation, supported Node.js and browser-runtime requirements before using this command in production.
Make Rails content available to the renderer
There are three practical patterns:
- Public or signed URL: point the CLI at the print endpoint. This is simplest, but protect private data with a short-lived signature and HTTPS.
- Exported HTML: render the Rails view to a file and rewrite asset URLs so the headless browser can fetch CSS, fonts and images.
- Application worker: enqueue a job that invokes the CLI, captures its exit status and stores the PDF outside the request cycle.
Whichever pattern you choose, test the exact runtime environment. A URL that works in your development browser may fail in a worker because of DNS, authentication, firewall rules, CSP, missing fonts or expiring credentials.
Run the CLI from a Rails job
# app/jobs/render_report_pdf_job.rb
class RenderReportPdfJob < ApplicationJob
queue_as :default
def perform(report_id)
report = Report.find(report_id)
input = Rails.root.join("tmp", "report-#{report.id}.html")
output = Rails.root.join("tmp", "report-#{report.id}.pdf")
File.write(input, ApplicationController.render(
template: "reports/print",
layout: "print",
assigns: { report: report }
))
success = system("pagedjs-cli", input.to_s, "-o", output.to_s)
raise "Paged.js failed" unless success && File.exist?(output)
report.pdf.attach(io: File.open(output), filename: "report-#{report.id}.pdf")
ensure
File.delete(input) if input && File.exist?(input)
File.delete(output) if output && File.exist?(output)
end
end
For production, prefer a process-spawning API that avoids shell interpolation, set a job timeout, capture stderr, and clean temporary files on failure. Large documents should run outside the web request with bounded concurrency.
CSS first, JavaScript hooks when necessary
Keep page size, breaks, counters and running content in CSS whenever possible. Paged.js also documents handlers and hooks for transformations that cannot reasonably be expressed in source markup or CSS, such as modifying content during parsing or layout. Read the handlers and hooks documentation and verify method names against your installed version; that page is dated 2020.
Use a hook for a specific, tested requirement—for example, adding a generated label to a page header—not as a replacement for basic print CSS. Keep custom code isolated from your Rails application JavaScript so it cannot alter ordinary interactive pages.
Rank #4
Rails and Paged.js troubleshooting
The polyfill does not paginate
- Confirm the page is served over HTTP(S), not opened as a
file://URL. - Check that the script actually loaded in the browser network panel and that its asset URL was precompiled.
- Look for JavaScript exceptions caused by loading a module as a classic script, or vice versa.
- Verify that the stylesheet is reachable and contains print rules. A blocked CSS request leaves Paged.js without the layout information it needs.
Images, fonts or styles are missing in a PDF
- Use URLs resolvable from the headless browser, not paths that exist only on the Rails server’s filesystem.
- Check authentication, CSP, CORS and mixed-content errors.
- Wait for the assets to load before invoking the CLI or capture process; lazy-loaded images may require an explicit trigger in your page.
- Install the fonts in the renderer’s operating-system image and use deterministic font stacks.
The CLI works locally but fails in a worker
- Install the same Node.js, CLI and headless-browser dependencies in the worker image.
- Log the command’s stderr and exit status, and use an absolute executable path if PATH differs.
- Check sandbox permissions, shared-memory limits and outbound network access.
- Make temporary input/output directories writable and clean them after both success and failure.
Page breaks differ between preview and automation
Use the same Paged.js version, stylesheet, viewport assumptions and font files in both paths. Browser print settings affect the interactive Save as PDF flow, while CLI flags and runtime defaults affect automation. Compare generated HTML and computed styles before changing break rules.
Recommended Free Tools
Performance, reliability and security checklist
- Cache stable CSS, fonts and images, but invalidate cached assets when their content changes.
- Generate large PDFs asynchronously and report job progress instead of holding an HTTP request open.
- Bound concurrent headless-browser processes; each consumes CPU and memory.
- Record the Paged.js, CLI, Node.js and browser versions used for a PDF so a later regeneration is explainable.
- Sanitize user-authored HTML and constrain outbound requests to prevent server-side request forgery when rendering URLs.
- Set explicit timeouts and fail closed when required assets or pages do not load.
Or skip the browser setup
If your requirement is simply to obtain a clean screenshot or PDF of a URL, ScreenshotNeo provides a website screenshot API and MCP server. It removes cookie-consent banners, newsletter popups and chat widgets before capture; bot checks, blank pages, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info and capture_pdf—work with Claude, Cursor and other MCP clients.
For a one-call image request, see the ScreenshotNeo documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo supports full-page and element captures, 12 device presets plus custom viewports, retina scale, PDF paper and page-range controls, custom CSS and JavaScript, click and wait conditions, request blocking, headers and cookies, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, which can simplify migration.
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 provides two months free. Create a free ScreenshotNeo account.
Windows 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 reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteFAQ
Does Rails have an official Paged.js integration?
No. Rails documents asset delivery and Paged.js documents its browser and CLI workflows separately, so your application must connect those pieces.
Best Value
Should a user-facing report use the CLI?
Usually not. The browser polyfill gives an immediate preview and lets the user control the browser’s print dialog; reserve the CLI for repeatable, unattended generation.
Can I use Paged.js hooks for every layout rule?
Hooks are intended for document-specific transformations. Prefer print CSS for ordinary page sizing, breaks, counters and running content.
Frequently Asked Questions
Does Rails have an official Paged.js integration?
No. Rails documents asset delivery and Paged.js documents its browser and CLI workflows separately, so your application must connect those pieces.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsShould a user-facing report use the CLI?
Usually not. The browser polyfill gives an immediate preview and lets the user control the browser’s print dialog; reserve the CLI for repeatable, unattended generation.
Can I use Paged.js hooks for every layout rule?
Hooks are intended for document-specific transformations. Prefer print CSS for ordinary page sizing, breaks, counters and running content.
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.




