Settings reference
Settings control everything about a render that is not markup: paper, margins, headers and footers, image size, waiting, PDF metadata and formatting defaults. They are stored with each template version and can be overridden per request:
- In the editor, the Page setup panel writes them: paper, margins, header and footer height and padding, scale, background, CSS page size, Tailwind, the image size and format, locale, time zone and currency, and the Document and E-invoice sections. Keys without a field there (
waitFor,pageRanges,image.quality,image.clipSelector) are kept when you save; set them in a project or through the API. - In a project, they are
settings.jsonin the template's folder; the filesheader.htmlandfooter.htmlbeside it fillheader.htmlandfooter.htmlof the settings. - Through the API, they are the
settingsof a version (POST /templates/{id}/versions) and of a render request.
How settings combine
Formfeed deep-merges three layers, later ones winning:
- the defaults on this page,
- the template version's settings,
- the
settingsobject of the render request.
Only the keys you set change; everything else keeps its value. A list replaces the list below it. Setting a section to null removes it, which is how a request turns off a template's footer:
{ "template": "invoice", "data": { … }, "settings": { "margin": { "top": "30mm" }, "footer": null } }
The request's locale field is a shortcut for settings.locale; when a request sends both, settings.locale wins.
Example
{
"paper": { "format": "A4", "landscape": false },
"margin": {
"top": "25mm",
"right": "18mm",
"bottom": "22mm",
"left": "18mm"
},
"footer": {
"html": "<div style=\"font-size: 8pt\">Page <span class=\"pageNumber\"></span></div>",
"height": "12mm"
},
"printBackground": true,
"pdf": {
"metadata": {
"title": "Invoice {{ invoice.number }}",
"author": "Fennlor Studio GmbH"
}
},
"locale": "de-DE",
"timezone": "Europe/Berlin",
"currency": "EUR",
"tailwind": true
}
Page (PDF)
Lengths take the units mm, cm, in and px, or a bare number of pixels ("20mm", "1in", "96"). Other units, such as pt, em or %, fail the render.
| Key | Type | Default | Meaning |
|---|---|---|---|
paper.format | string | "A4" | A0–A6, Letter, Legal, Tabloid, Ledger, in any case. Ignored when width and height are set. Another name fails the render. |
paper.width, paper.height | length | null | Custom page size, for example "100mm" and "150mm". Both are needed; one alone is ignored. |
paper.landscape | boolean | false | Turns the page to landscape: width and height swap, for a custom size too. |
margin.top, .right, .bottom, .left | length | 20mm, 15mm, 20mm, 15mm | Page margins. Headers and footers are drawn inside the top and bottom margins. |
preferCssPageSize | boolean | false | Let @page rules in your CSS decide the page size instead of paper. |
printBackground | boolean | true | Print background colours and images. |
scale | number | 1 | Scales the page content, 0.1 to 2. A value outside that range fails the render. |
pageRanges | string | "" | Keep only these pages, for example "1-3, 5". Empty keeps all. The page count, the plan's page limit and the units count the pages that are kept. |
Before printing, Chromium lays the page out in a window the size of the paper (A4 portrait: 794 × 1123 CSS pixels), so scripts that measure the window see the page's width.
Header and footer (PDF)
| Key | Type | Default | Meaning |
|---|---|---|---|
header.html, footer.html | string | none | Markup for the running header and footer, rendered once with the template's language and data and printed on every page. The editor's Header and Footer tabs and a project's header.html and footer.html write these. In an ad-hoc html render without engine they are used as written. |
header.height, footer.height | CSS length | none | Height of the header or footer box. It does not change the margin: make margin.top (or margin.bottom) at least as large. Header height and Footer height in the editor. |
header.padding, footer.padding | CSS padding | "0 10mm" | Space inside the header or footer box. The box spans the full page width, as Chromium prints it, so this padding is what keeps its content off the paper edge; 0 lets a design run edge to edge. Header padding and Footer padding in the editor. |
header: null or footer: null removes one. See Headers, footers and page numbers for page numbers, styling and what does not work there (stylesheets, images by URL, scripts).
PDF output
| Key | Type | Default | Meaning |
|---|---|---|---|
pdf.metadata.title | string | "" | Document title, which a PDF reader shows in its title bar. Rendered with the data, so it may contain template expressions ("Invoice {{ invoice.number }}"). Also the document's <title> and the value of the title class in headers and footers. An ad-hoc html render without engine and a url render ignore it. |
pdf.metadata.author, pdf.metadata.subject, pdf.metadata.keywords | string | "" | Document properties, rendered with the data like the title, so "{{ company.name }}" becomes the name; one that renders empty is left out. An ad-hoc html render without engine writes them as given. keywords is one string, such as "invoice, 2026". |
pdf.tagged | boolean | false | Write the structure tree (headings, lists, tables, links) a screen reader reads the document by. A tagged PDF is not yet a PDF/UA file: that is pdf.ua. |
pdf.outline | boolean | false | Generate a bookmark outline from the headings, nested by heading level. Chromium builds it from the PDF's tags, so this also produces a tagged PDF. |
pdf.ua | boolean or { "check": "strict" | "report" } | false | Make the file a PDF/UA-1 document: tagged, repaired, and checked against veraPDF's machine-checkable rules of the standard. true (and {}) is the strict check, which fails a render whose file does not pass; report delivers it with the verdict. Implies pdf.tagged. false in a request switches off what the template declares. |
The Document section of the editor's Page setup writes these: Title, Author, Subject, Keywords, Bookmarks from the headings (pdf.outline), Tagged PDF (pdf.tagged) and Accessible PDF (PDF/UA-1) (pdf.ua).
pdf.ua applies to PDF output only. A request that asks for it together with an image output, with post.merge_after, or for a Word or PowerPoint template is answered with 400 invalid_request before anything is rendered; a template that declares it renders its images as usual. See Accessible PDFs.
E-invoice
einvoice makes the template an invoice template: every PDF rendered from it is a ZUGFeRD or Factur-X e-invoice, built from the _invoice block of the data. Image output of the same template is not affected. The E-invoice section of the editor's Page setup writes it. Live e-invoices need the Starter plan or higher; see Plans and units.
| Key | Type | Default | Meaning |
|---|---|---|---|
einvoice | object | none | Declares the e-invoice. {} takes the defaults below. |
einvoice.profile | en16931, basic | en16931 | The profile of the invoice. |
einvoice.flavour | factur-x, zugferd | factur-x | The name and the release the render reports. The file is the same. |
einvoice.xml | embedded, both | embedded | both also stores the XML as a file of its own beside the PDF. |
einvoice.display_check | warn, strict | warn | What happens when the PDF does not show a value of the XML: a warning, or a failed render. |
A request's settings.einvoice and post.einvoice merge over it field by field, and post.einvoice: false switches it off for one request. See the options.
Image output
Used by templates of kind image, and by any render with output: "png", "jpg" or "webp".
| Key | Type | Default | Meaning |
|---|---|---|---|
image.format | png, jpeg, webp | png | What an image template renders when the request names no output. jpg is accepted too. A request's output always wins; a request can also set settings.image.format instead. |
image.width, image.height | integer (CSS px) | 1200, 630 | Viewport size. html and body take this size too. |
image.deviceScaleFactor | number | 2 | Pixel density. 2 doubles the pixel size of the file: 1200 × 630 becomes 2400 × 1260. |
image.quality | integer | 90 | JPEG and WebP quality, 1–100. WebP at 100 is lossless. PNG ignores it. |
image.fullPage | boolean | false | Capture the full scroll height instead of the viewport. |
image.transparent | boolean | false | Transparent background for PNG and WebP; JPEG has none. Only where the page paints no background of its own. Transparent background (PNG) in the editor. |
image.clipSelector | string | null | CSS selector of one element to capture instead of the whole viewport; the first match counts. When no element matches within 30 seconds, the render fails with render_timeout. |
design | object | none | The layers of a template made in the visual editor. It is what you edit, not what renders: a render uses the HTML and CSS the editor writes from it, and a design in a render request is ignored. At most 256 kB. A project keeps it in design.json. |
Waiting for content
Before Formfeed prints, the page has loaded and none of its requests is still running (loading may take up to 30 seconds), its fonts are ready, text marked with data-ff-fit is fitted, and the conditions below are met. A page that can fetch on its own, a url render or a template with a script of its own, an event handler attribute such as onload or a frame, is printed only once the network has also been idle for half a second, since its code may still start a request. The scripts Formfeed adds for charts and fitted text do not count. These keys are for pages that finish later, usually because of JavaScript.
| Key | Type | Default | Meaning |
|---|---|---|---|
waitFor.networkIdle | boolean or "auto" | "auto" | "auto" waits as described above. true always waits for half a second of network idle, as every render did until 18 October 2026; false prints right after the load event and the fonts, which helps a page that keeps polling. |
waitFor.selector | string | null | Wait until an element matching this CSS selector exists and is visible (an element with display: none or no size does not count). |
waitFor.timeoutMs | integer | 5000 | How long to wait for selector, in milliseconds; at most 30,000. When the element has not appeared by then, the render fails with render_timeout. |
waitFor.delayMs | integer | 0 | Extra fixed pause in milliseconds after everything else, at most 10,000; a larger value counts as 10,000. |
{ "waitFor": { "selector": "#report-ready", "timeoutMs": 8000 } }
Formatting and styling
| Key | Type | Default | Meaning |
|---|---|---|---|
locale | BCP 47 tag | "en-GB" | Formats dates and numbers, picks the translation dictionary and sets <html lang>. Scripts in the page see it as the browser's language. The request field locale sets it per render. |
timezone | IANA zone | "Europe/Berlin" | Time zone for dates, of the helpers and of the page's JavaScript. |
currency | ISO 4217 code | "EUR" | Default currency of money. |
tailwind | boolean | false | Compile the Tailwind utility classes the document uses; see Tailwind CSS. |
Word and PowerPoint templates
Word and PowerPoint templates take their paper, margins, headers and footers from the document, so the page, header, footer, waiting and image settings above do not apply to them, nor do pdf.metadata.title, pdf.tagged, pdf.outline and pdf.ua (pdf.ua is refused). What they use:
| Key | Type | Default | Meaning |
|---|---|---|---|
office.output | docx, pptx, pdf | the template's own format | What a render produces when it names no output. A docx template accepts docx or pdf, a pptx template pptx or pdf. Output when a render names none on the template's Settings panel. |
locale, timezone, currency | as above | Formatting of the helpers, as in HTML templates. | |
pdf.metadata.author, pdf.metadata.subject, pdf.metadata.keywords | string | "" | Written into the PDF output as given: unlike an HTML template, a Word or PowerPoint template does not render them with the data. A docx or pptx output keeps the document's own properties. |
einvoice | as above | Their PDF output can be an e-invoice too. |
Through the API
The settings object of POST /v1/renders uses exactly these keys. For ad-hoc html renders there is no template, so the request settings merge directly over the defaults:
{
"html": "<h1>Shipping label</h1>",
"settings": {
"paper": { "width": "100mm", "height": "150mm" },
"margin": { "top": "5mm", "right": "5mm", "bottom": "5mm", "left": "5mm" }
}
}
With "engine": "jinja2" (or liquid, handlebars) the html is a template: it is rendered with data, and so are header.html, footer.html and the pdf.metadata fields. Without engine the markup, header and footer are used as written, and pdf.metadata.title is not applied; give the document a <title> of its own. A url render takes the page, header, footer, waiting and image settings.