
The first step in your workflow is setting up a Webhook node that will receive incoming data (e.g., invoice details, reports, or dynamic content).

<h1>Invoice</h1>
<p>Customer: {{ $json.customer }}</p>
<p>Amount: ${{ $json.amount }}</p>

You can use external JavaScript libraries like QRCode.js in your PDF templates. When using ES Modules, wrap your import in a module script tag:
<script type="module">
import QRCode from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
// Generate QR code
const qrDataUrl = await QRCode.toDataURL('https://example.com', {
width: 150,
margin: 1
});
// Set the image source
document.getElementById('qr').src = qrDataUrl;
</script>
<img id="qr" alt="QR Code" /> When using asynchronous JavaScript (QR codes, charts, API calls), you must signal when your content is ready by setting window.__RENDER_DONE__ = true. The PDF generator waits for this flag before capturing the page.
<script type="module">
import QRCode from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
// Initialize as false
window.__RENDER_DONE__ = false;
async function generateQR() {
// Your async operations
const qrDataUrl = await QRCode.toDataURL('https://example.com');
document.getElementById('qr').src = qrDataUrl;
// Signal that rendering is complete
window.__RENDER_DONE__ = true;
}
// Start generation
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', generateQR);
} else {
generateQR();
}
</script> ⚠️ Important: Without setting window.__RENDER_DONE__ = true, your PDF may be blank or incomplete because the generator won't wait for async operations to finish!