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 include CSS from a URL in a Ruby-generated PDF, the HTML-to-PDF renderer must be able to resolve the stylesheet address and fetch it. Use an absolute HTTPS URL for a quick test; for relative URLs, give the renderer the correct document or base URL, or rewrite the asset links as absolute URLs. The right setting depends on whether you use PDFKit with wkhtmltopdf, Grover with Chromium, or another renderer—and whether you pass HTML, a URL, or a file.
First check how your stylesheet is supplied
There are two distinct ways to provide CSS: include a <link rel="stylesheet"> in the HTML, or use a renderer-specific stylesheet option. They are not interchangeable in every renderer or input mode. Before changing Ruby configuration, inspect the actual HTML given to the converter and identify the form of the stylesheet address.
- Absolute URL:
https://assets.example.com/pdf.css. The renderer still needs network access to that host. - Root-relative URL:
/assets/pdf.css. It needs a meaningful document/base URL to identify the host. - Protocol-relative URL:
//assets.example.com/pdf.css. It needs a protocol, such as HTTPS, to complete the address. - Relative URL:
assets/pdf.css. It resolves against the document URL or base path, so the base must match the location you intend.
A browser on your workstation loading the CSS successfully does not establish that a PDF renderer running in a server, container, or background job can reach it. Nor does an authenticated web page guarantee that the renderer has the cookies or credentials needed to fetch its stylesheet.
Recommended Free Tools
Choose the configuration for your Ruby renderer
| Renderer | How to supply the stylesheet | How relative paths resolve | Important boundary |
|---|---|---|---|
| PDFKit with wkhtmltopdf | Link the CSS in the HTML; for HTML input, PDFKit also documents a stylesheets helper. |
Use root_url or protocol where appropriate. |
The helper cannot be added when the source is a URL or File. |
| Direct wkhtmltopdf | Link CSS from the document or use the user stylesheet option. | Supply a usable URL or path and configure resource loading as needed. | Local-file access controls and external URL reachability are separate issues. |
| Grover with Chromium | Link CSS in HTML or use style_tag_options with a URL, local path, or inline content. |
Set display_url or preprocess relative URLs as absolute. |
Without a display URL, Grover defaults to http://example.com, which is usually not your asset host. |
PDFKit and wkhtmltopdf
PDFKit wraps wkhtmltopdf. If you pass an HTML string, put a complete stylesheet URL in the HTML for the simplest diagnostic. For relative links, PDFKit documents root_url and protocol. Its documented example uses a site root to resolve paths such as /images/cat.png, and shows protocol: 'https' for protocol-relative URLs.
#1 Best Overall
- INNOVATIVE CARTRIDGE-FREE PRINTING — No more dealing with lots of tiny ink cartridges; With this wireless document and photo printer each ink bottle set is equivalent to about 90 individual cartridges²
- LESS FREQUENT INK REPLACEMENT — Replacement ink bottles don't have to be changed nearly as often as ink cartridges¹; When you choose this combination printer, scanner and copier you can print up to 4,500 pages black/7,500 color³
- COLOR PRINTING — Up to 2 years of ink in the box4 (and with every replacement ink set) for fewer out-of-ink frustrations
- ZERO CARTRIDGE WASTE — By using an Epson EcoTank printer you can help reduce the amount of cartridge waste ending up in landfills
- HOME PRINTER DESIGNED FOR RELIABILITY — The Epson EcoTank ET-2800 All-in-One Supertank Color Printer creates vivid, detailed prints and documents thanks to Micro Piezo Heat-Free Technology; Fire off 10 ISO pages per minute1 to easily finish large jobs
HTML-string example with a base URL
html = '<html><head><link rel="stylesheet" href="/assets/pdf.css"></head><body><h1>Invoice</h1></body></html>'
kit = PDFKit.new(html, root_url: 'https://example.com/')
pdf = kit.to_pdf
File.binwrite('invoice.pdf', pdf)
This illustrates the documented base-URL pattern. Replace the example host and path with the origin and stylesheet path that actually serve your assets. The resulting PDF can only include the remote CSS if the wkhtmltopdf process can fetch it. If your stylesheet is already absolute, you can link that absolute URL in the HTML and test without relying on base-path resolution.
PDFKit stylesheet helper limitation
PDFKit documents kit.stylesheets << '/path/to/css/file' for HTML input, but explicitly says: “Stylesheets can not be added when source is provided as a URL or File.” If your current input is a URL or file, put the <link> in the source document itself, or change the input method if using the helper is important. Do not assume that adding the helper after constructing a URL/File-backed kit will attach the CSS.
PDFKit passes options through to the wkhtmltopdf executable. Confirm the option names and behavior against the executable installed in the environment running the job; an option supported by a different build may not behave the same way.
Direct wkhtmltopdf controls
If you invoke wkhtmltopdf directly, its interface includes a user stylesheet option whose value can be a URL or path. It also documents load-error behavior, with choices to abort, skip, or ignore failed resources. These controls can help distinguish a missing stylesheet from a conversion that fails on any missing asset. Check the installed binary’s help and behavior before choosing an error policy: suppressing a load error can produce a PDF successfully while silently omitting the CSS.
Rank #2
- CARTRIDGE-FREE PRINTING — Print lab-quality photos, graphics and creative projects; Get vibrant colors and sharp text with Epson's high-accuracy printhead and Claria ET Premium 6-color inks
- INK BOTTLES — Save on photos1 and creative projects with affordable in-house printing; All-in-one printer allows you to print 4" x 6" photos for about 4 cents each vs. 40 cents with traditional ink cartridges1
- LESS FREQUENT INK REPLACEMENT — Replacement ink bottles don't have to be changed nearly as often as ink cartridges¹; Printer, scanner and copier lets you print up to 6,200 color pages³
- PRINT FOR LONGER — Up to 2 years of ink in the box² (and with every replacement ink set) for fewer out-of-ink frustrations with this wireless printer
- ZERO CARTRIDGE WASTE — Epson EcoTank printer helps reduce the amount of cartridge waste ending up in landfills; Cartridge-free printer uses high-yield ink bottles; Each replacement ink bottle set is equivalent to about 100 individual ink cartridges⁴
Local-file access is a separate concern. A setting that controls access to local files does not make an external HTTPS URL reachable, and external-network access does not imply permission to read a local path. Diagnose the type of URL first, then verify the relevant access path.
Grover with Chromium
When Grover receives an HTML string, set display_url to the intended page or base so Chromium can resolve relative asset paths. The README documents that Grover otherwise defaults to http://example.com; relative URLs can therefore point somewhere unintended if your assets belong to your application host.
Set the display URL
html = '<html><head><link rel="stylesheet" href="/assets/pdf.css"></head><body><h1>Invoice</h1></body></html>'
pdf = Grover.new(html, display_url: 'https://example.com/').to_pdf
File.binwrite('invoice.pdf', pdf)
Use the actual origin serving /assets/pdf.css. Alternatively, preprocess the HTML so the stylesheet URL is absolute.
Rank #3
- SET IT UP ONCE AND PRINT WITH CONFIDENCE. No complicated maintenance. Just easy, reliable printing you can count on.
- INK FOR YEARS. NOT MONTHS. Up to 2 years of ink included. Get thousands of pages of cartridge-free printing. More pages, less hassle
- KEEPS PRINTING WELL AFTER COMPETITORS HAVE QUIT. No complex maintenance. Sharper text, richer colors.[2] Only with HP Smart Tank
- PREMIUM SUPPORT - Strong technical expertise to solve issues faster
- THE LAST PRINTER YOU'LL EVER NEED. Enjoy years of refillable, cartridge-free printing.
Add a stylesheet explicitly
Grover also documents style_tag_options for supplying a stylesheet independently of the link in the HTML. Its documented alternatives include a URL, a local path, or inline content. For an external CSS URL, the shape is:
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minutepdf = Grover.new(
html,
style_tag_options: { url: 'https://example.com/style.css' }
).to_pdf
Use one clear source of truth while debugging: either verify the link in the rendered HTML or add the explicit stylesheet option. If both are present, check whether you are loading duplicate or conflicting styles.
Rails views: inspect the generated link
Rails’ stylesheet_link_tag generates markup; it does not itself guarantee that the PDF renderer will retrieve the asset. A view may emit a full path relative to the document root or a URL, depending on the application setup. Inspect the final rendered HTML passed to the converter, not only the template or helper call.
Rank #4
- Wireless Bluetooth Printer: Portable thermal printer compatible with iPhone, Android phones, iPad and tablet computers via Bluetooth. For smartphones, please download the "Nada Print" App. You can also connect to laptops and computers for printing using a USB-C cable. (Note: Laptops and computers can only be connected via USB and require the installation of a driver first. Bluetooth connection is not supported.)
- No-ink printing: Only supports US Letter and A4 size thermal paper.(Doesn't support regular paper) The no-ink portable thermal printer uses direct thermal technology, requiring no ink, toner or ribbons, making it environmentally friendly, cost-effective and time-saving. The thermal printer package comes with a roll of US Letter thermal printing paper. Note: When installing the paper, remember to switch the paper size switch on APP
- Clear Print: NDYIN N80 portable thermal printer adopts high-definition printing technology, with a 203DPI resolution to provide you with clear printing results. This mobile printer is compatible with roll paper, folded paper and tattoo transfer paper, supporting printing from your mobile phone PDF, Word, pictures and web pages anytime and anywhere. It is recommended to use our NDYIN thermal paper to achieve good printing quality
- Portable wireless printer for travel: The thermal printer is equipped with a built-in 1500mAh rechargeable battery, which can print 160 sheets of 8.5" x 11" thermal paper after being fully charged. It weighs only 1.5 pounds and is compact in size. This ink-free portable printer can be easily carried in a backpack or briefcase! It is perfect for business travel, cars, small offices, construction sites, schools and homes. You can print documents, contracts, invoices and boarding passes anytime and anywhere
- The N80 thermal printer has a wide range of uses. The package includes the N80 printer, a roll of US Letter paper(7m/roll), a user manual, a guide card, a type-C soft cable and a type C adapter. Note: The charging adapter is not included. Special thermal paper is required for use; ordinary paper cannot be used. This ink-free portable thermal printer is suitable for various scenarios such as home, school, travel, office, and outdoor, meeting the printing needs of different groups of people. This tattoo template printer is also compatible with tattoo transfer paper, making it an ideal choice for tattoo art
- Render the Rails view using the same path used by the PDF job.
- Find the stylesheet
<link>and copy its actualhref. - Classify that value as relative, root-relative, protocol-relative, or absolute.
- For relative forms, configure a renderer base URL or convert the
hrefto an absolute URL. - Verify that the PDF process can fetch the resulting URL from its own runtime.
This avoids a common false fix: changing Rails’ asset helper when the actual problem is that the renderer received relative markup with no useful base URL.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.A debugging sequence that isolates the failure
- Inspect the input HTML. Confirm that the stylesheet link exists and determine its exact
href. If it is absent, fix the view or HTML generation before changing the PDF renderer. - Try an absolute HTTPS stylesheet URL. If that works, the CSS itself is likely being supplied, while relative URL resolution or base configuration is the likely issue. If it does not work, continue checking access and renderer logs.
- Check access from the renderer runtime. Test from the same server, container, or job environment that launches PDFKit, wkhtmltopdf, or Chromium. Check network restrictions, DNS/TLS errors, redirects, and whether the URL requires authentication unavailable to the renderer.
- Match the setting to the input mode. For PDFKit, distinguish an HTML string from URL or File input before using
stylesheets. For Grover, usedisplay_urlfor relative assets or an explicitstyle_tag_optionsURL. - Read the converter’s output and logs. Look for resource-load failures and verify the installed wkhtmltopdf build’s load-error behavior. A successful PDF conversion is not proof that every linked resource loaded.
These steps identify configuration and accessibility problems; actual behavior depends on the renderer build and deployment environment. The documented APIs do not establish that a particular production network can reach a given stylesheet host.
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 →Common symptoms and fixes
| Symptom | Likely cause | What to check |
|---|---|---|
| PDF has default or unstyled text | The link is missing, unresolved, blocked, or failed to load. | Inspect the generated HTML and try the stylesheet’s absolute HTTPS URL. |
| CSS loads in a browser but not in the PDF | The renderer runs in a different network environment or lacks required browser state. | Check reachability and authentication from the renderer process itself. |
| Root-relative assets resolve to the wrong host | No suitable base/document URL was set. | Set PDFKit’s root_url or Grover’s display_url, or make the URL absolute. |
| Protocol-relative stylesheet fails | The renderer has no intended protocol to apply. | Set PDFKit’s protocol where suitable, or use an explicit HTTPS URL. |
| PDFKit stylesheet helper has no effect | The source was passed as a URL or File. | Link CSS inside the source document or use the helper with HTML input. |
| Conversion aborts on a missing resource | wkhtmltopdf load-error behavior is set to abort, or the installed build handles the failure that way. | Inspect that build’s options and logs; choose an error policy deliberately rather than hiding a missing stylesheet. |
| Local CSS path is denied | Local-file access restrictions apply. | Check the renderer’s local-file access controls separately from external URL access. |
Performance, reliability, and security considerations
Remote CSS introduces a dependency on DNS, network routing, the asset host, and any authentication or redirect behavior involved in retrieving it. For repeatable conversions, prefer a stable asset URL accessible from the renderer’s runtime, or a local stylesheet mechanism supported by the renderer and input mode. If you use a local file, account for the renderer’s local-file access controls. If you use a public remote URL, ensure the document does not expose sensitive content through a fetchable link or rely on credentials that the PDF process does not possess.
A base URL fixes address resolution; it does not grant network access, provide missing cookies, or make an inaccessible stylesheet public. Likewise, changing a failed-resource policy can affect whether a PDF is produced, but it does not repair the stylesheet request. Treat conversion success and stylesheet inclusion as separate things to verify.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server, not a Ruby HTML-to-PDF renderer or a way to attach CSS to a PDF. If the task is to capture a web page as an image or PDF rather than generate a styled PDF from your own HTML, it can return a screenshot or PDF from one GET request. The response identifies page verdict and billing status; the service removes supported cookie/consent banners, newsletter popups, and chat widgets before capture, with each cleanup step configurable. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for MCP clients such as Claude and Cursor. Details are in 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
ScreenshotNeo offers 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots. If a screenshot/PDF API fits your job, sign up for ScreenshotNeo free.
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 →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.

