ScreenshotNeo

BlogHow-to

How to Use Cookies and Headers with wkhtmltoimage

Pass cookies and custom headers to wkhtmltoimage, control whether headers reach page resources, and troubleshoot authentication and rendering issues.

By the ScreenshotNeo team4 October 20267 min read

Direct answer: use the repeatable --cookie NAME VALUE flag for individual cookies, --cookie-jar PATH for a file-backed cookie jar, and repeatable --custom-header NAME VALUE flags for request headers. Add --custom-header-propagation if custom headers should be sent with resource requests too. Cookie values should be URL-encoded. These options control request context; they do not guarantee that the target site will accept it or that JavaScript-rendered content will be ready.

1. Pass cookies and headers on the command line

Install a wkhtmltoimage build for your environment, then use this syntax pattern, replacing the placeholders with values for a site you are authorized to access:

wkhtmltoimage \
  --cookie 'session_id' 'URL_ENCODED_COOKIE_VALUE' \
  --custom-header 'Authorization' 'Bearer TOKEN' \
  --custom-header-propagation \
  --javascript-delay 1000 \
  'https://example.test/private-page' output.png

This example sets one cookie and one custom header. Both options can be repeated to supply more than one value:

wkhtmltoimage \
  --cookie 'session_id' 'URL_ENCODED_SESSION' \
  --cookie 'locale' 'en' \
  --custom-header 'Authorization' 'Bearer TOKEN' \
  --custom-header 'X-Client-Context' 'report' \
  'https://example.test/private-page' output.png

Cookie values should be URL-encoded as directed by the project usage documentation. Encoding matters for values containing characters that have special meaning in URLs or command contexts. Do not assume that encoding the value changes the cookie name or makes an invalid or expired session valid.

Keep credentials out of source control, shared command transcripts, and shell history. The examples use placeholders; use your environment’s approved secret-handling mechanism when automating real captures. The flags document how to pass values, not a secret-storage system.

Option Use it when What to know
--cookie NAME VALUE You have a small number of known cookie values for this invocation. Repeat the flag for each cookie. URL-encode cookie values.
--cookie-jar PATH You want wkhtmltoimage to read and write cookies through a jar file. The manual describes both reading and writing. Its option description does not establish a portable file format for every browser export or packaged build.

Cookie jar example:

wkhtmltoimage \
  --cookie-jar '/path/to/cookies.txt' \
  'https://example.test/private-page' output.png

Use a jar when its lifecycle and permissions are managed by your application. Verify the file format and behavior supported by your installed binary before relying on a browser-exported jar.

3. Decide whether headers reach page resources

--custom-header NAME VALUE adds a custom request header. The repeatable --custom-header-propagation option sends configured custom headers for each resource request as well. This is useful when page assets or other resources also require the header. Without propagation, do not assume the page’s image, script, stylesheet, or other resource requests receive those custom headers.

# Send the custom header for the page request; no propagation requested
wkhtmltoimage \
  --custom-header 'Authorization' 'Bearer TOKEN' \
  'https://example.test/private-page' output.png

# Also propagate configured custom headers to resource requests
wkhtmltoimage \
  --custom-header 'Authorization' 'Bearer TOKEN' \
  --custom-header-propagation \
  'https://example.test/private-page' output.png

The manual also documents --no-custom-header-propagation. Use it to explicitly disable propagation when needed. The option description refers to each resource request; it does not define domain scoping or behavior across redirects. Check the behavior of the particular build and target site rather than assuming a security boundary.

Cookies and headers are separate controls. Use the cookie options to provide cookie values. The documentation does not establish that manually passing a Cookie: custom header is equivalent to wkhtmltoimage’s cookie handling.

4. Handle JavaScript-rendered pages

JavaScript can be enabled with --enable-javascript. Use --javascript-delay MILLISECONDS to wait after page load before capture. For example:

wkhtmltoimage \
  --enable-javascript \
  --javascript-delay 1500 \
  'https://example.test/dashboard' dashboard.png

Choose the delay for the page and validate the output. A fixed delay is not a guarantee that a single-page application, delayed API call, animation, or lazy-loaded element has finished. The project usage documentation describes a 200 ms default delay, while the cited Debian manual does not state that default; check the installed build’s help for its exact behavior.

5. Check your installed version and flags

  1. Run wkhtmltoimage --version to identify the binary.
  2. Run wkhtmltoimage --extended-help and confirm the cookie, header, propagation, and JavaScript options are present.
  3. If using a wrapper or language binding, check that binding’s own documentation. CLI flags do not prove that every API exposes equivalent settings.
  4. Make a capture against a page you control and verify both the main page and any protected resources.

Builds can differ. The Debian unstable manual and project documentation describe these options but do not guarantee identical behavior in every packaged binary or wrapper.

6. Python and Node.js automation

For automation, invoke the installed executable with an argument array so values are passed as individual arguments. Avoid constructing a shell command by concatenating untrusted values.

Python

import subprocess

args = [
    "wkhtmltoimage",
    "--cookie", "session_id", "URL_ENCODED_COOKIE_VALUE",
    "--custom-header", "Authorization", "Bearer TOKEN",
    "--custom-header-propagation",
    "--javascript-delay", "1000",
    "https://example.test/private-page",
    "output.png",
]
subprocess.run(args, check=True)

Repeat the --cookie or --custom-header pair in the list to add values. For a jar, add "--cookie-jar", "/path/to/cookies.txt" and omit individual cookie pairs as appropriate.

Node.js

import { spawn } from "node:child_process";

const args = [
  "--cookie", "session_id", "URL_ENCODED_COOKIE_VALUE",
  "--custom-header", "Authorization", "Bearer TOKEN",
  "--custom-header-propagation",
  "--javascript-delay", "1000",
  "https://example.test/private-page",
  "output.png",
];

const child = spawn("wkhtmltoimage", args, { stdio: "inherit" });
child.on("error", (error) => {
  console.error("Could not start wkhtmltoimage:", error);
  process.exitCode = 1;
});
child.on("close", (code) => {
  if (code !== 0) process.exitCode = code ?? 1;
});

These examples require wkhtmltoimage to be installed and available on PATH. Replace placeholder credentials using your controlled runtime configuration.

7. Common errors and fixes

Symptom Likely cause What to try
“Unknown option” or an option is ignored The installed binary, package, or wrapper differs from the documentation being followed. Check --version and --extended-help; confirm you are invoking the intended executable.
The page shows a login screen The cookie is missing, malformed, URL-encoding is wrong, expired, scoped differently by the site, or not accepted. Confirm the exact cookie name and current value, encode the value as documented, and verify the target URL accepts that session.
The page loads but images or styles are missing Resources may require the custom header, or may have separate access requirements. Try --custom-header-propagation if those resources need the configured header, then inspect the resulting capture.
Assets still fail with propagation enabled The server may reject the header, resources may use another authentication mechanism, or build behavior may differ. Inspect the target’s resource access requirements and verify the installed build’s help and behavior. The documentation does not specify domain or redirect scoping.
Content is blank or stale JavaScript may be disabled or the capture delay may be too short for this page. Enable JavaScript if needed and adjust --javascript-delay based on observed page rendering. A delay is page-dependent.
Cookie jar does not authenticate The file may not use a format supported by that build, may lack the required cookie, or may be unwritable when the tool updates it. Check the file path and permissions, inspect the jar contents safely, and verify format compatibility for the installed binary.
Automation exits unsuccessfully The executable may be absent, arguments may be malformed, or capture may fail. Run the exact argument list locally, check the process exit status and stderr, and confirm the output path is writable.

8. Performance, reliability, and cost

Each capture starts a renderer and loads the target page and its resources. Extra JavaScript wait time adds directly to elapsed time; the needed value depends on the page. Header propagation can affect more requests because it applies to resource requests too. The cited option documentation does not provide performance benchmarks, so measure representative pages in your own environment.

For reliable automation, set an external job timeout, retain the exit code and diagnostic output, and validate that the output file exists and is nonempty. Retry only failures that are plausibly temporary, and avoid logging live cookie or authorization values. A successful process exit alone does not prove the intended authenticated state appeared in the screenshot.

Operational cost depends on where and how often you run the binary, plus the resources and wait time each page requires. The cited sources give no runtime or cost benchmark. For recurring jobs, track capture duration and failure rate with representative pages rather than relying on a universal delay or throughput assumption.

9. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Its API accepts one GET request with a URL and returns a screenshot or PDF. The API key and request options are documented at ScreenshotNeo API docs.

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 accepts cookie and request configuration as screenshot options; see the docs for parameter names. It removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Create a free account and get 1,000 screenshots a month with no card.

10. FAQ

Yes. The project usage documentation marks both --cookie and --custom-header as repeatable options.

The manual describes --cookie-jar as reading and writing cookies to the supplied jar.

Does header propagation define which domains receive the header?

The cited description says custom headers are sent for each resource request, but does not define domain scoping or redirect behavior. Confirm the behavior for your build and target.

No such equivalence is established by the cited settings reference. It lists a cookie jar and a propagation setting, while marking cookie and custom-header settings as TODO. Check the documentation for the specific binding.