🔮 Sanity Create is here. Writing is reinvented. Try now, no developer setup

Recommendations for generating PDFs from Sanity data using NextJS and headless browsers

1 replies
Last updated: Mar 22, 2021
Anyone have some recommendations for generating PDFs from Sanity data? All the data is also shown as HTML, so I guess I could generate the PDFs from the HTML or straight from Sanity, but not sure which solutions would be best and which tools best suitedEdit: I'm using NextJS
Mar 22, 2021, 1:04 PM
in my experience any other than browser based pdf generators for websites make a mess of your layout. So I recommend making the page with next (makes debugging also easier) and using a serverless function that sets up a headless browser, visits the page and generates the download.
I've used both puppeteer (
https://github.com/puppeteer/puppeteer ) and playwright (https://github.com/microsoft/playwright ) successfully for generating very nice pdfs - with clickable links and everything.
Here's a super basic one I did on aws. Just shoot it a url and filename and it downloads that page as pdf. (This will eventually need some form of authentication)

const playwright = require("playwright-aws-lambda");

const CUSTOM_CSS = `
  // whatever custom css for print/pdf

exports.lambdaHandler = async (event, context) => {
  if (!event.queryStringParameters) {
    return {
      statusCode: 500,
      body: JSON.stringify("missing parameters"),

  if (!event.queryStringParameters || !event.queryStringParameters.url) {
    return {
      statusCode: 500,
      body: JSON.stringify("missing parameter url"),

  if (!event.queryStringParameters.filename) {
    return {
      statusCode: 500,
      body: JSON.stringify("missing parameter filename"),

  try {
    const browser = await playwright.launchChromium();
    const context = await browser.newContext();
    const page = await context.newPage();
    const response = await page.goto(event.queryStringParameters.url);
    const status = await response.status();

    await page.addStyleTag({ content: CUSTOM_CSS });

    if (status !== 200) {
      return {
        statusCode: 500,
        body: JSON.stringify("page not found"),

    await page.emulateMedia({ media: "screen", format: "A4" });
    const file = await page.pdf({
      printBackground: true,
    await browser.close();

    return {
      statusCode: 200,
      body: file.toString("base64"),
      isBase64Encoded: true,
      headers: {
        "Content-Type": "application/pdf",
        "Content-Disposition": `attachment; filename=${event.queryStringParameters.filename}`,
  } catch (err) {
    return err;
Mar 22, 2021, 1:43 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?