Guides · Node.js · built-in fetch

Turn an online registration form into a fillable PDF in Node.js with built-in fetch

Every event eventually meets a participant who cannot — or will not — register online: no account, a locked-down work laptop, a school that wants paper on file. The usual answer is maintaining a second, Word-document copy of the form that drifts out of sync with the web one. The better answer is generating the paper copy from the web form, so there is exactly one source of truth.

Below is a complete, runnable Node.js program using built-in fetch, no third-party dependency needed. It reads your API key from the SNAPDOK_KEY environment variable — free keys take about thirty seconds and need no card.

import { writeFile } from "node:fs/promises";

const res = await fetch("https://snapdok.io/v1/render", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SNAPDOK_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://your-app.com/events/spring-workshop/register",
    format: "pdf",
    pdf_forms: true,
    pdf_form_only: true,
  }),
});

if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
await writeFile("registration.pdf", Buffer.from(await res.arrayBuffer()));
console.log(res.headers.get("x-form-fields"), "// fields on the printed form");

Radio groups are the detail to check on registration forms: a set of <input type="radio"> sharing a name becomes a proper PDF radio group — pick one and the others clear, same as on the page. Checkbox consents ("email me about future workshops") stay independently tickable. A <select> of ticket types becomes a dropdown in the PDF reader.

With pdf_form_only the render drops your site's navigation and prints just the form block with its headings — hand that straight to a printer. And because fields keep their HTML names, a filled copy that comes back to you can be read programmatically with any PDF library and fed into the same handler your web form posts to.

Notes for built-in fetch

No dependency needed: fetch is global from Node 18 onward (snapdok's own test suite uses it). The binary-safety detail is res.arrayBuffer()Buffer.from(...) — reaching for res.text() is the classic way to corrupt a PDF in Node. fetch does not reject on HTTP error statuses, so the res.ok check is load-bearing: without it, an expired key writes a 40-byte JSON error to disk with a .pdf extension.

Response headers worth reading

HeaderMeaning
X-Form-FieldsHow many controls made it into the PDF.
X-Form-SkippedAnything skipped — compare against your form.
X-Form-ExtractedWhether the page was pruned to the form.

Full parameter reference: the docs. Hard numbers on caps and timeouts: limits.

Related guides

Same task, other stacks

More with Node.js + built-in fetch

In the wild