Use imgkit as the Python wrapper and install wkhtmltoimage separately as the renderer. After both are available, choose from_url, from_file, or from_string, pass wkhtmltoimage flags in an options dictionary, and write a PNG, JPEG, WebP, or another supported image format. The key setup detail is that installing imgkit alone does not install the executable it calls.
What imgkit and wkhtmltoimage each do
These are two separate pieces of software. IMGKit is a Python wrapper. It builds a command and starts the wkhtmltoimage executable for you. wkhtmltoimage is the command-line renderer from the wkhtmltopdf project; it uses Qt WebKit to turn HTML into an image.
That separation explains the most common installation error: pip install imgkit installs the Python module, but it does not provide the renderer binary. You need both components on the machine that runs your script.
Install the wrapper and the renderer
1. Install IMGKit in your Python environment
python -m pip install imgkit
Run this inside the virtual environment, container image, or system environment that will execute your application. If your platform uses a separate Python 3 command, use python3 -m pip install imgkit instead.
#1 Best Overall
2. Install wkhtmltoimage separately
Install the wkhtmltopdf package supplied for your operating system. That package provides the wkhtmltoimage executable as well as the related PDF tool. The executable must be present in the runtime environment, not merely on your development computer.
Verify the installation from a shell:
wkhtmltoimage --version
If the shell reports that the command cannot be found, IMGKit will not be able to render until you either add the directory containing the binary to PATH or provide its full path through an IMGKit configuration object.
3. Account for the project’s maintenance status
The upstream GitHub repository that contains wkhtmltoimage is marked as archived on January 2, 2023. Its official changelog lists version 0.12.6 with a release date of June 11, 2020. Treat the renderer as an older, largely fixed tool: pin the package you deploy, test representative pages, and avoid assuming that modern browser behavior or newly released web APIs will be supported.
Pick the IMGKit function that matches your input
IMGKit exposes three straightforward entry points. The destination can be a filename, or you can pass False to receive the generated bytes in memory.
| Input | Call | Use it when |
|---|---|---|
| URL | imgkit.from_url(url, output) |
The page is available over HTTP or HTTPS. |
| HTML file | imgkit.from_file(path_or_file, output) |
You already have a local HTML document. |
| HTML string | imgkit.from_string(html, output) |
Your application generated the markup in memory. |
Render a URL to an image file
import imgkit
imgkit.from_url("https://example.com", "out.jpg")
The renderer fetches the URL and writes the result to out.jpg. Use a filename extension that matches the format you intend to produce, or set the format explicitly in the options shown later.
Rank #2
Render a local HTML file
import imgkit
imgkit.from_file("page.html", "out.jpg")
You can also pass an open file object. This is useful when your code has already opened the file with a specific encoding or obtained it from another layer:
import imgkit
with open("page.html", "r", encoding="utf-8") as html_file:
imgkit.from_file(html_file, "out.jpg")
Render an HTML string
import imgkit
html = "<!doctype html><html><body><h1>Hello</h1></body></html>"
imgkit.from_string(html, "out.jpg")
For reliable local assets, use URLs that the renderer can resolve from the document. If your markup refers to relative files, keep the HTML and its assets in a predictable directory and test the same layout in the deployment environment.
Keep the result in memory
import imgkit
html = "<h1>Generated in memory</h1>"
image_bytes = imgkit.from_string(html, False)
with open("out.jpg", "wb") as output_file:
output_file.write(image_bytes)
Passing False instead of a destination path returns the image data. That lets you send it to a response, object storage, or another processing step without first creating a temporary output file.
Pass wkhtmltoimage settings through options
IMGKit forwards renderer flags through an options dictionary. Use the option name without the command-line -- prefix. Options that are switches with no value can use None, False, or an empty string. Repeated options can be represented by a list or tuple; options that accept multiple values can use a tuple.
Choose an output format explicitly
import imgkit
options = {
"format": "png"
}
imgkit.from_url("https://example.com", "out.png", options=options)
Setting format removes ambiguity when the output filename does not make the desired format obvious. The same pattern works with the file and string functions.
Represent flags and repeated values
import imgkit
options = {
"format": "png",
"some-switch": None,
"custom-header": ("X-Render-Mode", "preview"),
"cookie": ["session", "demo"]
}
imgkit.from_file("page.html", "out.png", options=options)
The exact option names and accepted values come from wkhtmltoimage. Keep the dictionary close to your rendering code and document why each flag is needed; that makes upgrades and troubleshooting easier.
Point IMGKit at a specific executable
If automatic discovery fails, construct a configuration with the full path to wkhtmltoimage and pass it to the conversion function:
Recommended Free Tools
import imgkit
config = imgkit.config(wkhtmltoimage="/opt/wkhtmltopdf/bin/wkhtmltoimage")
imgkit.from_url(
"https://example.com",
"out.png",
config=config,
options={"format": "png"}
)
Replace the example path with the path on your machine. In containers and service managers, an explicit path is often more dependable than relying on an inherited PATH.
Headless servers and Xvfb
The upstream project README describes the tools as running entirely headless, without requiring a display or display service. IMGKit’s documentation separately notes that some headless server deployments may still need Xvfb, a virtual display, and shows enabling it through the wrapper’s xvfb configuration option.
Keep these as two separate checks:
- First run the renderer without a display and see whether your environment works as supplied.
- If the process fails because the server lacks a usable display, install Xvfb according to your operating system and provide its path through IMGKit’s configuration.
import imgkit
config = imgkit.config(
wkhtmltoimage="/opt/wkhtmltopdf/bin/wkhtmltoimage",
xvfb="/usr/bin/xvfb-run"
)
imgkit.from_url("https://example.com", "out.png", config=config)
The paths above are examples. Use the actual locations installed by your system package or deployment image.
A complete reusable Python function
This example accepts any of the three source types, keeps the renderer path configurable, and returns bytes when no output path is supplied:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →from pathlib import Path
from typing import Optional, Union
import imgkit
def render_html(
source: str,
source_kind: str = "string",
output_path: Optional[Union[str, Path]] = None,
wkhtmltoimage_path: Optional[str] = None,
) -> bytes:
options = {"format": "png"}
config = imgkit.config(wkhtmltoimage=wkhtmltoimage_path) if wkhtmltoimage_path else None
destination = str(output_path) if output_path is not None else False
if source_kind == "url":
result = imgkit.from_url(source, destination, options=options, config=config)
elif source_kind == "file":
result = imgkit.from_file(source, destination, options=options, config=config)
elif source_kind == "string":
result = imgkit.from_string(source, destination, options=options, config=config)
else:
raise ValueError("source_kind must be 'url', 'file', or 'string'")
if output_path is not None:
return Path(output_path).read_bytes()
return result
if __name__ == "__main__":
png = render_html("<h1>IMGKit</h1>", source_kind="string")
Path("out.png").write_bytes(png)
For a production wrapper, validate URLs and file paths before invoking the renderer, log the selected source kind and executable path, and preserve the renderer’s stderr output when a conversion fails.
Operational checks before you automate captures
Make the source deterministic
Capture the same URL, file, or HTML string in a repeatable environment. A URL that requires authentication, depends on a private network, or changes while it loads can produce different images between runs. For local documents, package the HTML and required assets together with the application so relative references resolve consistently.
Choose the output deliberately
Use PNG when you need lossless output or crisp text, and JPEG when a smaller photographic image is more useful. Set format explicitly when the output is consumed by another program, then use a matching extension so humans and downstream tools do not have to infer the type.
Keep the binary with the application
Because IMGKit delegates rendering to an external executable, a successful local installation does not guarantee that a worker, container, or scheduled job can run it. Include the renderer in the deployment image or install it as part of provisioning, and verify it with wkhtmltoimage --version during health checks.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Best Value
Troubleshooting common failures
| Symptom | Likely cause | Fix |
|---|---|---|
ModuleNotFoundError: imgkit |
The package was installed into a different Python environment. | Activate the environment used by the application and run python -m pip install imgkit there. |
| “No wkhtmltoimage executable found” or similar discovery error | The renderer is not installed or is not on PATH. |
Install the wkhtmltopdf package, verify wkhtmltoimage --version, or pass imgkit.config(wkhtmltoimage="/full/path/to/wkhtmltoimage"). |
| The command works in a shell but fails in a service | The service has a different PATH or filesystem. |
Use an absolute executable path in the config and confirm the service account can execute it and write the destination. |
| The output file is missing or empty | The conversion returned in memory, the destination directory is unwritable, or rendering failed. | Use a writable absolute destination, check whether you passed False, and capture the exception and renderer stderr. |
| A local page is blank or missing images | Relative assets cannot be resolved from the renderer’s working context. | Check every stylesheet, image, and font reference; use resolvable paths or URLs and test the same directory layout used in deployment. |
| Remote pages fail while local HTML works | The renderer cannot reach the URL from that host, or the page depends on network resources that do not load there. | Open the URL from the same machine, check DNS and outbound access, and simplify the page to identify the failing dependency. |
| Failure on a minimal Linux server mentioning a display | The deployment needs a virtual display even though the renderer is designed for headless use. | Install Xvfb and configure IMGKit with the documented xvfb path, then rerun a minimal example. |
| Modern page layout differs from a current browser | wkhtmltoimage uses an older Qt WebKit engine; the upstream repository is archived and its latest listed release is 0.12.6 from June 11, 2020. | Reduce reliance on newer browser features, test the exact page, or choose a maintained browser-based capture service for that workload. |
When IMGKit is the right fit
IMGKit is a practical choice when your Python process already owns the HTML generation and you can install and pin a native renderer. It gives you one Python API for URLs, files, and strings while retaining wkhtmltoimage’s command-line options.
It is less convenient when you cannot install native binaries, need current browser compatibility, or must capture many unrelated sites from a server with strict network and display constraints. In those cases, a hosted screenshot API removes the binary and display setup from your application.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. Give it a URL with one GET request and it returns a PNG, JPEG, WebP, or PDF. Its cleanup step accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the capture; each cleanup step can be turned off.
Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and each response identifies the result with X-Page-Verdict and X-Billed headers. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated 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 matchFor a URL capture, the one-call form is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for all request options. The same request in Python is:
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)
And in 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}`);
ScreenshotNeo also supports full-page captures with lazy images loaded, CSS-selector element captures, dark mode, device presets and custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, click-before-capture actions, selector hiding, waits for selectors, delays or network idle, ad/tracker/request blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk requests for up to 100 URLs, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify a migration.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; yearly billing gives two months free, and every feature is included on every plan. Create a free ScreenshotNeo account to try the URL-based workflow.
Quick Recap
Final checklist
- Install
imgkitin the same Python environment as your application. - Install wkhtmltoimage separately through the wkhtmltopdf package.
- Verify the executable with
wkhtmltoimage --versionor configure its absolute path. - Use
from_url,from_file, orfrom_stringfor the corresponding input. - Pass renderer flags in an
optionsdictionary without the--prefix. - Use
Falsewhen you need image bytes in memory. - Test whether your server needs the documented Xvfb setup.
- Pin and test the older renderer deliberately, especially for modern sites.
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.




