Octa Engineering Notes Christian Elías Request for Comments: OCTA-12 octa.page Category: Informational May 2026 CV as Code: Generating a PDF from an Astro page with Playwright Abstract Generating a print-ready PDF CV from a static Astro page using Playwright headlessly — why @page margins are ignored by Playwright, why astro-pdf was skipped, and ATS compatibility pitfalls with em dashes and special characters. Status of This Memo This memo documents notes notes for the Internet community. It does not specify an Internet standard of any kind. Distribution of this memo is unlimited. The canonical version lives at https://octa.page/doc/cv-as-code-playwright-pdf/ and the machine-readable source at https://octa.page/doc/cv-as-code-playwright-pdf.md The CV lives in "src/pages/cv-print.astro" — a fully static, print-optimized HTML page with "noindex". Playwright visits it headlessly and saves the output to "public/", where the download link already points. pnpm dev # start local server on :4321 pnpm cv:pdf # run scripts/generate-cv-pdf.mjs The generation script: import { chromium } from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('http://localhost:4321/cv-print', { waitUntil: 'networkidle' }); await page.pdf({ path: 'public/Christian_Elias_Cruz_Gonzalez_esp.pdf', format: 'A4', printBackground: false, margin: { top: '18mm', right: '18mm', bottom: '14mm', left: '18mm' }, }); await browser.close(); The page uses "@page { size: A4; margin: ... }" so margins are declared twice — once in CSS for browser preview, once in "page.pdf()" for the headless render. In practice Playwright ignores "@page" margins and uses the ones passed to "pdf()". 1. Why not "astro-pdf" "astro-pdf" hooks into the build and visits pages post-build via a preview server. That works but adds build time and a dev dependency that trails Astro major releases. A standalone script is simpler: edit the page, run "pnpm cv:pdf", commit the PDF. No build coupling. 2. ATS considerations The resulting PDF is text-based (not a rasterized image), so ATS parsers extract content correctly. A few patterns that break ATS even in text PDFs: o Em dashes ("—") in date ranges — some parsers (Greenhouse, Lever) misread them as unknown characters. Use simple hyphens. o "+N" prefix on numbers inside bullets — some parsers treat "+" as a boolean search operator. Write "más de N" or "over N". o "→" and "<" in prose — replace with plain text equivalents before generating. Christian Elías Informational [Page 1]