HTML to PDF: Templates, Invoices & Arabic RTL avatar

HTML to PDF: Templates, Invoices & Arabic RTL

Pricing

from $2.40 / 1,000 pdf generateds

Go to Apify Store
HTML to PDF: Templates, Invoices & Arabic RTL

HTML to PDF: Templates, Invoices & Arabic RTL

HTML to PDF converter for templates and Markdown. Merge JSON, CSV or dataset rows with Handlebars to make one PDF per row: invoices, certificates, reports. Page size, margins, header, footer, page numbers, Arabic RTL fonts. Public PDF links.

Pricing

from $2.40 / 1,000 pdf generateds

Rating

0.0

(0)

Developer

Malik Said

Malik Said

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Security

Limited permissions

Share

Turn an HTML or Markdown template into PDF files. Add a list of data rows, and the Actor makes one PDF per row. Use it for invoices, receipts, certificates, letters and reports. Each PDF gets a public download link in the dataset.

The template uses Handlebars fields such as {{customer}}. Rows can come from JSON, pasted CSV, an Apify dataset or a URL. You choose the page size, margins, header, footer and page numbers. Arabic and other right-to-left documents print correctly with bundled Arabic fonts.

What you can use it for

  • Invoices and receipts from an order export, one PDF per order.
  • Course certificates or badges from a list of names.
  • Monthly reports with tables and charts, in English or Arabic.
  • Letters, quotes and contracts from a spreadsheet.
  • Markdown notes or documentation as clean printable PDFs.
  • PDFs from the output of another Actor: pass its dataset ID.

How to use it

  1. Paste your template in Template. HTML gives full control with your own CSS. For Markdown, set Template type to Markdown.
  2. Add your rows in Data rows (JSON), Data rows (CSV), Apify dataset ID or Data URL.
  3. Set File name, for example invoice-{{number}}.
  4. Pick the page size, margins and an optional header and footer.
  5. Optional: turn on Also save one ZIP of all PDFs or Also save one merged PDF to get every document in one download or one printable file. Both are free.
  6. Run. Open the PDF links in the dataset, or use the ZIP and merged PDF links in the BUNDLES record.

Leave the template empty to try the built-in sample: three two-language invoices.

Input example

{
"template": "<h1>Invoice {{number}}</h1><p>Bill to: {{customer}}</p><table>{{#each items}}<tr><td>{{name}}</td><td>{{formatCurrency (multiply qty price) ../currency}}</td></tr>{{/each}}</table><p>Total: {{formatCurrency (sum items \"qty\" \"price\") currency}}</p>",
"data": [
{ "number": "INV-1001", "customer": "Example Trading LLC", "currency": "USD", "items": [{ "name": "Design work", "qty": 10, "price": 45 }] }
],
"fileName": "invoice-{{number}}",
"pageFormat": "A4",
"marginTop": "20mm",
"footerTemplate": "<div style=\"text-align:center\">Invoice {{number}}, page <span class=\"pageNumber\"></span> of <span class=\"totalPages\"></span></div>"
}

Template fields and helpers

Handlebars fills {{field}} with the value from the row and escapes HTML in it. Use {{{field}}} with three braces only for HTML you trust. Loops ({{#each items}}), conditions ({{#if paid}}) and nested fields ({{customer.name}}) work.

HelperExampleResult
formatNumber{{formatNumber 1234.5 decimals=2 locale="de-DE"}}1.234,50
formatCurrency{{formatCurrency 99 "SAR" locale="ar-SA"}}٩٩٫٠٠ ر.س.‏
formatDate{{formatDate date style="long"}}October 1, 2026
sum{{sum items "qty" "price"}}Sum of qty x price
add, subtract, multiply, divide{{multiply qty price}}Number
eq{{#if (eq status "paid")}}true or false
upper, lower, default{{default note "None"}}Text
json{{{json labels}}}JSON for a script, such as a chart

Every row also gets _rowNumber (from 1), _index (from 0) and _runDate (today, YYYY-MM-DD).

Arabic and right-to-left documents

  • Text direction Auto keeps the dir of your HTML. Without one, the Actor picks right to left when most letters are Arabic or Hebrew. You can also force left to right or right to left.
  • Five fonts are bundled: Noto Sans, Noto Sans Arabic, Noto Naskh Arabic, Cairo and Amiri, in regular and bold. Use them by name in your CSS, for example font-family: 'Cairo'. Default font sets the font for text your CSS does not style.
  • The default page-number footer is in Arabic for right-to-left pages: صفحة 1 من 3.
  • Use CSS logical properties such as text-align: start so one template works in both directions.

Images, fonts and scripts

The page has no network access by default. This keeps your data private and stops a template from reaching other systems. To load images, web fonts, CSS or chart libraries, add their hosts to Allowed asset hosts, for example cdn.jsdelivr.net, or fonts.googleapis.com and fonts.gstatic.com for Google Fonts. Subdomains are included.

  • Requests to other hosts are blocked. The row counts them in blockedRequests and lists the hosts in blockedHosts.
  • Local and private network addresses are always refused, even when allowed.
  • Each asset is fetched once per run and reused for every PDF, up to 15 MB per file.
  • Images in the header and footer must be data: URLs. This is a Chromium rule.
  • For charts, turn off animation and fixed-size canvases print best (Chart.js: animation: false, responsive: false).
  • When a script fills the page late, set Wait for element to a CSS selector, for example #chart[data-ready]. Each PDF prints as soon as that element exists, up to 20 s per row. A row whose element never appears is saved as failed with a reason and is free.

Output

One dataset row per data row. Generated PDFs are saved in the run's key-value store.

With the ZIP or merged PDF options on, the key-value store also holds all-pdfs.zip and all-pdfs.pdf (or numbered parts for very large runs). The BUNDLES record lists each file with its link, file count, size and, for the merged PDF, its page count. They are not charged and add no dataset rows.

FieldMeaning
rowNumberPosition of the data row, from 1. Rows can finish out of order
statusgenerated, or failed with a reason
fileNameThe name from your File name template
fileKeyKey in the key-value store. Letters other than a to z become dashes
fileUrlPublic link to download the PDF
fileSizeBytes, pageCountSize and number of pages
pageFormat, landscape, directionHow the PDF was printed
blockedRequests, blockedHosts, assetErrorsNetwork requests that were blocked or failed
renderMsTime to render and save the PDF

The row does not copy your data row.

Sample record from a test run of the default input:

{
"id": "6c5e00e6325074a4",
"rowNumber": 1,
"status": "generated",
"reason": null,
"fileName": "invoice-INV-1001.pdf",
"fileKey": "invoice-INV-1001.pdf",
"fileUrl": "https://api.apify.com/v2/key-value-stores/y70ojoszSBrciNR8w/records/invoice-INV-1001.pdf?signature=1nveIAM9YRl1h0XwFpPZz",
"fileSizeBytes": 21569,
"pageCount": 1,
"pageFormat": "A4",
"landscape": false,
"direction": "ltr",
"templateType": "html",
"blockedRequests": 0,
"blockedHosts": [],
"assetErrors": [],
"renderMs": 451,
"scrapedAt": "2026-10-22T09:18:42.527Z"
}

Limits and memory

  • One PDF may take up to 60 seconds. A slower page is retried twice, then saved as a free failed row.
  • The Actor prints one PDF at a time. At the default 1,024 MB, a 1,000-invoice run finished with no failures in tests.
  • Long documents need more memory. In tests, 100-page tables printed at 1,024 MB. 200-page tables needed 2,048 MB. Set the memory in the run options.
  • A PDF that runs out of memory is saved as a free failed row. The other rows go on.
  • Tagged PDF (for screen readers) makes files much larger. It is off by default.
  • A ZIP part holds up to 1,000 PDFs or 1 GB. A merged PDF part holds up to 100 MB of PDFs. Larger runs get numbered parts. If a bundle cannot be built, each PDF keeps its own link and the run still succeeds.

Pricing

You pay a small start fee per run and a fee for each PDF generated. Failed rows are free. See the Pricing tab for the current prices.

To capture live web pages as screenshots or PDFs, use Website Screenshot & PDF Capture. This Actor is for documents you build from your own templates and data.

Support

Report a problem in the Issues tab. Include the run link and, if you can, a small template that shows the problem.