Generate PDFs and Images with Puppeteer: From Beginner to Production

Generate PDFs and Images with Puppeteer: From Beginner to Production

Imagine this: you need to generate weekly sales report PDFs or automatically create images for social media. Manual work is too tedious? Let Puppeteer help you!

What is Puppeteer?

Puppeteer is like a "headless" Chrome browser that you can control with code. What can it do?

  • 📄 Convert web pages to PDF
  • 📸 Take screenshots of web pages
  • 🤖 Automate testing
  • 📊 Generate reports

Best of all, it's completely free and maintained by Google!

💡 Quick Tip: If you need a simpler solution and don't want to handle server deployment and maintenance, consider using BulkDesign API. It provides ready-made templates and cloud rendering services, letting you focus on business logic rather than technical implementation.

Quick Start

Installing Puppeteer

# Create new project
mkdir my-pdf-generator
cd my-pdf-generator
npm init -y

# Install Puppeteer
npm install puppeteer

Installation will automatically download Chrome, so it might take a few minutes.

First Example: Web Page to PDF

Create generate-pdf.js file:

const puppeteer = require('puppeteer');

async function createPDF() {
  // Launch browser
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  // Navigate to webpage
  await page.goto('https://www.google.com');
  
  // Generate PDF
  await page.pdf({ 
    path: 'my-first-pdf.pdf',
    format: 'A4' 
  });
  
  // Close browser
  await browser.close();
  
  console.log('PDF generation complete!');
}

createPDF();

Run it:

node generate-pdf.js

That's it! Your first PDF is generated.

Practical PDF Generation Tips

1. Custom PDF Styling

async function createStyledPDF() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  await page.goto('https://your-website.com');
  
  await page.pdf({
    path: 'styled-report.pdf',
    format: 'A4',
    printBackground: true,  // Include background colors
    margin: {
      top: '20px',
      right: '20px',
      bottom: '20px',
      left: '20px'
    },
    // Add header and footer
    displayHeaderFooter: true,
    headerTemplate: '<div style="font-size:10px; text-align:center; width:100%;">My Report</div>',
    footerTemplate: '<div style="font-size:10px; text-align:center; width:100%;">Page <span class="pageNumber"></span></div>'
  });
  
  await browser.close();
}

2. HTML Content to PDF

Don't want to generate from web pages? Use HTML content directly:

async function htmlToPDF() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  const htmlContent = `
    <!DOCTYPE html>
    <html>
    <head>
      <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .header { color: #333; border-bottom: 2px solid #007acc; }
        .content { margin-top: 20px; line-height: 1.6; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>Monthly Sales Report</h1>
        <p>Generated on: ${new Date().toLocaleDateString()}</p>
      </div>
      <div class="content">
        <h2>This Month's Highlights</h2>
        <ul>
          <li>Sales increased by 25%</li>
          <li>150 new customers</li>
          <li>98% customer satisfaction</li>
        </ul>
      </div>
    </body>
    </html>
  `;
  
  await page.setContent(htmlContent);
  await page.pdf({ 
    path: 'sales-report.pdf',
    format: 'A4',
    printBackground: true
  });
  
  await browser.close();
  console.log('Sales report generated!');
}

Web Screenshots Made Easy

1. Basic Screenshots

async function takeScreenshot() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  // Set page size
  await page.setViewport({ width: 1200, height: 800 });
  
  await page.goto('https://www.google.com');
  
  // Take screenshot
  await page.screenshot({ 
    path: 'screenshot.png',
    fullPage: true  // Capture entire page
  });
  
  await browser.close();
  console.log('Screenshot complete!');
}

2. Capture Specific Elements

async function captureElement() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  await page.goto('https://your-dashboard.com');
  
  // Wait for element to load
  await page.waitForSelector('.chart-container');
  
  // Capture only the chart section
  const element = await page.$('.chart-container');
  await element.screenshot({ path: 'chart.png' });
  
  await browser.close();
}

3. Generate Social Media Images

async function createSocialImage() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  // Set Twitter image dimensions
  await page.setViewport({ width: 1200, height: 675 });
  
  const htmlContent = `
    <!DOCTYPE html>
    <html>
    <head>
      <style>
        body {
          margin: 0;
          background: linear-gradient(45deg, #667eea, #764ba2);
          display: flex;
          align-items: center;
          justify-content: center;
          height: 100vh;
          font-family: Arial, sans-serif;
          color: white;
        }
        .container {
          text-align: center;
          padding: 40px;
        }
        h1 { font-size: 48px; margin-bottom: 20px; }
        p { font-size: 24px; opacity: 0.9; }
      </style>
    </head>
    <body>
      <div class="container">
        <h1>🚀 New Feature Launch</h1>
        <p>Tools that make work more efficient</p>
      </div>
    </body>
    </html>
  `;
  
  await page.setContent(htmlContent);
  await page.screenshot({ 
    path: 'social-media.png',
    type: 'png'
  });
  
  await browser.close();
}

🎨 Designer-Friendly Alternative: If you frequently need to generate social media images, try BulkDesign's template system. You can design templates in a visual editor, then batch generate personalized images via API without writing complex HTML/CSS code.

Real-World Application Scenarios

1. Automated Report System

const express = require('express');
const app = express();

app.get('/generate-report/:userId', async (req, res) => {
  try {
    const userId = req.params.userId;
    
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    
    // Visit user-specific report page
    await page.goto(`https://your-app.com/report/${userId}`);
    
    // Wait for data to load
    await page.waitForSelector('.report-ready');
    
    const pdf = await page.pdf({ format: 'A4' });
    await browser.close();
    
    res.setHeader('Content-Type', 'application/pdf');
    res.send(pdf);
    
  } catch (error) {
    res.status(500).send('Report generation failed');
  }
});

app.listen(3000, () => {
  console.log('Report service started on port 3000');
});

2. Batch Processing

async function batchGenerate(urls) {
  const browser = await puppeteer.launch();
  
  for (let i = 0; i < urls.length; i++) {
    const page = await browser.newPage();
    
    try {
      await page.goto(urls[i]);
      await page.pdf({ 
        path: `report-${i + 1}.pdf`,
        format: 'A4' 
      });
      
      console.log(`PDF ${i + 1} generation complete`);
      
    } catch (error) {
      console.log(`PDF ${i + 1} generation failed:`, error.message);
    }
    
    await page.close();
  }
  
  await browser.close();
  console.log('All PDFs generated!');
}

// Usage example
const reportUrls = [
  'https://example.com/report/1',
  'https://example.com/report/2',
  'https://example.com/report/3'
];

batchGenerate(reportUrls);

âš¡ Batch Processing Optimization: For large-scale batch processing, BulkDesign API provides dedicated batch rendering endpoints and asynchronous processing capabilities. You can submit multiple tasks at once and receive completion notifications via webhooks, avoiding long waits and timeout issues.

Common Problem Solutions

1. Chinese Font Issues

// When using in Docker, need to install Chinese fonts
const browser = await puppeteer.launch({
  args: ['--font-render-hinting=none']
});

// Or specify fonts in HTML
const htmlWithChineseFont = `
  <style>
    body { 
      font-family: "Microsoft YaHei", "SimHei", sans-serif; 
    }
  </style>
`;

2. Waiting for Content to Load

async function waitForContent() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  await page.goto('https://dynamic-content-site.com');
  
  // Wait for specific element to appear
  await page.waitForSelector('.data-loaded');
  
  // Or wait for network idle
  await page.goto(url, { waitUntil: 'networkidle2' });
  
  await page.pdf({ path: 'complete-content.pdf' });
  await browser.close();
}

3. Memory Optimization

// For heavy processing, remember to clean up promptly
async function optimizedGeneration() {
  const browser = await puppeteer.launch({
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  
  try {
    // Your processing logic
    const page = await browser.newPage();
    // ... processing code
    await page.close(); // Remember to close pages
    
  } finally {
    await browser.close(); // Ensure browser closes
  }
}

Production Deployment

Docker Configuration

FROM node:16-slim

# Install Chrome dependencies
RUN apt-get update \
    && apt-get install -y wget gnupg \
    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
    && apt-get update \
    && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

CMD ["node", "server.js"]

🚀 Maintenance-Free Cloud Solution: If you don't want to handle Docker deployment, server maintenance, and scaling issues, you can directly use BulkDesign Cloud API. We've handled all the infrastructure, you just need to call the API to get high-quality rendering results.

Summary

Puppeteer makes PDF and image generation super simple:

✅ Easy Installation: One command to get started ✅ Powerful Features: PDF, screenshots, automation all possible ✅ Highly Customizable: Styles and dimensions as you wish ✅ Production Ready: Maintained by Google, stable and reliable

Choose the Right Solution

Choose Puppeteer if you:

  • Need complete control over the rendering process
  • Have complex custom requirements
  • Are willing to handle server deployment and maintenance

Choose BulkDesign API if you:

  • Want to get started quickly and focus on business logic
  • Need visual template design tools
  • Want to avoid server operations work
  • Need batch processing and asynchronous rendering

Next Steps

  1. Start Simple: Try basic PDF generation first
  2. Gradually Optimize: Add styling and error handling
  3. Expand Applications: Combine with your business scenarios
  4. Performance Tuning: Pay attention to memory management when processing large amounts of data

Start your automation journey now! Check the Puppeteer official documentation for questions or try BulkDesign free templates.


Related Resources:

Quick Experience: Want to immediately experience automated image generation? Try this simple API call:

curl -X POST https://api.bulkdesign.app/render/template \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "demo-template",
    "format": "png",
    "jsonData": {
      "headline.content": "Your First Automated Image!"
    }
  }'

Ready to automate your work? Start coding! 🚀

About the author

I'm a software engineer with over 10 years of professional experience. My expertise lies in recommendation systems and image processing algorithms, with a passionate interest in design principles and practices. I enjoy bridging the gap between technical solutions and creative design approaches.