Blog

PDF Generation in Power Automate: Complete Guide 2025

🔌 Official CustomJS Connector for Microsoft Power Automate

We provide a certified connector in the Microsoft Power Automate marketplace for professional HTML to PDF generation. No coding required—just add the connector to your flow and start generating PDFs with custom templates, QR codes, and advanced styling.

âś“ 600 Free PDFs/Month âś“ No Azure Functions âś“ HTML + CSS Support

Generating professional PDFs in Power Automate is a common requirement—invoices, receipts, reports, contracts, and certificates. While Power Automate offers basic PDF conversion from Word templates, it falls short for dynamic HTML-to-PDF generation with custom styling, complex layouts, and professional formatting.

The challenge: Power Automate's native PDF actions are limited to Word document conversion and simple HTML. For production-grade PDFs with custom CSS, multi-page layouts, headers/footers, and precise formatting, you need a more powerful solution.

This comprehensive guide covers advanced PDF generation techniques in Power Automate using CustomJS. We'll explore real-world use cases, template design, performance optimization, and best practices for creating professional PDFs at scale.

TL;DR

  • Power Automate's native PDF actions are limited—CustomJS enables professional HTML-to-PDF conversion.
  • Generate invoices, receipts, reports, and certificates with custom styling and layouts.
  • Use Nunjucks templates for dynamic data injection—no string concatenation needed.
  • Advanced features: custom fonts, headers/footers, page breaks, QR codes, and barcodes.
  • 600 free PDF generations per month, then predictable per-request pricing.

Why CustomJS for PDF Generation?

Power Automate's built-in PDF actions have significant limitations:

  • Word template dependency: Requires maintaining .docx files, limited styling options, complex setup.
  • Basic HTML support: No custom CSS, poor layout control, inconsistent rendering.
  • No templating engine: Manual string concatenation for dynamic content—error-prone and hard to maintain.
  • Limited formatting: No support for custom fonts, precise spacing, or professional layouts.

CustomJS solves these problems with a professional HTML-to-PDF engine powered by Puppeteer (Chrome headless). You get pixel-perfect rendering, full CSS3 support, custom fonts, and a powerful templating engine—all without managing servers.

Complete Example: Receipt with QR Code

This example shows a complete workflow from trigger to PDF generation with a QR code:

Power Automate Flow Overview

Complete Power Automate flow for PDF generation with QR code

Step 1: Manual Trigger - Define Input Fields

Add a "Manually trigger a flow" trigger with these input fields:

  • Receipt Number (Text) - Example: RCP-2025-001
  • Store Name (Text) - Example: Your Store Name
  • Customer Name (Text) - Example: John Doe
  • Subtotal (Number) - Example: 85.00
  • Tax (Number) - Example: 7.23
  • Total (Number) - Example: 92.23

Note: Power Automate will auto-generate internal names like text, text_1, number, number_1, etc. We'll map these to clean names in the next step.

Manual Trigger Configuration

Manual trigger with input fields for receipt data

Step 2: Data Operation - Map Data to Clean Names

Add a "Compose" action named "Receipt Data" to map the auto-generated field names to readable names:

Inputs (JSON):

{
  "receiptNumber": "@{triggerBody()?['text']}",
  "storeName": "@{triggerBody()?['text_1']}",
  "customerName": "@{triggerBody()?['text_2']}",
  "subtotal": "@{triggerBody()?['number']}",
  "tax": "@{triggerBody()?['number_1']}",
  "total": "@{triggerBody()?['number_2']}"
}

Adjust the field names (text, text_1, number, etc.) to match what Power Automate generated for your trigger fields.

Receipt Data Compose Action

Compose action mapping trigger fields to clean JSON structure

Step 3: Data Operation - Compose HTML

Add a "Compose" action named "HTML Input" with this HTML template:


<!DOCTYPE html>
<html>
<head>
  <style>
    @page { margin: 15mm; }
    body { 
      font-family: 'Courier New', monospace; 
      max-width: 400px; 
      margin: 0 auto; 
      padding: 20px;
    }
    .receipt-header { 
      text-align: center; 
      border-bottom: 2px dashed #000; 
      padding-bottom: 10px; 
      margin-bottom: 20px;
    }
    .receipt-title { 
      font-size: 24px; 
      font-weight: bold; 
      letter-spacing: 3px; 
    }
    .info-section { margin: 20px 0; }
    .totals { 
      margin-top: 20px; 
      padding-top: 10px; 
      border-top: 2px solid #000; 
    }
    .total { 
      font-size: 18px; 
      font-weight: bold; 
    }
    .qr-code { 
      text-align: center; 
      margin: 20px 0; 
    }
  </style>
  <script type="module">
    import QRCode from 'https://cdn.jsdelivr.net/npm/qrcode@1.5.4/+esm';
    
    window.__RENDER_DONE__ = false;
    
    async function generateQR() {
      try {
        const receiptUrl = 'https://yourstore.com/receipt/@{outputs('Receipt_Data')?['receiptNumber']}';
        const qrDataUrl = await QRCode.toDataURL(receiptUrl, { 
          width: 150,
          margin: 1 
        });
        document.getElementById('qr-img').src = qrDataUrl;
        window.__RENDER_DONE__ = true;
      } catch (err) {
        console.error('QR Code generation failed:', err);
        window.__RENDER_DONE__ = true;
      }
    }
    
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', generateQR);
    } else {
      generateQR();
    }
  </script>
</head>
<body>
  <div class="receipt-header">
    <div class="receipt-title">RECEIPT</div>
    <p>#@{outputs('Receipt_Data')?['receiptNumber']}</p>
    <p>@{utcNow('yyyy-MM-dd HH:mm')}</p>
  </div>
  
  <div class="info-section">
    <strong>@{outputs('Receipt_Data')?['storeName']}</strong><br>
    123 Shop Street<br>
    +1 555-1234
  </div>
  
  <div class="info-section">
    <strong>Customer:</strong> @{outputs('Receipt_Data')?['customerName']}
  </div>
  
  <div class="totals">
    <div>Subtotal: $@{outputs('Receipt_Data')?['subtotal']}</div>
    <div>Tax: $@{outputs('Receipt_Data')?['tax']}</div>
    <div class="total">Total: $@{outputs('Receipt_Data')?['total']}</div>
  </div>
  
  <div class="qr-code">
    <img id="qr-img" style="max-width: 150px;">
    <p style="font-size: 10px;">Scan to verify receipt</p>
  </div>
</body>
</html>
HTML Input Compose Action

Compose action with HTML template using clean field names

Step 4: CustomJS - HTML to PDF

Add the CustomJS "HTML to PDF" action:

HTML Content field:

@{outputs('HTML_Input')}

Click "Add dynamic content" → Select "Outputs" from your "HTML Input" Compose action

CustomJS HTML to PDF Action

CustomJS HTML to PDF action with HTML Input reference

Bonus: Upload to Google Drive

You can add a "Google Drive - Create file" action to automatically save the PDF:

Google Drive Upload Action

Upload generated PDF to Google Drive

Complete Flow Summary
  1. 1. Manual Trigger → User enters receipt data (auto-generated field names)
  2. 2. Compose "Receipt Data" → Maps to clean JSON structure
  3. 3. Compose "HTML Input" → Builds HTML using clean field names
  4. 4. CustomJS "HTML to PDF" → Generates PDF with QR code
  5. 5. Result → Base64 PDF ready for email/storage

âś“ Result: The PDF will be returned as base64-encoded content. You can then email it, save to SharePoint, or download it. The QR code will be fully rendered in the PDF!

⚠️ Important: This example uses window.__RENDER_DONE__ = true because the QR code is generated asynchronously. The PDF generator waits for this flag before capturing the page.

Related Articles

Continue reading on similar topics

Make.com PDF Generation: Complete Guide 2025
·Guide

Make.com PDF Generation: Complete Guide 2025

Learn how to automate PDF generation in Make.com with CustomJS. Step-by-step guide with templates for invoices, HTML to PDF, and page extraction. 600 free PDFs/month.

makepdfautomation
How to Execute JavaScript in Power Automate
·Guide

How to Execute JavaScript in Power Automate

Execute JavaScript code directly in Power Automate. Integrate JavaScript with CustomJS in 5 minutes – no Azure Functions needed.

power-automatejavascriptautomation
Airtable Accounting for Freelancers
·Guide

Airtable Accounting for Freelancers

Cost-effective alternative to QuickBooks & FreshBooks. Automatic PDF invoice generation with n8n, Make.com, or API integration.

airtableinvoiceaccounting

Troubleshooting Common Issues

Issue: PDF is blank or incomplete

Solution:

  • Check for JavaScript errors in template (use browser console)
  • If using async code (QR codes), ensure window.__RENDER_DONE__ = true is set
  • Verify all external resources (fonts, images) are accessible
  • Test template HTML in browser first

Issue: Layout breaks across pages

Solution:

  • Use page-break-inside: avoid on elements that should stay together
  • Add @page margins to control page layout
  • Reduce content padding and margins
  • Test with different page sizes (A4, Letter)

Issue: Fonts not rendering correctly

Solution:

  • Use Google Fonts or web-safe fonts
  • Ensure font URLs are publicly accessible
  • Add font-display: swap to font declarations
  • Test font loading in browser first

Issue: Images not appearing

Solution:

  • Use absolute URLs for images (not relative paths)
  • Ensure images are publicly accessible (no authentication required)
  • Use data URIs for small images: data:image/png;base64,...
  • Check image file size—large images may timeout

Real-World Use Cases

1. E-Commerce Order Confirmations

Automatically generate and email PDF receipts when orders are placed:

  • Trigger: New order in Shopify/WooCommerce
  • Action: Generate receipt PDF with order details
  • Action: Send email with PDF attachment
  • Action: Store PDF in SharePoint/OneDrive

2. SaaS Subscription Invoices

Create monthly invoices for recurring subscriptions:

  • Trigger: Scheduled monthly (1st of month)
  • Action: Get active subscriptions from database
  • Action: Generate invoice PDF for each customer
  • Action: Email invoice and update billing records

3. Certificate Generation

Issue course completion certificates or awards:

  • Trigger: Course completed in LMS
  • Action: Generate certificate PDF with student name and date
  • Action: Add QR code for verification
  • Action: Email certificate and store in student portal

4. Report Generation

Create formatted reports from data:

  • Trigger: Weekly/monthly schedule
  • Action: Query data from SQL/Excel/SharePoint
  • Action: Generate multi-page PDF report with charts
  • Action: Distribute to stakeholders

Best Practices

1. Template Organization

  • Store templates in SharePoint: Keep HTML templates in a document library for easy updates without modifying flows.
  • Version control: Use SharePoint versioning to track template changes.
  • Separate data from presentation: Use Compose actions to organize data—never concatenate HTML strings.
  • Test templates locally: Use our online generators to preview before deploying.

2. Performance Optimization

  • Minimize external resources: Inline CSS and use data URIs for small images.
  • Optimize images: Compress images before embedding—large images slow PDF generation.
  • Batch processing: For bulk PDFs, use parallel branches (max 5 concurrent).
  • Cache templates: Store frequently-used templates in variables instead of fetching repeatedly.

3. Error Handling

  • Validate data: Check for required fields before PDF generation.
  • Use try-catch scopes: Wrap PDF generation in error handling scopes.
  • Log failures: Send error notifications and log to SharePoint/database.
  • Retry logic: Configure retry policy for transient failures.

4. Security and Compliance

  • Sensitive data: PDFs are generated server-side—data is not stored or logged.
  • Access control: Use Power Automate's connection security for API keys.
  • Encryption: Store generated PDFs in encrypted SharePoint libraries.
  • Audit trail: Log PDF generation events for compliance.

Pricing and Limits

CustomJS PDF generation uses a simple, predictable pricing model:

  • Free tier: 600 PDF generations per month (20 per day average)
  • Pay-as-you-go: $0.01 per PDF after free tier
  • No hidden costs: No setup fees, no monthly minimums
  • Volume discounts: Contact for enterprise pricing (10,000+ PDFs/month)

Example: Generating 1,000 invoices per month = 600 free + 400 paid = $4.00/month

Conclusion

Professional PDF generation in Power Automate doesn't have to be complicated. With CustomJS, you get enterprise-grade HTML-to-PDF conversion without managing servers, dealing with Word templates, or writing complex code.

Start with our ready-to-use templates, customize them for your needs, and scale to thousands of PDFs per month. The free tier (600 PDFs/month) is perfect for small businesses and testing, while the pay-as-you-go pricing scales with your needs.

Next steps:

About the Author: This guide is maintained by the CustomJS team. We build tools that make Power Automate more powerful. Questions? Contact us at support@customjs.space