Why Automate Report Generation?

Every business generates reports: sales summaries, analytics dashboards, client deliverables, compliance documents. Doing this manually means hours of copy-pasting data into templates, adjusting formatting, and exporting PDFs.

With the ToolCenter HTML-to-PDF API, you can turn any HTML template into a polished PDF in a single API call. Feed it data, get a report.

The Architecture

The workflow is straightforward:

  1. Fetch your data — Database query, API call, or spreadsheet
  2. Render HTML template — Inject data into an HTML template
  3. Convert to PDF — Send the HTML to ToolCenter
  4. Deliver — Email, upload to S3, or serve to users

Step 1: Design Your Report Template

Create a professional HTML report template:

<!DOCTYPE html>
<html>
<head>
  <style>
    @page { size: A4; margin: 40px; }
    body { font-family: 'Helvetica Neue', sans-serif; color: #333; line-height: 1.6; }
    .header { display: flex; justify-content: space-between; align-items: center;
      border-bottom: 3px solid #667eea; padding-bottom: 20px; margin-bottom: 30px; }
    .logo { font-size: 24px; font-weight: bold; color: #667eea; }
    .meta { text-align: right; font-size: 14px; color: #666; }
    h1 { font-size: 28px; color: #1a1a1a; margin-bottom: 10px; }
    .summary-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin: 30px 0; }
    .card { background: #f8f9fa; border-radius: 8px; padding: 20px; text-align: center; }
    .card-value { font-size: 32px; font-weight: bold; color: #667eea; }
    .card-label { font-size: 14px; color: #666; margin-top: 5px; }
    table { width: 100%; border-collapse: collapse; margin: 20px 0; }
    th { background: #667eea; color: white; padding: 12px; text-align: left; }
    td { padding: 10px 12px; border-bottom: 1px solid #eee; }
    tr:nth-child(even) { background: #f8f9fa; }
    .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd;
      font-size: 12px; color: #999; text-align: center; }
  </style>
</head>
<body>
  <div class="header">
    <div class="logo">Acme Analytics</div>
    <div class="meta">
      <div>Monthly Sales Report</div>
      <div>{{reportDate}}</div>
    </div>
  </div>

  <h1>{{reportTitle}}</h1>

  <div class="summary-cards">
    <div class="card">
      <div class="card-value">{{totalRevenue}}</div>
      <div class="card-label">Total Revenue</div>
    </div>
    <div class="card">
      <div class="card-value">{{totalOrders}}</div>
      <div class="card-label">Orders</div>
    </div>
    <div class="card">
      <div class="card-value">{{avgOrderValue}}</div>
      <div class="card-label">Avg Order Value</div>
    </div>
  </div>

  <h2>Top Products</h2>
  <table>
    <tr><th>Product</th><th>Units Sold</th><th>Revenue</th></tr>
    {{#products}}
    <tr><td>{{name}}</td><td>{{units}}</td><td>{{revenue}}</td></tr>
    {{/products}}
  </table>

  <div class="footer">
    Generated automatically on {{generatedAt}} | Confidential
  </div>
</body>
</html>

Step 2: Populate the Template with Data

Use a template engine to inject your data:

const Handlebars = require('handlebars');
const fs = require('fs');

function renderReport(data) {
  const templateSrc = fs.readFileSync('./templates/report.html', 'utf-8');
  const template = Handlebars.compile(templateSrc);

  return template({
    reportTitle: `Sales Report — ${data.month} ${data.year}`,
    reportDate: new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }),
    totalRevenue: `$${data.totalRevenue.toLocaleString()}`,
    totalOrders: data.totalOrders.toLocaleString(),
    avgOrderValue: `$${(data.totalRevenue / data.totalOrders).toFixed(2)}`,
    products: data.topProducts,
    generatedAt: new Date().toISOString(),
  });
}

Step 3: Convert to PDF with ToolCenter

const axios = require('axios');

async function generatePDF(html) {
  const response = await axios.post(
    'https://api.toolcenter.dev/v1/pdf',
    {
      html: html,
      format: 'A4',
      margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' },
      printBackground: true,
      preferCSSPageSize: true,
    },
    {
      headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
      responseType: 'arraybuffer',
    }
  );

  return Buffer.from(response.data);
}

Step 4: Put It All Together

async function createMonthlyReport(month, year) {
  // 1. Fetch data from your database
  const data = await fetchSalesData(month, year);

  // 2. Render HTML
  const html = renderReport(data);

  // 3. Convert to PDF
  const pdf = await generatePDF(html);

  // 4. Save or send
  const filename = `sales-report-${year}-${month}.pdf`;
  fs.writeFileSync(`./reports/${filename}`, pdf);

  // Optional: send via email
  await sendEmail({
    to: '[email protected]',
    subject: `Sales Report — ${month}/${year}`,
    attachments: [{ filename, content: pdf }],
  });

  return filename;
}

Python Implementation

import requests
from jinja2 import Template
from datetime import datetime

def generate_report(data):
    # Load and render template
    with open('templates/report.html') as f:
        template = Template(f.read())

    html = template.render(
        report_title=f"Sales Report — {data['month']}",
        report_date=datetime.now().strftime('%B %d, %Y'),
        total_revenue=f"${data['total_revenue']:,.2f}",
        total_orders=f"{data['total_orders']:,}",
        products=data['top_products'],
    )

    # Convert to PDF
    response = requests.post(
        'https://api.toolcenter.dev/v1/pdf',
        json={
            'html': html,
            'format': 'A4',
            'margin': {'top': '20mm', 'bottom': '20mm', 'left': '15mm', 'right': '15mm'},
            'printBackground': True,
        },
        headers={'Authorization': 'Bearer YOUR_API_KEY'},
    )

    return response.content

Scheduling Reports

With Cron (Node.js)

const cron = require('node-cron');

// Generate monthly report on the 1st at 9 AM
cron.schedule('0 9 1 * *', async () => {
  const now = new Date();
  const lastMonth = now.getMonth(); // 0-indexed, so this is last month
  const year = now.getFullYear();
  await createMonthlyReport(lastMonth, year);
  console.log('Monthly report generated and sent!');
});

With AWS Lambda

exports.handler = async (event) => {
  const { month, year } = event;
  const filename = await createMonthlyReport(month, year);
  return { statusCode: 200, body: `Report generated: ${filename}` };
};

Advanced Features

Adding Charts

Include chart images in your report using a charting library:

const { ChartJSNodeCanvas } = require('chartjs-node-canvas');

async function renderChart(data) {
  const canvas = new ChartJSNodeCanvas({ width: 600, height: 300 });
  const image = await canvas.renderToDataURL({
    type: 'bar',
    data: {
      labels: data.map(d => d.month),
      datasets: [{ label: 'Revenue', data: data.map(d => d.revenue) }],
    },
  });
  return image; // data:image/png;base64,...
}

Embed it in your HTML template:

<img src="{{chartImage}}" style="width:100%;max-width:600px;" />

Multi-Page Reports

For long reports, use CSS page breaks:

.page-break { page-break-after: always; }

Headers and Footers

const response = await axios.post('https://api.toolcenter.dev/v1/pdf', {
  html: html,
  format: 'A4',
  headerTemplate: '<div style="font-size:10px;text-align:center;width:100%;">Acme Corp — Confidential</div>',
  footerTemplate: '<div style="font-size:10px;text-align:center;width:100%;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
  displayHeaderFooter: true,
});

Conclusion

Automated report generation eliminates hours of manual work. Design your templates once in HTML/CSS, populate them with live data, and let the ToolCenter PDF API handle the conversion. Whether it’s daily dashboards, weekly summaries, or monthly analytics, the pipeline stays the same: data in, PDF out.