Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To load JavaScript from a URL while generating a PDF in Ruby, put a valid script URL in the HTML and ensure the PDF renderer can resolve and fetch it. Then wait for the script’s page work to finish before capturing the PDF. A <script src> tag alone does not prove the renderer loaded or executed the file. The exact setup depends on whether your Ruby integration uses Chromium, such as Grover or FerrumPdf, or wkhtmltopdf, as used by PDFKit and Wicked PDF.

1. Add the script URL to the HTML

For a Rails template, use Rails’ javascript_include_tag. Its argument can be an asset-pipeline asset name or a URL:

<%= javascript_include_tag "https://assets.example.test/pdf/chart.js" %>

Replace the example URL with the actual script location. The helper emits a script reference in the rendered HTML; it does not fetch the file on behalf of the PDF converter or confirm that the converter can reach it. Rails documents the helper and its URL behavior at the Rails Asset Pipeline guide.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If the JavaScript is part of your Rails app, an asset-pipeline reference is often more maintainable than a separately hosted URL. For a Wicked PDF template, its wicked_pdf_javascript_include_tag helper is another option. Ensure the asset is available in production: Wicked PDF’s documentation recommends precompiling PDF assets. See Wicked PDF’s project documentation.

#1 Best Overall

In either case, inspect the final HTML—not just the template—to verify the script tag points to the intended URL. The PDF renderer runs in its own browser or process context, so a URL that works in your interactive browser may still fail there because of DNS, TLS, authentication, firewall rules, or the renderer’s URL base.

2. Make the script URL resolvable and reachable

When the converter receives raw HTML, relative paths such as /assets/chart.js need a base URL. Otherwise, the renderer may resolve them against an unintended address. Prefer a full absolute URL when practical, or set the base/display URL using the option supported by your renderer.

Ruby integration Renderer URL and base handling
Grover Puppeteer with Chromium Provide display_url or preprocess relative URLs into absolute ones. Without a supplied display URL, Grover documents a default display URL of http://example.com.
FerrumPdf Chromium Use display_url as the base for relative URLs in supplied HTML.
PDFKit wkhtmltopdf For raw HTML with relative resources, configure root_url and, if needed, protocol, or use complete URLs.
Wicked PDF wkhtmltopdf Use its Rails integration and PDF-specific asset helpers; confirm PDF assets are available in the deployed asset setup.

Consult the relevant project documentation for option names and syntax in the version you have installed: Grover, FerrumPdf, PDFKit, and Wicked PDF. These integrations do not use interchangeable rendering engines or options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The renderer must also be allowed to make the request. Check reachability from the same host, container, or network environment where PDF generation runs. If the script is private, provide the required authentication in a way supported by your renderer; do not assume that a user’s logged-in browser session or cookies are automatically available to the PDF process.

3. Choose an engine that can run the page’s JavaScript

Loading a script and executing it are separate requirements. Select the renderer based on the JavaScript your page needs, and validate that engine against the actual page and deployment environment.

Grover: Puppeteer and Chromium

Consider Grover when the PDF depends on contemporary browser JavaScript. Its documentation describes URL or inline-HTML input, wait controls, request-failure handling, JavaScript error handling, and supplementary script execution. Confirm the installed Puppeteer and Chrome versions work together and that the browser can access the target URLs. Grover documents localhost access restrictions introduced with Puppeteer v24.16.0 and Chrome 139, as well as file-URI access being disabled by default. Treat these as security boundaries, especially with user-controlled HTML; do not enable broad access casually.

FerrumPdf: Chromium

FerrumPdf is another Ruby interface to Chromium. Its documented options include URL or HTML input, a display URL for relative resources, JavaScript controls, and wait-for-idle settings. Review its current documentation and your installed version before relying on a specific option.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

PDFKit and Wicked PDF: wkhtmltopdf

PDFKit wraps wkhtmltopdf, and Wicked PDF provides Rails integration with wkhtmltopdf. Their documentation relevant to this task emphasizes correct resource paths and asset availability. Do not assume they support the same modern browser behavior or feature set as current Chromium-based renderers. Test the exact JavaScript and page layout you need with the version deployed.

There is no universally best renderer established for every Ruby application. Compare JavaScript compatibility, network and authentication behavior, readiness controls, URL-base handling, production asset setup, deployment footprint, and compatibility with your project’s versions.

4. Wait until the page is ready before creating the PDF

A script can load successfully and still be working when the PDF is generated. It may fetch data, render a chart, or update the DOM asynchronously. Prefer a page-specific readiness condition—for example, an element or state that your app sets only after rendering is complete—over assuming a fixed delay will always be enough.

Grover wait controls

Grover documents options including wait_for_function and wait_for_timeout, along with request-failure and JavaScript-error handling. A function-based condition can represent the page’s actual completion state. A timeout is simpler but may be too short on a slow run and unnecessarily long on a fast one. Check Grover’s documentation for the exact option syntax for your installed version: Grover on GitHub.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Puppeteer navigation and PDF capture

Puppeteer’s PDF guide demonstrates navigating with waitUntil: 'networkidle2' before calling page.pdf. That can help when the page’s outstanding network requests are a useful readiness signal, but it is not equivalent to confirming your application-specific rendering finished. Pages with polling, long-lived requests, or delayed work may need a more precise signal. Puppeteer also states: “By default, the Page.pdf() waits for fonts to be loaded.” Font readiness does not imply that JavaScript-driven data or DOM updates are complete. See Puppeteer’s PDF generation guide.

FerrumPdf idle waits

FerrumPdf exposes wait-for-idle configuration. Use it when network quiet is appropriate for the page, and check whether its behavior fits pages that make ongoing or delayed requests. For application-specific completion, a page readiness signal remains more meaningful than a generic idle condition. See FerrumPdf’s project documentation.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

5. A practical implementation sequence

  1. Render the HTML: Use javascript_include_tag for a Rails asset or the full URL, and inspect the output for the expected src.
  2. Set the resource base: Use absolute URLs or the renderer’s documented base/display URL for relative scripts and other assets.
  3. Check access from the renderer’s environment: Confirm DNS, TLS, network egress, authentication, and the script response are all valid from the worker or container generating the PDF.
  4. Choose and configure the engine: Verify it can execute the page’s JavaScript and that the installed browser and Ruby integration versions are compatible.
  5. Wait for meaningful completion: Configure a page-specific condition where possible; use network-idle or a timeout only when it is suitable for the page.
  6. Generate and inspect the PDF: Check whether the expected JavaScript-driven content is present, then review browser logs or failed requests if it is missing.

6. Troubleshoot missing JavaScript or incomplete PDF content

  • The script tag is missing or points to the wrong place: Inspect the final rendered HTML. Verify the helper argument and confirm the output contains the correct src.
  • A relative URL resolves incorrectly: Supply an absolute URL or configure the correct renderer base. PDFKit documents missing paths and reachability as reasons images, CSS, and JavaScript may not appear.
  • The URL works locally but not during PDF generation: Test from the same machine, container, or network as the renderer. Check DNS, TLS certificates, outbound network policy, response status and content type, and any required authentication.
  • The script loads, but its result is absent: The page may still be doing asynchronous work. Wait for a page-specific completion condition; inspect JavaScript errors and failed network requests where the renderer exposes them.
  • Assets work in development but fail after deployment: Check production asset compilation and use the PDF integration’s documented helpers where appropriate. Wicked PDF recommends precompiling PDF assets.
  • The app hangs while fetching its own assets: PDFKit documents a deadlock risk when callback requests reach a single-thread development server. Serve assets independently, use multiple workers, or inline appropriate small assets to avoid that callback dependency.
  • You are considering base64 inlining: Wicked PDF describes it as an option for small assets. It avoids separate resource requests but can make HTML larger, so it is not a blanket replacement for serving larger scripts.
  • A local or file URL is blocked: Review browser security configuration. Grover documents file-URI access as disabled by default and warns about enabling it for untrusted input. Its documented localhost restriction boundary is Puppeteer v24.16.0 and Chrome 139; confirm behavior against your installed versions rather than weakening access controls by default.

7. Or skip the browser setup

If your goal is to capture a URL as a PDF without managing the Ruby renderer, browser installation, and page readiness yourself, ScreenshotNeo offers a website screenshot API with PDF output. For this Ruby example, make the request and save the response body as a PDF:

require "net/http"
require "uri"

uri = URI("https://api.screenshotneo.com/v1/shot")
uri.query = URI.encode_www_form(
  access_key: "YOUR_API_KEY",
  url: "https://stripe.com",
  format: "pdf"
)

response = Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 90) do |http|
  http.get(uri.request_uri)
end

raise "Screenshot request failed: #{response.code} #{response.message}" unless response.is_a?(Net::HTTPSuccess)

File.binwrite("page.pdf", response.body)

See the ScreenshotNeo API documentation for request options and response details. Cookie banners are accepted before capture, and 60+ known consent platforms, newsletter popups, and chat widgets can be removed; each of these steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The Free plan includes 1,000 shots 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. Sign up for ScreenshotNeo’s free plan to try it with 1,000 screenshots a month and no card.

Frequently Asked Questions

Does adding a script URL to Rails HTML guarantee it runs in the PDF?

No. It creates a script reference; the renderer still has to resolve, fetch, execute, and finish the work triggered by that script.

Should I use network idle or a fixed delay?

Use a page-specific readiness condition when possible. Network-idle waits and fixed delays are useful only when their assumptions fit the page.

Can I use the same renderer options for Grover and PDFKit?

No. Grover uses Puppeteer/Chromium, while PDFKit uses wkhtmltopdf; configure each according to its own documentation.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.