The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Yes—you can send a wkhtmltopdf PDF directly to an HTTP response without creating a temporary file. Run wkhtmltopdf with - as its output path, copy stdout to the response, keep stderr for diagnostics, and check the exit status. Set Content-Type: application/pdf and use Content-Disposition: attachment when the browser should download the file (or inline to open it in the built-in PDF viewer).
This guide covers process streaming, the libwkhtmltox buffer, Node.js streams, download and inline behavior, security, timeouts, failure handling, and a practical production checklist. The examples assume wkhtmltopdf 0.12.6 with patched Qt, the documented command-line release.
Choose the output pattern first
| Pattern | How it works | Memory and failure characteristics |
|---|---|---|
| Child-process stdout | Invoke wkhtmltopdf ... - and pipe stdout to the HTTP body. |
Works incrementally and avoids a temporary file. Your framework must handle backpressure and process cleanup. |
| libwkhtmltox buffer | Leave the library output setting empty, then copy the generated buffer to the response. | Simpler where a complete byte array is required, but memory grows with PDF size. |
| Node.js wrapper stream | Use the wrapper’s readable stream and pipe it after setting headers. | Natural streaming; attach error and close handlers so a failed renderer cannot leave a hanging request. |
wkhtmltopdf is a headless Qt WebKit command-line converter. It does not require an X display service. Pin the binary version in deployment and record it with your application because rendering can change when the executable changes.
HTTP headers: download or display
Force a download
Send:
Content-Type: application/pdf
Content-Disposition: attachment; filename="report.pdf"
The filename should be a fixed, validated value. Never place unsanitized user input directly in a response header.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →#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
Open in the browser viewer
Use the same content type with:
Content-Type: application/pdf
Content-Disposition: inline; filename="report.pdf"
Some clients ignore inline display because of user settings, but the disposition communicates your intended behavior.
Stream wkhtmltopdf stdout from a web endpoint
The command-line output setting accepts - for stdout. Keep stdout exclusively for PDF bytes; diagnostics belong on stderr. A non-zero exit means the generated document must not be treated as a successful PDF.
Portable process algorithm
- Validate the requested URL and any rendering options.
- Set the PDF response headers before writing body bytes.
- Spawn
wkhtmltopdf --quiet input-url -. - Copy child stdout to the response stream while separately collecting or logging stderr.
- Enforce a process timeout and terminate the child if it exceeds the limit.
- After stdout closes, inspect the exit code. If it is non-zero and headers are not committed, return an error response; if headers were committed, abort the response and log the failure.
Python (standard library)
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse
import subprocess
class PdfHandler(BaseHTTPRequestHandler):
def do_GET(self):
target = "https://example.test/"
parsed = urlparse(target)
if parsed.scheme not in ("http", "https"):
self.send_error(400, "Unsupported URL")
return
proc = subprocess.Popen(
["wkhtmltopdf", "--quiet", target, "-"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
self.send_response(200)
self.send_header("Content-Type", "application/pdf")
self.send_header("Content-Disposition", 'attachment; filename="report.pdf"')
self.end_headers()
try:
while True:
chunk = proc.stdout.read(64 * 1024)
if not chunk:
break
self.wfile.write(chunk)
self.wfile.flush()
stderr = proc.stderr.read()
code = proc.wait(timeout=90)
except (BrokenPipeError, ConnectionResetError):
proc.kill()
proc.wait()
return
except subprocess.TimeoutExpired:
proc.kill()
proc.wait()
return
if code != 0:
self.log_error("wkhtmltopdf exited %s: %s", code, stderr.decode(errors="replace"))
HTTPServer(("127.0.0.1", 8080), PdfHandler).serve_forever()
For production Python applications, use the equivalent streaming API in your framework and make the timeout, URL allow-list, and error response configurable. The example demonstrates the important separation between stdout and stderr; it is not a substitute for authentication, authorization, or a URL policy.
Node.js with a child process
import { spawn } from "node:child_process";
import http from "node:http";
http.createServer((req, res) => {
const target = "https://example.test/";
res.writeHead(200, {
"Content-Type": "application/pdf",
"Content-Disposition": 'attachment; filename="report.pdf"'
});
const child = spawn("wkhtmltopdf", ["--quiet", target, "-"], {
stdio: ["ignore", "pipe", "pipe"]
});
let diagnostics = "";
child.stderr.on("data", chunk => { diagnostics += chunk.toString(); });
child.on("error", err => {
if (!res.headersSent) res.writeHead(502, { "Content-Type": "text/plain" });
res.destroy(err);
});
child.on("close", (code, signal) => {
if (code !== 0) console.error({ code, signal, diagnostics });
if (!res.destroyed) res.end();
});
req.on("close", () => { if (!res.writableEnded) child.kill("SIGTERM"); });
const timer = setTimeout(() => child.kill("SIGKILL"), 90000);
child.on("close", () => clearTimeout(timer));
child.stdout.pipe(res);
}).listen(8080);
In a real service, decide whether an error can still change the status before calling writeHead. Once PDF bytes have been sent, an HTTP 500 status cannot replace them; destroy the connection and record the renderer diagnostics instead.
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⁴
cURL from a shell-backed endpoint
curl -sS --fail-with-body https://example.test/
| wkhtmltopdf --quiet - -
That pipeline is useful for experimentation, but an application endpoint should pass a controlled URL as an argument, not concatenate untrusted shell text. Prefer an argument array (as in the Python and Node examples) to avoid shell injection.
Using libwkhtmltox without a temporary file
The library setting for the output path has two special behaviors: - sends output to stdout, while an empty value retains the generated PDF in an internal buffer. The buffer approach suits frameworks whose response API accepts a complete byte array.
- Create and configure the global and document settings.
- Set the document output path to an empty string.
- Convert the page.
- Read the library’s generated byte buffer and its length.
- Set
Content-TypeandContent-Disposition, then write exactly that many bytes. - Free the buffer and destroy the converter even when conversion fails.
Because the entire document is resident in memory, impose a maximum page size or job limit. A large, image-heavy document can consume substantially more memory than its final compressed PDF size while WebKit renders it.
Rendering controls that affect streamed output
JavaScript and asynchronous pages
JavaScript is enabled or disabled by an explicit setting, and the documented JavaScript delay defaults to 200 milliseconds. A page that fills its content asynchronously may need a longer delay or a window-status condition; otherwise wkhtmltopdf can capture before the data appears.
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 reinstallOutdated 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 matchRank #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.
Load errors
Choose deliberately among aborting, ignoring, or skipping load errors. Aborting is safer for reports that must be complete. Ignoring can produce a usable PDF when a non-critical asset fails, but it can also hide missing content.
Local files and resources
Local-file access and resource loading should be restricted. If a document needs local images or stylesheets, grant access only to the required directory rather than enabling broad filesystem access. Review custom headers, cookies, and user-agent values for the same reason: they can expose credentials to a renderer pointed at an attacker-controlled URL.
Page geometry
Set page size, margins, orientation, and other layout options explicitly when output must be stable across environments. Keep the binary and option set together in deployment documentation.
Security and reliability boundaries
- SSRF: allow-list destination hosts and schemes; block loopback, link-local, private, and metadata-network addresses when users can supply URLs.
- Credentials: never forward arbitrary cookies, Authorization headers, or custom headers from an untrusted request.
- Resource exhaustion: cap conversion time, concurrent renderer processes, document size, and redirect behavior.
- Isolation: run the renderer with a restricted OS user and filesystem permissions. Treat HTML, CSS, JavaScript, and remote resources as untrusted input.
- Client disconnects: stop the child process when the response closes so abandoned requests do not consume a renderer slot.
- Observability: log the pinned wkhtmltopdf version, exit code, elapsed time, target policy result, and stderr without logging secrets.
Common failures and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Browser downloads an HTML error page | The application wrote an error after beginning a PDF response. | Validate before committing headers; after commitment, abort and log rather than appending HTML. |
| PDF is blank or missing dynamic content | JavaScript finished after capture. | Increase the JavaScript delay or use a window-status condition. |
| Conversion hangs | Remote resource, script, or renderer never completes. | Apply a process timeout, kill the child, and cap redirects and external requests. |
| Images or stylesheets are absent | Local-file access or resource loading is restricted, or the URL is inaccessible. | Use an explicit, narrow local allow-list and verify resource URLs from the renderer’s network context. |
| Intermittent truncated responses | Child process, client, or proxy closed early; stdout and stderr were mixed. | Pipe only stdout, handle client-close events, and inspect exit status and stderr. |
| High memory usage | Whole-document buffering or too many concurrent jobs. | Stream stdout, limit concurrency, or move large jobs to a worker queue. |
Testing and deployment checklist
- Pin wkhtmltopdf 0.12.6 patched Qt (or record the exact version you deploy).
- Test both
attachmentandinlinedispositions in your supported browsers. - Exercise successful pages, JavaScript-heavy pages, missing assets, non-zero exits, timeouts, and client disconnects.
- Verify that stderr never contaminates the PDF body.
- Load-test large PDFs and confirm backpressure, process cleanup, and memory ceilings.
- Check proxy and server limits for response time and PDF size.
- Review URL, cookie, header, and local-file policies before allowing user-supplied input.
Or skip the browser setup
If your goal is simply a clean screenshot or PDF of a web page rather than running wkhtmltopdf yourself, ScreenshotNeo provides a single HTTP call. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
Read the complete parameter reference in the ScreenshotNeo documentation. The following examples use the supplied API format:
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
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}`);
Every feature is available on every plan: 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.
Frequently Asked Questions
Can wkhtmltopdf write a PDF to stdout?
Yes. Pass - as the output argument, for example wkhtmltopdf --quiet https://example.test -, and keep stderr separate.
Should I stream or buffer the PDF?
Stream stdout when documents may be large and your framework supports backpressure. Use the library buffer when your response API requires a complete byte array and you can enforce memory limits.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Why did my endpoint return a corrupt PDF?
Common causes are mixing stderr with stdout, writing an HTML error after PDF bytes, or ignoring a non-zero renderer exit. Keep channels separate and validate the exit status.
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.




