How do I generate a multi-page PDF?
Combine template pages into one document for reports, catalogs and multi-page certificates.
Published ·Updated
Multi-page templates in Orshot let you design multiple pages within a single template and generate them as one combined PDF document. This is ideal for reports, catalogs, slide decks, multi-section invoices, and any document that spans more than one page.
How It Works#
When your Studio template has multiple pages and you render as PDF, Orshot combines all pages into a single PDF file.
const response = await fetch("https://api.orshot.com/v1/studio/render", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer <YOUR_API_KEY>",
},
body: JSON.stringify({
templateId: "<MULTI_PAGE_TEMPLATE>",
modifications: {
"page1@title": "Annual Report 2026",
"page1@subtitle": "Q1 Financial Summary",
"page2@title": "Revenue Breakdown",
"page2@chart_data": "https://example.com/chart.png",
"page3@title": "Looking Ahead",
"page3@body": "Our projections for the coming quarter...",
},
response: {
format: "pdf",
type: "url",
},
}),
});
const data = await response.json();
console.log(data.data.content); // Single PDF URL with all pagesRendering Specific Pages#
Use response.includePages to select which pages appear in the final PDF:
{
"response": {
"format": "pdf",
"type": "url",
"includePages": [1, 3, 5]
}
}This generates a PDF containing only pages 1, 3, and 5 — skipping pages 2 and 4.
Use includePages to pick pages. pdfOptions.rangeFrom and
pdfOptions.rangeTo cannot select template pages, because each template
page prints as its own PDF page before the pages are joined.
Page-Specific Content#
Use the page{N}@ prefix to target content on specific pages:
{
"modifications": {
"page1@heading": "Cover Page",
"page1@canvasBackgroundColor": "#0f172a",
"page1@heading.color": "#ffffff",
"page2@heading": "Table of Contents",
"page2@canvasBackgroundColor": "#ffffff",
"page2@heading.color": "#0f172a",
"page3@heading": "Chapter 1: Introduction",
"page3@body": "This report covers our progress in Q1 2026..."
}
}Keys Without a Page Prefix#
On a multi-page template, a content key without the page{N}@ prefix is not applied to any page. The response returns a warning that names the prefixed key to use. To set the same footer on every page, send it once per page:
{
"modifications": {
"page1@footer_text": "© 2026 Acme Corp",
"page2@footer_text": "© 2026 Acme Corp",
"page3@footer_text": "© 2026 Acme Corp",
"page1@title": "Cover",
"page2@title": "Summary",
"page3@title": "Details"
}
}Style keys work differently. A bare dotted key such as footer_text.color applies to every page that has a footer_text layer. Inline keys and canvas keys such as canvasBackgroundColor also apply to every page.
Example: Product Catalog#
Generate a multi-page product catalog:
const products = [
{
name: "Wireless Headphones",
price: "$89",
image: "https://example.com/headphones.jpg",
},
{
name: "Smart Watch",
price: "$249",
image: "https://example.com/watch.jpg",
},
{
name: "Portable Speaker",
price: "$59",
image: "https://example.com/speaker.jpg",
},
];
const modifications = {};
products.forEach((product, i) => {
const page = i + 1;
modifications[`page${page}@brand_logo`] = "https://example.com/brand-logo.png";
modifications[`page${page}@product_name`] = product.name;
modifications[`page${page}@product_price`] = product.price;
modifications[`page${page}@product_image`] = product.image;
modifications[`page${page}@product_name.href`] =
`https://shop.example.com/product/${i + 1}`;
});
const response = await fetch("https://api.orshot.com/v1/studio/render", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer <YOUR_API_KEY>",
},
body: JSON.stringify({
templateId: "<CATALOG_TEMPLATE>",
modifications,
response: {
format: "pdf",
type: "url",
fileName: "product-catalog-2026",
},
pdfOptions: {
colorMode: "cmyk",
},
}),
});Example: Multi-Page Certificate#
Generate a certificate with a cover page and detailed breakdown:
await fetch("https://api.orshot.com/v1/studio/render", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer <YOUR_API_KEY>",
},
body: JSON.stringify({
templateId: "<CERTIFICATE_TEMPLATE>",
modifications: {
// Page 1: Certificate
"page1@recipient": "Alex Johnson",
"page1@title": "Certificate of Completion",
"page1@course": "Full Stack Development",
"page1@date": "March 25, 2026",
// Page 2: Course details
"page2@modules_completed": "12 / 12",
"page2@total_hours": "180 hours",
"page2@final_grade": "A+",
"page2@verify_link": "Verify Online",
"page2@verify_link.href": "https://example.com/verify/CERT-001",
},
response: {
format: "pdf",
type: "url",
},
}),
});Flow Text (Automatic Multi-Page PDFs)#
If your template uses flowing content (text with textMode: "flow"), the PDF automatically includes as many pages as needed to fit all the text. You design a single page, and the flow engine generates the rest.
{
"templateId": "<FLOW_TEMPLATE>",
"modifications": {
"body": "Your long document text... can be any length."
},
"response": {
"format": "pdf",
"type": "url"
}
}The PDF output combines all pages (source + overflow) into one document. response.includePages picks pages from your template, not from the flow output. Each picked page that overflows still adds all its flow pages.
Flow is great for reports, articles, or invoices where the number of pages depends on the content. See the Flowing Content guide for setup instructions.
Render Costs#
Each page in a multi-page PDF counts towards your render usage. This includes both designed pages and the extra pages that flowing text creates. Use includePages to render, and pay for, only the pages you need.
For large documents with the same styling on every page, use bare dotted
style keys (for example title.color) to keep your request payload small.
Content keys still need a page{N}@ prefix.
Ready to automate?
Start rendering images, PDFs and videos from your templates in under 2 minutes. Free plan, no credit card.
Get your API key- Image, PDF and video generation via API
- Visual editor with AI and smart layouts
- Zapier, Make, MCP and 40+ integrations
- White-label embed for your own app
- 100 free credits a month, no credit card required