{"id":9971,"date":"2026-01-19T11:03:44","date_gmt":"2026-01-19T10:03:44","guid":{"rendered":"https:\/\/scalarly.com\/marketing-book\/?p=9971"},"modified":"2026-01-19T11:34:30","modified_gmt":"2026-01-19T10:34:30","slug":"always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security","status":"publish","type":"post","link":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/","title":{"rendered":"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Why \u201cit worked once\u201d isn\u2019t the same as \u201cit works every time\u201d<\/h2>\n\n\n\n<p class=\"has-drop-cap\">Adding <a href=\"https:\/\/scalarly.com\/marketing-book\/beyond-page-numbers-the-2025-guide-to-professional-headers-and-footers-in-zoho-writer\/\" target=\"_blank\" rel=\"noreferrer noopener\">page numbers<\/a> sounds like a solved problem\u2014until you put it into a real pipeline: CRM \u2192 generate PDF \u2192 merge attachments \u2192 paginate \u2192 send to client. That\u2019s where the gap between \u201c<a href=\"https:\/\/scalarly.com\/marketing-book\/boring-on-purpose-the-playbook-for-running-zoho-delete-pages-as-a-real-job-pipeline-no-link-edition\/\" target=\"_blank\" rel=\"noreferrer noopener\">works on my machine<\/a>\u201d and \u201c<a href=\"https:\/\/scalarly.com\/marketing-book\/a-2025-update-seamless-external-collaboration-in-zoho-password-protected-links-real-time-editing-and-whats-changed\/\" target=\"_blank\" rel=\"noreferrer noopener\">works every time<\/a>\u201d shows up.<\/p>\n\n\n\n<p>In earlier implementations, teams often treated pagination as a final, synchronous step: send a PDF, wait, get the result, and move on. Today\u2019s approach is different. Modern page numbering APIs commonly run as <strong>scheduled asynchronous jobs<\/strong>, return a <strong>status-check URL<\/strong>, and require you to build around practical constraints like <strong>file size\/page count limits<\/strong>, <strong>layout consistency<\/strong>, and <strong>secure file access<\/strong>. <\/p>\n\n\n\n<p>This production guide is an updated, operations-focused article: what you should do now, what changed compared to older \u201cquick script\u201d approaches, and how to make pagination stable at scale.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What changed from before to today<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Before: pagination as a blocking \u201cone-and-done\u201d step<\/h3>\n\n\n\n<p>A typical older workflow looked like this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Upload the PDF<\/li>\n\n\n\n<li>Add \u201cPage X of Y\u201d<\/li>\n\n\n\n<li>Immediately download the result<\/li>\n\n\n\n<li>If it fails, retry manually or rerun the script<\/li>\n<\/ul>\n\n\n\n<p>That approach can work for small files and low volume, but it breaks down when:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PDFs get large (scanned exhibits, image-heavy reports)<\/li>\n\n\n\n<li>Multiple jobs run concurrently<\/li>\n\n\n\n<li>Downstream systems need predictable timing and retries<\/li>\n\n\n\n<li>You must guarantee consistent placement across many document types<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Today: pagination as a resilient job in a workflow<\/h3>\n\n\n\n<p>A modern production-grade workflow assumes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The service may return <strong>in-progress<\/strong> status first<\/li>\n\n\n\n<li>You must <strong>poll a status-check URL<\/strong> until the job completes<\/li>\n\n\n\n<li>You need <strong>timeouts, retries, and backoff<\/strong><\/li>\n\n\n\n<li>You should enforce <strong>input limits<\/strong> before submitting<\/li>\n\n\n\n<li>You standardize output using <strong>placeholders<\/strong> and a <strong>house layout style<\/strong><\/li>\n\n\n\n<li>You treat security as a first-class requirement (token scopes, safe URL handling)<\/li>\n<\/ul>\n\n\n\n<p>This isn\u2019t \u201cmore complicated for fun.\u201d It\u2019s what keeps pagination correct when you\u2019re processing hundreds or thousands of PDFs across multiple systems.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Design around API limits from day one<\/h2>\n\n\n\n<p>The most common production failure isn\u2019t an authentication issue\u2014it\u2019s an input that violates constraints.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Correct interpretation of file limits<\/h3>\n\n\n\n<p>In production, treat documented limits as <strong>maximums<\/strong>, not minimums:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Maximum file size: <strong>50 MB<\/strong><\/li>\n\n\n\n<li>Maximum length: <strong>150 pages<\/strong><\/li>\n<\/ul>\n\n\n\n<p>If you submit a file beyond those caps, your job may fail outright or behave inconsistently.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Build a preflight step that runs before pagination<\/h3>\n\n\n\n<p>A reliable pipeline introduces a \u201cpreflight\u201d stage that checks:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>File size (bytes\/MB)<\/li>\n\n\n\n<li>Page count<\/li>\n\n\n\n<li>Whether the PDF is encrypted or malformed (if relevant to your ecosystem)<\/li>\n\n\n\n<li>Whether the PDF is image-heavy and likely to exceed limits after merges<\/li>\n<\/ul>\n\n\n\n<p>If the PDF fails preflight, don\u2019t send it to the pagination endpoint. Handle it intentionally.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">When PDFs are too large: what to do in a pre-step<\/h3>\n\n\n\n<p>If your documents can exceed limits (especially scanned PDFs), add a preprocessing step such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Split<\/strong> the PDF into smaller segments and paginate each segment (only if your business rules allow it)<\/li>\n\n\n\n<li><strong>Compress<\/strong> images (reduce DPI, re-encode JPEGs, remove redundant metadata)<\/li>\n\n\n\n<li><strong>Downsample<\/strong> oversized scans (a common culprit in court filings and legacy archives)<\/li>\n<\/ul>\n\n\n\n<p>This is one of the biggest changes from \u201cbefore\u201d to \u201ctoday\u201d: instead of hoping the service accepts whatever you send, you proactively shape the input so the pagination job is predictable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Treat pagination as an asynchronous job, not a blocking call<\/h2>\n\n\n\n<p>In production, the most important mindset shift is to avoid blocking your application while the PDF is processed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What the async flow looks like<\/h3>\n\n\n\n<p>After you submit a job, the service returns:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A <strong>status_check_url<\/strong><\/li>\n\n\n\n<li>A status like <strong>inprogress<\/strong> <\/li>\n<\/ul>\n\n\n\n<p>You poll the status-check URL until you receive:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A <strong>download_url<\/strong><\/li>\n\n\n\n<li>A status like <strong>success<\/strong> <\/li>\n<\/ul>\n\n\n\n<p>That design is intentional: it allows the service to queue and process requests reliably without forcing your client to hold a long-running connection open.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why this is better than synchronous pagination<\/h3>\n\n\n\n<p>Async processing supports:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Better scalability during traffic spikes<\/li>\n\n\n\n<li>More predictable performance under load<\/li>\n\n\n\n<li>Cleaner failure recovery (you can retry status polling without resubmitting the job)<\/li>\n\n\n\n<li>Easier integration into queues and workflow engines<\/li>\n<\/ul>\n\n\n\n<p>This is a major \u201ctoday\u201d upgrade compared to older approaches that assumed pagination would finish immediately.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Polling done right: backoff, timeouts, and user experience<\/h2>\n\n\n\n<p>Polling is easy to implement badly. Production systems implement it carefully.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use exponential backoff to reduce load<\/h3>\n\n\n\n<p>A practical pattern is exponential backoff:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>2s \u2192 4s \u2192 8s \u2192 16s \u2192 30s (cap)<\/li>\n<\/ul>\n\n\n\n<p>This reduces unnecessary requests when jobs take longer and protects both your system and the API from excessive polling traffic.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use graceful timeouts instead of hard failure<\/h3>\n\n\n\n<p>If the job isn\u2019t complete within your tolerance window:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Don\u2019t crash the entire workflow<\/li>\n\n\n\n<li>Mark the document state as <strong>processing<\/strong><\/li>\n\n\n\n<li>Notify the user or downstream system that the file will be available soon<\/li>\n\n\n\n<li>Continue polling in a controlled way (or re-check later via a scheduled worker)<\/li>\n<\/ul>\n\n\n\n<p>This is one of the clearest differences between amateur and production systems: \u201ctimeout gracefully\u201d beats \u201cfail loudly\u201d when the job is still legitimately running.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Make polling idempotent and safe<\/h3>\n\n\n\n<p>Polling should be safe to repeat:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Don\u2019t change state on every poll attempt<\/li>\n\n\n\n<li>Don\u2019t duplicate records or send duplicate notifications<\/li>\n\n\n\n<li>Keep a single source of truth for job state (job ID, status URL, timestamps)<\/li>\n<\/ul>\n\n\n\n<p>In other words: submitting the job is the \u201cwrite\u201d action; polling should behave like a \u201cread\u201d action.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Standardize templates with placeholders to eliminate math and mistakes<\/h2>\n\n\n\n<p>The easiest way to get inconsistent pagination is to compute page numbers yourself. Don\u2019t.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use placeholders so pagination always matches the final PDF<\/h3>\n\n\n\n<p>Placeholders like these keep numbering correct even when the PDF length changes due to merges or inserted pages:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>&lt;&lt;page_number>><\/code><\/li>\n\n\n\n<li><code>&lt;&lt;total_pages>><\/code> <\/li>\n<\/ul>\n\n\n\n<p>This is especially important in production because the \u201cfinal page count\u201d is often unknown until the last step:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Terms and conditions get appended<\/li>\n\n\n\n<li>Attachments are included conditionally<\/li>\n\n\n\n<li>A cover sheet is inserted depending on client type<\/li>\n\n\n\n<li>A signature page is added at send time<\/li>\n<\/ul>\n\n\n\n<p>With placeholders, you avoid fragile client-side calculations and keep the output accurate.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Treat pagination text as a reusable, versioned asset<\/h3>\n\n\n\n<p>Instead of hardcoding strings across services, define a small set of approved templates:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u201cPage &lt;&lt;page_number>> of &lt;&lt;total_pages>>\u201d<\/li>\n\n\n\n<li>\u201c&lt;&lt;page_number>> \/ &lt;&lt;total_pages>>\u201d<\/li>\n\n\n\n<li>\u201cPage &lt;&lt;page_number>>\u201d (when totals aren\u2019t required)<\/li>\n<\/ul>\n\n\n\n<p>Version them like you version code. If Legal or Compliance changes the wording, you update one template set\u2014not 12 different microservices.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Make placement predictable with a documented house style<\/h2>\n\n\n\n<p>Pagination problems aren\u2019t always \u201cwrong numbers.\u201d Often it\u2019s \u201cright numbers in the wrong place.\u201d<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Offsets are the production secret weapon<\/h3>\n\n\n\n<p>Offsets let you nudge placement in <strong>pixels<\/strong> so the page number doesn\u2019t collide with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Footer logos<\/li>\n\n\n\n<li>Pre-printed letterhead<\/li>\n\n\n\n<li>Stamps<\/li>\n\n\n\n<li>Page margins that differ between document sources<\/li>\n<\/ul>\n\n\n\n<p>Even if your API supports default header\/footer placement, offsets are what make output consistent across many PDFs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Define a single \u201chouse style\u201d and apply it everywhere<\/h3>\n\n\n\n<p>A strong best practice is to define a standard layout such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Header left: document title<\/li>\n\n\n\n<li>Footer center: page numbering<\/li>\n\n\n\n<li>Footer right: date or version<\/li>\n<\/ul>\n\n\n\n<p>Then reuse the same offsets across every document type. The goal is to prevent a scenario where invoices have one footer spacing, reports have another, and exhibit packets drift slightly depending on the source system.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How this differs from older workflows<\/h3>\n\n\n\n<p>Before, teams often \u201ceyeballed\u201d layout by adjusting settings per document type. Today, production systems centralize layout rules:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>One set of offsets<\/li>\n\n\n\n<li>One typography standard<\/li>\n\n\n\n<li>One placement pattern<\/li>\n<\/ul>\n\n\n\n<p>That reduces long-term maintenance and stops layout drift over time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Security and authorization: the checklist that prevents headaches later<\/h2>\n\n\n\n<p>Pagination seems harmless\u2014until you realize you\u2019re moving sensitive documents through URLs and tokens.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Ensure your OAuth scope is correct<\/h3>\n\n\n\n<p>Your OAuth token must include the appropriate scope for PDF editor operations (for example, <code>ZohoWriter.pdfEditor.ALL<\/code>).<\/p>\n\n\n\n<p>In production, handle tokens carefully:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Store them securely (never log raw tokens)<\/li>\n\n\n\n<li>Refresh them proactively<\/li>\n\n\n\n<li>Fail fast on scope-related errors (don\u2019t retry endlessly)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Be careful with publicly accessible file URLs<\/h3>\n\n\n\n<p>Many APIs allow the <code>file<\/code> parameter to be either an uploaded file or a publicly accessible URL. In production, URLs can become a security risk if handled casually.<\/p>\n\n\n\n<p>If you use URLs:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Prefer <strong>short-lived, expiring signed URLs<\/strong><\/li>\n\n\n\n<li>Restrict access by IP or token where possible<\/li>\n\n\n\n<li>Ensure the URL doesn\u2019t reveal sensitive identifiers<\/li>\n\n\n\n<li>Avoid long-lived public links to customer documents<\/li>\n<\/ul>\n\n\n\n<p>This is one of the most important \u201ctoday\u201d shifts: security is no longer an afterthought. Document automation is now part of the security perimeter.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Observability: logging and metrics that make failures actionable<\/h2>\n\n\n\n<p>When pagination fails at scale, you need answers fast.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What to log (and what not to log)<\/h3>\n\n\n\n<p>Log:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Job submission timestamp<\/li>\n\n\n\n<li>Job status transitions (submitted \u2192 in progress \u2192 success\/failure)<\/li>\n\n\n\n<li>File size and page count (metadata only)<\/li>\n\n\n\n<li>Polling attempts and total completion time<\/li>\n<\/ul>\n\n\n\n<p>Do not log:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Full document URLs if they expose sensitive info<\/li>\n\n\n\n<li>Access tokens<\/li>\n\n\n\n<li>Raw PDF content<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Metrics to track in production<\/h3>\n\n\n\n<p>A minimal metrics set:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Success rate<\/li>\n\n\n\n<li>Average processing time (p50\/p95)<\/li>\n\n\n\n<li>Failure rate by category (input too large, auth, timeout, malformed PDF)<\/li>\n\n\n\n<li>Polling request volume<\/li>\n<\/ul>\n\n\n\n<p>These metrics help you spot changes in upstream behavior\u2014like a CRM update that suddenly produces bigger PDFs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Testing strategy: how to prove it works before it matters<\/h2>\n\n\n\n<p>Production reliability starts in test environments.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Build a test suite that reflects reality<\/h3>\n\n\n\n<p>Include PDFs that represent your worst cases:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Image-heavy scanned files near the size limit<\/li>\n\n\n\n<li>PDFs near the page-count limit<\/li>\n\n\n\n<li>Mixed-source bundles (merged PDFs with different margins)<\/li>\n\n\n\n<li>Documents with cover pages and appended terms<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Validate layout, not just correctness<\/h3>\n\n\n\n<p>Don\u2019t stop at \u201cdownload succeeded.\u201d Validate:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Page numbers appear on every required page<\/li>\n\n\n\n<li>Total pages matches the final output<\/li>\n\n\n\n<li>Numbers don\u2019t overlap with existing content<\/li>\n\n\n\n<li>Placement is consistent with your house style<\/li>\n<\/ul>\n\n\n\n<p>This is another \u201cbefore vs today\u201d change: earlier tests often checked only that the API returned a file. Modern tests check that the output is usable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A modern production blueprint you can implement<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Preflight<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Check size and page count against maximums<\/li>\n\n\n\n<li>If too large, compress\/split\/downsample<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Submit async job<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Upload file or pass controlled URL<\/li>\n\n\n\n<li>Store status_check_url and job metadata<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Poll with backoff<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Exponential backoff<\/li>\n\n\n\n<li>Stop at a sensible time window<\/li>\n\n\n\n<li>Mark job as processing if still running<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Retrieve result<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>On success, download via download_url<\/li>\n\n\n\n<li>Store output in your secure storage<\/li>\n\n\n\n<li>Expire or revoke any temporary links<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Post-validate<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Confirm placeholders resolved correctly (Page X of Y)<\/li>\n\n\n\n<li>Confirm consistent placement\/offsets<\/li>\n\n\n\n<li>Confirm output naming and metadata<\/li>\n<\/ul>\n\n\n\n<p>This blueprint is what \u201cworks every time\u201d looks like in practice.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Final takeaway: production pagination is a workflow, not a feature<\/h2>\n\n\n\n<p>From before to today, the key evolution is this: pagination isn\u2019t a tiny formatting step anymore. In modern systems, it\u2019s a <strong>reliable, asynchronous workflow component<\/strong> that must handle limits, polling, layout standards, and security without human babysitting.<\/p>\n\n\n\n<p>If you build around maximum constraints, treat processing as async, standardize placeholders and offsets, and handle URLs\/tokens securely, you end up with pagination that\u2019s boring\u2014in the best possible way. It just works.<\/p>\n\n\n\n<p class=\"has-small-font-size\">\u00a9 Image credits to <a href=\"https:\/\/www.pexels.com\/@steve\/\" target=\"_blank\" rel=\"noreferrer noopener\">Steve Johnson<\/a><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Why \u201cit worked once\u201d isn\u2019t the same as \u201cit works every time\u201d Adding page numbers sounds like a solved problem\u2014until you put it into a real pipeline: CRM \u2192 generate PDF \u2192 merge attachments \u2192 paginate \u2192 send to client. That\u2019s where the gap between \u201cworks on my machine\u201d and \u201cworks every time\u201d shows up. In earlier implementations, teams often..<\/p>\n<a class=\"read-more-link\" href=\" https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/ \">Read more<\/a>","protected":false},"author":1,"featured_media":9972,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"content-type":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[2219],"tags":[],"class_list":["post-9971","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-crm"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.3 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security &#187; Little Marketing Book<\/title>\n<meta name=\"description\" content=\"Adding page numbers sounds like a solved problem\u2014until you put it into a real pipeline: CRM \u2192 generate PDF \u2192 merge attachments \u2192 paginate \u2192 send to client. That\u2019s where the gap between \u201cworks on my machine\u201d and \u201cworks every time\u201d shows up.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security &#187; Little Marketing Book\" \/>\n<meta property=\"og:description\" content=\"Adding page numbers sounds like a solved problem\u2014until you put it into a real pipeline: CRM \u2192 generate PDF \u2192 merge attachments \u2192 paginate \u2192 send to client. That\u2019s where the gap between \u201cworks on my machine\u201d and \u201cworks every time\u201d shows up.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/\" \/>\n<meta property=\"og:site_name\" content=\"Little Marketing Book\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/scalarly\/\" \/>\n<meta property=\"article:published_time\" content=\"2026-01-19T10:03:44+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-01-19T10:34:30+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1280\" \/>\n\t<meta property=\"og:image:height\" content=\"853\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"respect\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@teamscalarly\" \/>\n<meta name=\"twitter:site\" content=\"@teamscalarly\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"respect\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/\"},\"author\":{\"name\":\"respect\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#\/schema\/person\/3f3c5e5992d47fed746a015c091d41fb\"},\"headline\":\"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security\",\"datePublished\":\"2026-01-19T10:03:44+00:00\",\"dateModified\":\"2026-01-19T10:34:30+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/\"},\"wordCount\":1845,\"publisher\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#organization\"},\"image\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png?fit=1280%2C853&ssl=1\",\"articleSection\":[\"CRM\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/\",\"url\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/\",\"name\":\"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security &#187; Little Marketing Book\",\"isPartOf\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png?fit=1280%2C853&ssl=1\",\"datePublished\":\"2026-01-19T10:03:44+00:00\",\"dateModified\":\"2026-01-19T10:34:30+00:00\",\"description\":\"Adding page numbers sounds like a solved problem\u2014until you put it into a real pipeline: CRM \u2192 generate PDF \u2192 merge attachments \u2192 paginate \u2192 send to client. That\u2019s where the gap between \u201cworks on my machine\u201d and \u201cworks every time\u201d shows up.\",\"breadcrumb\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#primaryimage\",\"url\":\"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png?fit=1280%2C853&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png?fit=1280%2C853&ssl=1\",\"width\":1280,\"height\":853},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/scalarly.com\/marketing-book\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#website\",\"url\":\"https:\/\/scalarly.com\/marketing-book\/\",\"name\":\"Little Marketing Book\",\"description\":\"by Scalarly\",\"publisher\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/scalarly.com\/marketing-book\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#organization\",\"name\":\"Scalarly\",\"url\":\"https:\/\/scalarly.com\/marketing-book\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2019\/07\/logo-trans.png?fit=3066%2C674&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2019\/07\/logo-trans.png?fit=3066%2C674&ssl=1\",\"width\":3066,\"height\":674,\"caption\":\"Scalarly\"},\"image\":{\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/scalarly\/\",\"https:\/\/x.com\/teamscalarly\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#\/schema\/person\/3f3c5e5992d47fed746a015c091d41fb\",\"name\":\"respect\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/scalarly.com\/marketing-book\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/9e37ca8469decc469bf66e6cfcf54f0f3e070763ce31b703a3f9aaa6402b2ec9?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/9e37ca8469decc469bf66e6cfcf54f0f3e070763ce31b703a3f9aaa6402b2ec9?s=96&d=mm&r=g\",\"caption\":\"respect\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security &#187; Little Marketing Book","description":"Adding page numbers sounds like a solved problem\u2014until you put it into a real pipeline: CRM \u2192 generate PDF \u2192 merge attachments \u2192 paginate \u2192 send to client. That\u2019s where the gap between \u201cworks on my machine\u201d and \u201cworks every time\u201d shows up.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/","og_locale":"en_US","og_type":"article","og_title":"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security &#187; Little Marketing Book","og_description":"Adding page numbers sounds like a solved problem\u2014until you put it into a real pipeline: CRM \u2192 generate PDF \u2192 merge attachments \u2192 paginate \u2192 send to client. That\u2019s where the gap between \u201cworks on my machine\u201d and \u201cworks every time\u201d shows up.","og_url":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/","og_site_name":"Little Marketing Book","article_publisher":"https:\/\/www.facebook.com\/scalarly\/","article_published_time":"2026-01-19T10:03:44+00:00","article_modified_time":"2026-01-19T10:34:30+00:00","og_image":[{"width":1280,"height":853,"url":"https:\/\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png","type":"image\/png"}],"author":"respect","twitter_card":"summary_large_image","twitter_creator":"@teamscalarly","twitter_site":"@teamscalarly","twitter_misc":{"Written by":"respect","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#article","isPartOf":{"@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/"},"author":{"name":"respect","@id":"https:\/\/scalarly.com\/marketing-book\/#\/schema\/person\/3f3c5e5992d47fed746a015c091d41fb"},"headline":"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security","datePublished":"2026-01-19T10:03:44+00:00","dateModified":"2026-01-19T10:34:30+00:00","mainEntityOfPage":{"@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/"},"wordCount":1845,"publisher":{"@id":"https:\/\/scalarly.com\/marketing-book\/#organization"},"image":{"@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png?fit=1280%2C853&ssl=1","articleSection":["CRM"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/","url":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/","name":"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security &#187; Little Marketing Book","isPartOf":{"@id":"https:\/\/scalarly.com\/marketing-book\/#website"},"primaryImageOfPage":{"@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#primaryimage"},"image":{"@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png?fit=1280%2C853&ssl=1","datePublished":"2026-01-19T10:03:44+00:00","dateModified":"2026-01-19T10:34:30+00:00","description":"Adding page numbers sounds like a solved problem\u2014until you put it into a real pipeline: CRM \u2192 generate PDF \u2192 merge attachments \u2192 paginate \u2192 send to client. That\u2019s where the gap between \u201cworks on my machine\u201d and \u201cworks every time\u201d shows up.","breadcrumb":{"@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#primaryimage","url":"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png?fit=1280%2C853&ssl=1","contentUrl":"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png?fit=1280%2C853&ssl=1","width":1280,"height":853},{"@type":"BreadcrumbList","@id":"https:\/\/scalarly.com\/marketing-book\/always-correct-pagination-in-production-a-modern-playbook-for-async-page-numbering-limits-templates-and-security\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/scalarly.com\/marketing-book\/"},{"@type":"ListItem","position":2,"name":"Always-Correct Pagination in Production: A Modern Playbook for Async Page Numbering, Limits, Templates, and Security"}]},{"@type":"WebSite","@id":"https:\/\/scalarly.com\/marketing-book\/#website","url":"https:\/\/scalarly.com\/marketing-book\/","name":"Little Marketing Book","description":"by Scalarly","publisher":{"@id":"https:\/\/scalarly.com\/marketing-book\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/scalarly.com\/marketing-book\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/scalarly.com\/marketing-book\/#organization","name":"Scalarly","url":"https:\/\/scalarly.com\/marketing-book\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/scalarly.com\/marketing-book\/#\/schema\/logo\/image\/","url":"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2019\/07\/logo-trans.png?fit=3066%2C674&ssl=1","contentUrl":"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2019\/07\/logo-trans.png?fit=3066%2C674&ssl=1","width":3066,"height":674,"caption":"Scalarly"},"image":{"@id":"https:\/\/scalarly.com\/marketing-book\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/scalarly\/","https:\/\/x.com\/teamscalarly"]},{"@type":"Person","@id":"https:\/\/scalarly.com\/marketing-book\/#\/schema\/person\/3f3c5e5992d47fed746a015c091d41fb","name":"respect","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/scalarly.com\/marketing-book\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/9e37ca8469decc469bf66e6cfcf54f0f3e070763ce31b703a3f9aaa6402b2ec9?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9e37ca8469decc469bf66e6cfcf54f0f3e070763ce31b703a3f9aaa6402b2ec9?s=96&d=mm&r=g","caption":"respect"}}]}},"jetpack_featured_media_url":"https:\/\/i0.wp.com\/scalarly.com\/marketing-book\/wp-content\/uploads\/2026\/01\/Untitled-1280-x-853-px-5-4.png?fit=1280%2C853&ssl=1","jetpack_sharing_enabled":true,"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/posts\/9971","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/comments?post=9971"}],"version-history":[{"count":2,"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/posts\/9971\/revisions"}],"predecessor-version":[{"id":9978,"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/posts\/9971\/revisions\/9978"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/media\/9972"}],"wp:attachment":[{"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/media?parent=9971"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/categories?post=9971"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scalarly.com\/marketing-book\/wp-json\/wp\/v2\/tags?post=9971"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}