This is a small compatibility module, not the official pdfkit package. Replace
import pdfkit with import pdfkit_compat as pdfkit to send from_string or
from_url calls to the existing hiver/bulk-website-screenshots Actor.
Chromium renders the PDF; no local wkhtmltopdf installation is needed.
This is a paid cloud call, not a free local renderer. HTML and URLs go to Apify. Do not send secrets, private documents or sensitive customer records without first reviewing Apify's handling and retention policies. Use your own Apify account and token; this repository contains none.
Clone this repository, install its dependency and run your script from the repo
(or copy pdfkit_compat.py next to your script):
git clone https://github.com/hiver-data/pdfkit-alternative.git
cd pdfkit-alternative
python -m pip install -r requirements.txtSet APIFY_TOKEN in your environment using your own secret manager. The module
also accepts token= or an injected apify_client.ApifyClient via client=.
No request is made until you call a rendering function.
import pdfkit_compat as pdfkit
options = {
'page-size': 'Letter',
'orientation': 'Landscape',
'margin-top': '0.5in',
'margin-right': '0.5in',
'margin-bottom': '0.5in',
'margin-left': '0.5in',
'print-media-type': None,
}
pdfkit.from_string('<h1>Invoice</h1><p>Paid</p>', 'invoice.pdf', options)
pdfkit.from_url('https://en.wikipedia.org/wiki/Cat', 'cat.pdf', options)
# Saving returns True. False/None as the output path returns PDF bytes.
pdf_bytes = pdfkit.from_string('<p>Receipt</p>', False, options)Each call starts exactly one Actor run. All calls set max_total_charge_usd=1.00,
1024 MB memory, a 300-second run timeout and a 330-second wait. Change the charge
cap explicitly if needed:
pdfkit.from_string('<p>Receipt</p>', 'receipt.pdf', max_total_charge_usd=0.02)A charge cap is a platform limit, not a price quote or a promise the entire cap
will be spent. The module does not automatically retry billed calls. An
unfinished/failed run raises PDFKitError; inspect that run before calling
again. Existing output files are replaced atomically only after the complete
PDF has been fetched. Output directories must already exist.
from_string(html, path, options)andfrom_url(url, path, options)accept one nonempty string.from_file, lists, CSS file arguments, headers/footers, cookies, authentication, local-file access and pdfkitconfigurationare not supported. Unknown options raise before starting a paid run.page-sizemaps topageSize: A4, Letter, Legal, A3, A5 or Tabloid.orientationmaps tolandscape: Portrait or Landscape.margin-top/right/bottom/leftmap to the Actor's four-sidemarginobject. Nonnegative mm/cm/in/px/pt work; unitless numeric margins are millimetres.print-media-typemaps toformat: pdf: Chromium's PDF output always uses print CSS, whether the flag is omitted or passed as None/empty string/True. Screen-media rendering is not supported.- Defaults are the Actor's A4 portrait, zero margins, printed backgrounds — NOT wkhtmltopdf's default margins. Chromium layout/fonts, JavaScript and pagination are not guaranteed to match wkhtmltopdf byte-for-byte.
- HTML has a 2 MiB UTF-8 limit, uses about:blank and cannot read local files. Relative external resource URLs need absolute URLs or an HTML base element. URLs must be http(s) without embedded credentials.
- JavaScript gets the Actor's normal loading/delay behaviour; this is not a guarantee arbitrary asynchronous applications have finished rendering.
For HTML lists and mixed HTML + URL batches, use the Actor directly rather than calling this scalar shim in a loop. One run can use:
{
"html": ["<h1>Invoice</h1>", "<h1>Receipt</h1>"],
"urls": ["https://en.wikipedia.org/wiki/Cat"],
"format": "pdf",
"pageSize": "Letter",
"landscape": true,
"margin": "0.5in"
}Board run xCcB7tEdn6snKVWj8 (2026-10-14, build 0.1.19) returned 4/4 successful
PDF files from three HTML strings plus Wikipedia Cat, with zero error rows and
four screenshot-taken charge events. Every page in all four downloaded files
has MediaBox [0, 0, 792, 612] (Letter landscape). The Promise/fetch/arrow-script
HTML printed MODERN_JS_PRINTED. Run time: 36.568 seconds at 1024 MB. This is one
cloud smoke, not a long-term reliability or competitor bench result.
Public pricing checked on 2026-10-14: $0.80 per 1,000 successfully stored files
on the free tier, plus Apify's $0.00005 per-run-per-GB start event; paid tiers are
lower. Failed captures have no screenshot-taken event (the start event still
applies). Check the Store page for current pricing. The board's $0.0023973 run
usage is platform credit usage, not the customer's per-event bill.
python -m unittest -vThe tests make no Apify runs or HTTP requests. They use the board's full exported input/rows and the actual first HTML PDF. The URL-success transport test explicitly substitutes that small invoice PDF for a download; it is not the cloud Cat PDF. The exact Cat row separately tests detection of truncated output. The four full cloud PDFs were independently downloaded and checked in the issue's cloud gate. Install requirements before running the 21 tests: they exercise the installed SDK's real ActorClient.call signature, dataset pagination and binary-record deserializer without HTTP. The fake client also rejects unknown SDK keywords. Synthetic run metadata is labelled in the test; the row and PDF come from the board export.
Both apify-client 3.3.0 and 2.5.1 were checked in fresh virtual environments on
2026-10-14: pip install -r requirements.txt apify-client==VERSION, all 21 tests
passed with no skips, and a fake-token from_string('<h1>x</h1>', False, {'page-size': 'Letter'}) reached Apify's HTTP 401 authentication error (no
TypeError, no billed run). The shim uses timedelta timeouts and normalizes the
Run model on 3.x; 2.x uses seconds and a dictionary. Requirements allow >=2.5,<4.
This module is MIT licensed. Fixtures document our own board run; no pdfkit source code is copied. No affiliation with pdfkit or wkhtmltopdf.