Use Cases (Actualizado: 2/6/2026)

Generar PDF con Claude Code: facturas y reportes con Playwright

Implementa PDF con Claude Code: Playwright, CSS de impresión, fuentes, facturas, reportes y pruebas visuales.

Generar PDF con Claude Code: facturas y reportes con Playwright

Un botón de “descargar PDF” parece una tarea pequeña hasta que el documento se usa con clientes reales. Una factura necesita importes correctos, impuestos, márgenes, datos fiscales, tablas legibles y un total que no quede cortado. Un reporte mensual necesita textos, capturas, gráficos y saltos de página razonables. Un certificado debe conservar nombre, fecha, identificador y marca visual aunque se imprima.

La forma más práctica para un equipo web es generar PDF desde HTML con un navegador real. Construyes el documento como HTML, aplicas CSS de impresión, renderizas con Chromium y exportas con Playwright o Puppeteer. Claude Code puede hacerlo bien, pero solo si le pides una superficie imprimible: tamaño de página, márgenes, fuentes, fondos, saltos, pruebas visuales y casos de error. Si el prompt es vago, puede devolver un ejemplo frágil basado en canvas o coordenadas manuales.

Usa fuentes oficiales para comprobar detalles: page.pdf de Playwright, PDF generation y PDFOptions de Puppeteer, @page y CSS de impresión en MDN, y la documentación de Claude Code. Para ampliar dentro de ClaudeCodeLab, revisa automatización de hojas de cálculo, testing con Playwright y estrategias de testing.

Por qué HTML-to-PDF es el punto de partida

Hay tres enfoques habituales. Con una librería de bajo nivel como jsPDF, dibujas texto y líneas con coordenadas. Sirve para etiquetas simples, pero una factura compleja se convierte pronto en ajustes de x e y. Con un enfoque de captura o canvas, creas una imagen y la colocas en el PDF. Puede verse correcto en una revisión rápida, pero el texto no se busca bien, pesa más, se ve borroso al ampliar y es difícil de comparar.

El enfoque HTML-to-PDF mantiene el documento como web imprimible. Las tablas siguen siendo tablas, los encabezados siguen siendo encabezados, y @page controla tamaño y margen. Además puedes abrir el HTML antes de exportar, hacer screenshots y detectar cambios visuales. Para Claude Code, esto también es mejor: edita HTML, CSS, scripts Node y tests, no una colección opaca de coordenadas.

flowchart TD
  A["Datos de negocio"] --> B["Plantilla HTML"]
  B --> C["CSS de impresión y @page"]
  C --> D["Render de Chromium"]
  D --> E["Archivo PDF"]
  C --> F["Comparación de screenshot"]
  F --> G["Evidencia de revisión"]

Casos de uso reales

El primer caso es la factura. Necesita vendedor, comprador, líneas, impuestos, total, vencimiento y número estable. Los fallos graves son importes mal redondeados, impuestos omitidos, fondo de tabla perdido o total desplazado a otra página.

El segundo caso es el reporte mensual. Marketing, SEO, ventas y SaaS suelen mezclar resumen, tablas, imágenes, gráficos y recomendaciones. Aquí importan los saltos de página: un título no debería quedar solo al final de una hoja, y un gráfico no debería separarse de su explicación.

El tercer caso es el certificado. Nombre, curso, fecha, ID, logo y QR suelen vivir en una sola página. Si conviertes todo en una imagen, pierdes búsqueda y aumentas tamaño. Mantén texto significativo como HTML y usa imágenes solo para logos, firmas o QR.

El cuarto caso es un reporte interno de auditoría. Cambios de permisos, despliegues, aprobaciones e incidentes deben poder rastrearse. Incluye fecha de generación, entorno, versión de la app e ID de datos en el pie.

Prompt útil para Claude Code

Implementa generación de PDF.

Dirección:
- Renderiza una plantilla HTML con Playwright Chromium y expórtala a PDF.
- No conviertas todo el documento en una sola imagen canvas.
- Usa A4 vertical, margen de 14mm, fondos visibles y CSS de impresión.
- Usa una pila de fuentes compatible con español, japonés e inglés.
- Deja una estructura reutilizable para facturas, reportes y certificados.

Implementación:
- Añade scripts/create-invoice-pdf.mjs.
- Genera out/invoice-ES-2026-0602.pdf desde datos de ejemplo.
- Formatea dinero con Intl.NumberFormat.
- Escapa texto de usuario antes de insertarlo en HTML.
- Usa printBackground y preferCSSPageSize en page.pdf.

Verificación:
- Documenta el comando de ejecución.
- Permite comparar por screenshot el HTML imprimible.
- Comprueba fuentes, saltos, fondos y total.

Código ejecutable

npm init -y
npm pkg set type=module
npm i -D playwright
npx playwright install chromium
mkdir scripts out
node scripts/create-invoice-pdf.mjs
import { chromium } from "playwright";
import { mkdir } from "node:fs/promises";
import { dirname, resolve } from "node:path";

const outputPath = resolve("out/invoice-ES-2026-0602.pdf");
const money = new Intl.NumberFormat("es-ES", { style: "currency", currency: "EUR" });

const invoice = {
  number: "ES-2026-0602",
  buyer: "Ejemplo Digital S.L.",
  seller: "Masa Design Lab",
  issuedAt: "2026-06-02",
  items: [
    { name: "Diseño de plantilla PDF", quantity: 1, unitPrice: 800 },
    { name: "Script Playwright de generación", quantity: 1, unitPrice: 1200 },
    { name: "CSS de impresión y verificación de fuentes", quantity: 1, unitPrice: 600 },
  ],
};

function escapeHtml(value) {
  return String(value).replace(/[&<>"']/g, (char) => ({
    "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;",
  })[char]);
}

function renderHtml(data) {
  const subtotal = data.items.reduce((sum, item) => sum + item.quantity * item.unitPrice, 0);
  const tax = Math.round(subtotal * 0.21);
  const rows = data.items.map((item) => `<tr>
    <td>${escapeHtml(item.name)}</td>
    <td class="num">${item.quantity}</td>
    <td class="num">${money.format(item.unitPrice)}</td>
    <td class="num">${money.format(item.quantity * item.unitPrice)}</td>
  </tr>`).join("");

  return `<!doctype html><html lang="es"><head><meta charset="utf-8">
  <style>
    @page { size: A4; margin: 14mm; }
    body { font-family: "Noto Sans", Arial, sans-serif; color: #202124; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    header { display: flex; justify-content: space-between; border-bottom: 3px solid #1f5eff; padding-bottom: 14px; }
    h1 { margin: 0; font-size: 28px; }
    table { width: 100%; border-collapse: collapse; margin-top: 24px; }
    th { background: #eef3ff; text-align: left; }
    th, td { border-bottom: 1px solid #d7dce5; padding: 10px 8px; }
    .num { text-align: right; white-space: nowrap; }
    .total { margin-left: auto; width: 260px; margin-top: 20px; font-size: 18px; font-weight: 700; }
    .avoid-break { break-inside: avoid; page-break-inside: avoid; }
  </style></head><body>
  <header><h1>Factura</h1><div>Número: ${escapeHtml(data.number)}<br>Fecha: ${escapeHtml(data.issuedAt)}</div></header>
  <p><strong>Cliente:</strong> ${escapeHtml(data.buyer)}</p>
  <p><strong>Proveedor:</strong> ${escapeHtml(data.seller)}</p>
  <table><thead><tr><th>Concepto</th><th class="num">Cantidad</th><th class="num">Precio</th><th class="num">Importe</th></tr></thead><tbody>${rows}</tbody></table>
  <div class="total avoid-break">Total: ${money.format(subtotal + tax)}</div>
  </body></html>`;
}

await mkdir(dirname(outputPath), { recursive: true });
const browser = await chromium.launch();
try {
  const page = await browser.newPage();
  await page.setContent(renderHtml(invoice), { waitUntil: "networkidle" });
  await page.evaluate(() => document.fonts.ready);
  await page.emulateMedia({ media: "print" });
  await page.pdf({ path: outputPath, printBackground: true, preferCSSPageSize: true, margin: { top: "0", right: "0", bottom: "0", left: "0" } });
  console.log(`Created ${outputPath}`);
} finally {
  await browser.close();
}

Errores frecuentes y verificación

Los errores más comunes son convertir todo en imagen, olvidar printBackground, mezclar márgenes del navegador con @page, exportar antes de que carguen fuentes o logos, y meter nombres de cliente sin escapar. También es habitual probar solo una factura corta y descubrir demasiado tarde que una nota larga rompe el salto de página.

La verificación debe incluir más que “existe un PDF”. Prueba el cálculo del total con tests de unidad. Abre la ruta imprimible, aplica page.emulateMedia({ media: "print" }) y guarda un screenshot con Playwright para detectar cambios. Revisa una factura corta, una larga, una sin logo y una con texto multilingüe.

CTA y resultado probado

PDF es un tema monetizable porque conecta código con facturas, reportes, certificados, lead magnets y entregables de cliente. Empieza con la chuleta gratuita de Claude Code, usa productos y plantillas para flujos repetibles, y acude a formación o consultoría si tu equipo necesita integrar generación de PDF, revisión y Playwright en un repositorio real.

Para este artículo comprobé el flujo con Node.js local, Playwright Chromium y una factura de ejemplo. La parte más útil no fue llamar a page.pdf, sino tratar el HTML imprimible como una superficie verificable. En trabajos reales de Masa, las incidencias más frecuentes son fuentes que cambian el alto de línea, fondos que desaparecen y saltos de página que nadie miró antes de enviar el documento.

#Claude Code #PDF generation #jsPDF #Puppeteer #reports
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.