SnapPDFSnapPDF
← back to showcase
EXAMPLE BUILD — illustrative architecture, not a published case study

Clearform

Weekly customer reports delivered without a cron-job archaeology team.

Analytics SaaS · Series A · 22 engineers

The build

Clearform delivers a Monday-morning PDF report to 5,200 B2B customers. Previously, a 3-node Puppeteer cluster generated them. Now it's a Vercel Cron → SnapPDF pipeline with 99.98% delivery reliability.

Stack

  • · Next.js
  • · PostgreSQL
  • · Vercel Cron
  • · Chart.js
  • · Resend
  • · SnapPDF

Architecture

your app/from-imagesSnapPDF/mergeSnapPDF/add-page-numbersSnapPDF/watermarkSnapPDFdelivery

Ops used: /from-images → /merge → /add-page-numbers → /watermark

How they use SnapPDF

Clearform tracks product-engagement metrics for B2B SaaS companies. Every Monday at 06:00 UTC, each customer receives a PDF summarizing the previous week — usage by cohort, retention curves, feature-adoption deltas, a custom executive summary generated by a prompt-chained LLM pipeline.

For two years, the report generator ran on a 3-node Puppeteer cluster behind a queue. Every Sunday night, the ops team watched dashboards. Memory leaks in Chromium, PDF-size bloat from large tables, and intermittent crashes meant ~6% of reports missed the Monday window. Customers noticed; three complaints a week correlated tightly with churn risk.

The migration to SnapPDF took one sprint. Chart.js already rendered to canvas in the browser; they ported that to a Node + headless-canvas pipeline that emits PNGs per chart. The PNGs flow into /from-images to become PDF pages, /merge stitches with a pre-built cover and appendix, /add-page-numbers adds "Page N of M" with a roman-numeral prefix for the exec summary, and /watermark stamps the account name discretely at the bottom.

Measured results: on-time delivery moved from 94% to 99.98%; infrastructure cost dropped by $290/month (EC2 + S3 saved); engineering time allocated to the report pipeline fell from 0.3 FTE to 0.02 FTE — essentially, nobody owns it anymore except a Slack alert that has never fired. The one-time migration cost: 12 engineering days.

The pattern generalizes: if you render charts to bitmaps anywhere in your stack, the from-images → merge pipeline is the lowest-friction path to programmatic PDF output. Clearform now also offers "one-off report" exports to customers on-demand, using the same pipeline triggered by a button click — a feature their enterprise customers had been asking for for 18 months.

Outcomes

On-time delivery
94% → 99.98%
Infra cost
–$290/mo
Eng ownership
0.3 FTE → 0.02 FTE
Report-related churn
–38%

Integration pattern

A simplified excerpt showing the core SnapPDF calls.

// apps/reports-worker/src/generate.ts
import { SnapPDF } from '@snappdf/sdk';
const snap = new SnapPDF({ apiKey: process.env.SNAPPDF_KEY! });

export async function generateWeeklyReport(customerId: string) {
  const customer = await db.customers.findById(customerId);
  const weekData = await analytics.getWeek(customerId);

  // 1. render charts server-side to PNG
  const chartPngs = await Promise.all(
    weekData.charts.map((c) => renderChartToPng(c)),
  );

  // 2. PNGs → PDF pages
  const { pdf: chartPdfs } = await snap.pdf.fromImages({
    images: chartPngs.map((png) => ({ data: png, mime: 'image/png' })),
    pageSize: 'a4',
    fit: 'contain',
    margin: 48,
  });

  // 3. merge with cover + exec summary
  const { pdf: full } = await snap.pdf.merge({
    files: [coverFor(customer), execSummaryFor(weekData), chartPdfs, APPENDIX_URL],
    preserveBookmarks: true,
  });

  // 4. pagination
  const { pdf: paginated } = await snap.pdf.addPageNumbers({
    file: full,
    template: 'Page {n} of {total}',
    position: 'bottom-center',
    skipFirst: 2,
  });

  // 5. account-name watermark
  const { pdf: stamped } = await snap.pdf.watermark({
    file: paginated,
    kind: 'text',
    text: customer.displayName.toUpperCase(),
    position: 'bottom-center',
    opacity: 0.08,
    color: '#64748b',
  });

  return stamped;
}

Start building like this

Free tier gives you 100 ops/month — enough to prototype any of the flows on this page. No card required.

Other builds