HubSpot PDF API: 3 Ways to Generate PDFs From Your CRM Data
Generate branded PDFs - invoices, NDAs, quotes, certificates - straight from HubSpot data. Three approaches, from a free no-code link to fully automated workflows. 600 free PDFs/month.
PDFMonkey is one of the most popular ways to generate PDFs inside Make.com, Zapier, and n8n. It has a clean dashboard, a friendly visual template builder, and Liquid templating that no-code teams pick up in an afternoon. So why look for a PDFMonkey alternative at all?
For most automation users it comes down to one thing: the document ceiling. PDFMonkey's free plan stops at 20 documents per month, and that free tier cannot load external images, fonts, CSS, or JavaScript (verified on pdfmonkey.io/pricing, June 2026). The moment your webhook fires more than a handful of times a day, or your template needs a chart, a QR code, or a web font, you are on a paid plan.
This guide compares PDFMonkey and CustomJS honestly: where PDFMonkey wins, where it does not, and exactly how to port a template and a Make.com or n8n scenario from one to the other. You will get a side-by-side Liquid to Nunjucks template diff, the before and after curl payloads, and a live editor to test the migration in your browser. CustomJS gives you 600 free PDFs per month, full Chromium rendering with JavaScript, and native Make.com and n8n modules under a single API key.
A note on honesty: pricing below was checked on June 30, 2026 against PDFMonkey's public pricing page. Plans change. If a number looks off, the live page is the source of truth. We are not here to bash PDFMonkey. It is a good tool, and for some teams it is the right one. This article exists to help you decide.
Any fair comparison starts with the strengths, because they are real. If these are the things you care about most, PDFMonkey may well be the better fit, and you should stay.
barcode and in_time_zone.None of that is in dispute. The question is whether you are paying for capability you actually use, and whether the limits get in your way.
Here is the pattern we hear most often from people searching for a cheaper PDFMonkey alternative. None of these are deal-breakers on their own. Stacked together, they push high-volume webhook users to shop around.
PDFMonkey's forever-free plan is 20 documents per month, with 1-day file retention, and it explicitly cannot load external images, fonts, CSS, or JavaScript. That last part surprises people: a logo hosted on your CDN, a Google Font, or a chart will not render until you upgrade. For comparison, CustomJS gives you 600 PDFs per month free, with no feature lockout. Charts and QR codes render on the free tier.
Webhook-driven automations are spiky. An order surge, a campaign, or a batch import can quintuple your document count in a day. PDFMonkey's plans step up in fixed tiers, so you size for the peak, not the average. If your monthly volume sits awkwardly between two tiers, you pay for the higher one all month.
Modern documents are not static. Sales dashboards want a Chart.js graph, packing slips want a scannable QR code, certificates want a verification barcode. PDFMonkey can do some of this through its builder and custom filters, but it does not run your own arbitrary client-side JavaScript at render time. CustomJS converts inside a full Chromium instance, so any library that runs in a browser runs in your PDF.
PDFMonkey makes PDFs. If your automation also needs to screenshot a web page or scrape a price, that is a second and third subscription. CustomJS bundles HTML to PDF, screenshots, and scraping behind a single key and a single rate limit.
PDFMonkey prices in euros, CustomJS in US dollars, so treat the cross-currency comparison as approximate. The shape is what matters: a much larger free tier and a flatter curve at the volumes most automations actually run.
| Plan | PDFMonkey | CustomJS |
|---|---|---|
| Free | 20 docs/mo, no external images, fonts, CSS or JS | 600 PDFs/mo, full rendering, no feature lockout |
| Entry paid | Starter, €5/mo, 300 docs | Pro, $9/mo, ~3,000 PDFs (100/day) |
| Mid tier | Pro, €15/mo, 3,000 docs | Ultra, $29/mo, ~15,000 PDFs (500/day) |
| High volume | Pro+, €60/mo, 5,000 docs | Mega, $99/mo, ~150,000 PDFs (5,000/day) |
| Other APIs | PDF only | PDF + screenshots + scraping, one key |
PDFMonkey figures from pdfmonkey.io/pricing, checked June 30, 2026. PDFMonkey measures monthly documents; CustomJS measures a daily request limit, so the monthly figures above are approximate. Always confirm current limits on each provider's pricing page.
The honest read: at the very top end PDFMonkey's Premium plan (€300/mo for 60,000 docs) is a clean managed offering, and its dashboard is part of what you pay for. At the free and mid tiers, where most automations live, CustomJS is dramatically cheaper per PDF and removes the free-tier feature lockout entirely.
| Feature | PDFMonkey | CustomJS |
|---|---|---|
| Free documents / month | 20 | 600 |
| Template engine | Liquid (v4) | Nunjucks |
| Visual template builder | Yes (drag-and-drop) | No (HTML/CSS first) |
| Document dashboard / history | Yes | API-first (return URL or base64) |
| Arbitrary JavaScript at render | Limited | Yes, full Chromium |
| External images / fonts on free tier | No | Yes |
| Native Make.com module | Yes | Yes |
| Native n8n node | Yes | Yes |
| Screenshots & scraping | No | Yes, same key |
Below is a PDFMonkey-style invoice rebuilt as a CustomJS Nunjucks template. The left panel is the HTML template, the right is the JSON data that PDFMonkey would call document.payload. Edit either side and render the PDF in your browser. This is the same engine that powers the production API.
The variables you see, like {{ invoice_number }} and the {% for item in items %} loop, are Nunjucks. If you have ever written a PDFMonkey Liquid template, this will feel immediately familiar.
This is the part most people overestimate. Liquid and Nunjucks share the same fundamentals: {{ }} for output, {% %} for logic, loops, conditionals, and filters with the pipe character. For a typical invoice or report, the diff is small.
<h1>Invoice {{ document.invoice_number }}</h1>
<p>Billed to: {{ document.customer.name }}</p>
<table>
{% for item in document.items %}
<tr>
<td>{{ item.description }}</td>
<td>{{ item.price | times: item.qty }}</td>
</tr>
{% endfor %}
</table>
{% if document.is_paid %}
<span class="badge">PAID</span>
{% endif %}
<p>Date: {{ document.created_at | date: "%B %d, %Y" }}</p><h1>Invoice {{ invoice_number }}</h1>
<p>Billed to: {{ customer.name }}</p>
<table>
{% for item in items %}
<tr>
<td>{{ item.description }}</td>
<td>{{ item.price * item.qty }}</td>
</tr>
{% endfor %}
</table>
{% if is_paid %}
<span class="badge">PAID</span>
{% endif %}
<p>Date: {{ created_at }}</p>The handful of things to know when you port a template:
| Concern | Liquid (PDFMonkey) | Nunjucks (CustomJS) |
|---|---|---|
| Data root | {{ document.x }} | {{ x }} (your JSON is the root) |
| Filters | {{ n | times: 2 }} | {{ n * 2 }} or {{ n | round }} |
| Loops | {% for x in list %} | {% for x in list %} (identical) |
| Conditionals | {% if x %}...{% endif %} | {% if x %}...{% endif %} (identical) |
| Dates | | date: "%B %d" | Format in your code, or use moment |
The biggest practical change is the data root. PDFMonkey nests your payload under document; with CustomJS your JSON object is the template context directly. A find-and-replace of document. for nothing handles most of it. For full template capabilities, see the HTML to PDF API reference.
PDFMonkey is a two-step API: create a document from a template ID and data, then poll or wait for the generated file. CustomJS is a single synchronous call that returns the PDF.
curl -X POST 'https://api.pdfmonkey.io/api/v1/documents' \
-H 'Authorization: Bearer YOUR_PDFMONKEY_KEY' \
-H 'Content-Type: application/json' \
-d '{
"document": {
"document_template_id": "TEMPLATE_ID",
"status": "pending",
"payload": { "invoice_number": "INV-001", "total": "1,250.00" }
}
}'
# then fetch document.download_url once status is "success"curl -X POST 'https://e.customjs.io/html2pdf' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"input": {
"html": "<h1>Invoice {{ invoice_number }}</h1><p>Total: {{ total }}</p>",
"data": { "invoice_number": "INV-001", "total": "1,250.00" }
}
}' > invoice.pdf One request, one PDF, no polling loop. Send input.data and the HTML is rendered through Nunjucks before conversion. Omit it and you can pass finished HTML straight through.

If your Make.com scenario already uses the PDFMonkey app, swapping it for CustomJS is a one-module change. The trigger, the data mapping, and the downstream steps (email, Google Drive, Slack) all stay exactly the same.
Trigger (Webhook / Sheets / Airtable)
-> PDFMonkey: Create a Document
template: Invoice
payload: mapped fields
-> PDFMonkey: Find a Document (wait for "success")
-> Email: send with download_urlTrigger (Webhook / Sheets / Airtable)
-> CustomJS: HTML to PDF
html: your Nunjucks template
data: mapped fields
-> Email: send with PDF output (no polling step)Notice the scenario got shorter: the "Find a Document" wait step disappears because CustomJS returns the file in the same call. To set it up, add the CustomJS module, paste your API key once as a connection, and map the same fields you already mapped into PDFMonkey's payload. Full walkthrough in the Make.com integration guide and the HTML to PDF module docs.
For invoices specifically, there is also a dedicated Invoice Generator module that takes structured line-item data and skips templating entirely, closer to PDFMonkey's builder experience.
The n8n story is the same shape. Replace the PDFMonkey node with the CustomJS node, or, if you prefer raw control, an HTTP Request node pointed at the endpoint.
{
"method": "POST",
"url": "https://e.customjs.io/html2pdf",
"authentication": "genericCredentialType",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{ "name": "x-api-key", "value": "YOUR_API_KEY" }
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "input",
"value": "={{ { html: $json.template, data: $json.invoice } }}"
}
]
},
"options": { "response": { "response": { "responseFormat": "file" } } }
}Install the community node, add your API key as a credential, and pick the HTML to PDF operation. Map your template and data fields, and the node returns the PDF as binary you can attach to an email or push to storage. See the n8n HTML to PDF node docs and the installation guide.
Using Zapier instead? CustomJS works there too via a Webhooks by Zapier POST step using the same payload as the curl example above, so a PDFMonkey-on-Zapier flow ports without restructuring.
This is the clearest reason to switch, and the hardest to work around if you stay. Because CustomJS converts in a real headless Chrome, your template can load any browser library and run it before the PDF is captured. Charts, QR codes, barcodes, and dynamic layouts all work.
The one rule: when your template does asynchronous work, set window.__RENDER_DONE__ = true when the content is ready, and the renderer waits for that flag before capturing the page.
<div id="qr"></div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/qrcode.min.js"></script>
<script>
new QRCode(document.getElementById("qr"), {
text: "https://verify.example.com/INV-001",
width: 120,
height: 120
});
// tell CustomJS the async render finished
window.__RENDER_DONE__ = true;
</script>We cover this pattern in depth in HTML to PDF with async JavaScript and generating QR codes in PDFs.
A migration guide that pretends the other tool is never the right choice is not worth reading. Stay on PDFMonkey if:
For everyone else, especially teams that want a bigger free tier, render-time JavaScript, and one key across PDF, screenshots, and scraping, CustomJS is the leaner fit.
PDFMonkey is a good product with a great dashboard and a gentle learning curve. The reasons to look for an alternative are not about quality. They are about the free-tier ceiling, the per-call cost at volume, and the lack of arbitrary JavaScript at render time.
CustomJS keeps the parts you like, Liquid-style templating becomes near-identical Nunjucks, native Make.com and n8n modules, the same field mapping, and adds 600 free PDFs a month, full Chromium rendering, and a single key that also does screenshots and scraping. Migration is a templating swap and a one-module change in your scenario, not a rebuild.
Start free with 600 PDFs per month
Continue reading on similar topics
Generate branded PDFs - invoices, NDAs, quotes, certificates - straight from HubSpot data. Three approaches, from a free no-code link to fully automated workflows. 600 free PDFs/month.
Compare the best form builders for automation in 2026. CustomJS vs. Typeform vs. Jotform vs. Tally vs. Fillout. Features, pricing, and real-world use cases. Save $420-1,056/year on automation costs.
How to create a mailhook in n8n: IMAP trigger, Gmail trigger, parser services, Mailgun/SendGrid inbound parse, and CustomJS Mail Hook compared on latency, setup, attachments, and cost. 600 free emails/month.