server-pdf-playwright
Skill0 starsChanged 3 months agoMITView on GitHub
Server-side PDF generation with Playwright in Next.js: HTML to PDF, Node runtime route, feature flags, client fallback, and email attachments. Use when client jsPDF quality is insufficient or PDFs must be generated on the server for security or size reasons.
- Reads credentials
- Installs packages
In this repository23 other files it gives its agents.
- client-document-exportSkill
- cloudflare-turnstile-nextjsSkill
- ga4-analytics-nextjsSkill
- git-repo-privacy-auditSkill
- hardened-contact-form-nextjsSkill
- html-semantic-markupSkill
- multi-step-wizard-flowSkill
- nextjs-api-routesSkill
- nextjs-app-routerSkill
- nextjs-seo-metadataSkill
- nextjs-ui-foundationSkill
- next-themes-dark-modeSkill
- playwright-e2e-testingSkill
- react-components-patternsSkill
- react-hooks-patternsSkill
- recharts-dashboardSkill
- resend-email-nextjsSkill
- shadcn-ui-setupSkill
- specialized-form-inputsSkill
- tailwind-css-v4Skill
- vitest-unit-testingSkill
- web-accessibility-wcagSkill
- zustand-persist-stateSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 3 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 20
Always keep client fallback when server feature is disabled or unavailable.
- Distinctive: line 91
Never pass raw user HTML without sanitization if untrusted
- Distinctive: line 92
Prefer server-rendered template from structured JSON data
- Very specific: line 94
Don't expose Playwright on Edge — runtime = "nodejs" only
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Server PDF (Playwright)
When to use
| Client jsPDF/html-to-image | Server Playwright |
| Quick WYSIWYG snapshots | Consistent print layout |
| No server deps | Large/complex multi-page PDFs |
| User-triggered export | Trusted HTML → PDF pipeline |
Always keep client fallback when server feature is disabled or unavailable.
Install (server host only)
npm install playwright
npx playwright install chromiumHeavy — gate behind env flag; not suitable for Edge runtime.
Feature flag
ENABLE_SERVER_PDF=trueexport function isServerPdfEnabled(): boolean {
return process.env.ENABLE_SERVER_PDF === "true";
}Route handler
// app/api/generate-pdf/route.ts
export const runtime = "nodejs";
export async function POST(req: Request) {
if (!isServerPdfEnabled()) {
return Response.json({ error: "Server PDF disabled" }, { status: 503 });
}
const { html, filename } = schema.parse(await req.json());
const pdf = await renderHtmlToPdf(html);
return new Response(pdf, {
headers: {
"Content-Type": "application/pdf",
"Content-Disposition": `attachment; filename="${filename}"`,
},
});
}Render helper
import { chromium } from "playwright";
export async function renderHtmlToPdf(html: string): Promise<Buffer> {
const browser = await chromium.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setContent(html, { waitUntil: "networkidle" });
return await page.pdf({ format: "A4", printBackground: true });
} finally {
await browser.close();
}
}Reuse browser instance in production with connection pooling if volume is high.
Client flow
- Try
POST /api/generate-pdfwith sanitized HTML snapshot - On 503/500 → fall back to client jsPDF (see
client-document-exportskill) - Rate-limit API (5/min per IP)
Security
- Never pass raw user HTML without sanitization if untrusted
- Prefer server-rendered template from structured JSON data
- Cap HTML size and generation timeout
- Don't expose Playwright on Edge —
runtime = "nodejs"only
Deployment notes
- Vercel serverless: Playwright often not available — use dedicated Node host or external PDF service
- Docker: install Chromium deps in image
- Cold start: expect 2–5s first request
Anti-patterns
- Mandatory server PDF with no client fallback
- Running Playwright on every request without pool/timeout
- Sending full dashboard DOM HTML with script tags from client
Pair with: client-document-export, resend-email-nextjs, nextjs-api-routes.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

