Legal Technology & Document Engineering•Published October 2, 2026•16 min read

Legal Document Numbering & Bates Stamping: In-Browser Header & Footer Guide

In modern corporate litigation, regulatory investigations, patent disputes, and international arbitration, legal teams are required to produce thousands—often millions—of evidentiary pages during the discovery phase. To maintain an indisputable chain of custody and allow attorneys, judges, and expert witnesses to reference specific pages precisely during depositions and trials, the legal profession relies on Bates Stamping (also known as Bates Numbering).

Originating in the late 19th century with Edwin G. Bates's mechanical sequential numbering stamp machine, modern Bates stamping has evolved into a sophisticated digital process applied to PDF files. Concurrently, academic publications, formal contracts, technical manuals, and corporate reports require standardized Page X of Y headers and footers with precise typographical alignment.

However, implementing digital numbering in PDF documents presents subtle mathematical and architectural hurdles: inverted Cartesian coordinate spaces, font glyph width calculation, margin clipping avoidance, and batch sequence preservation across multi-volume document bundles. In this technical guide, we break down PDF coordinate mathematics, explore Bates stamping conventions, and provide production-ready JavaScript code for stamping litigation bundles client-side with 100% data privacy.

Advertisement
Responsive In-Article Ad Slot

PDF Typographic Coordinate Space & Alignment Geometry

The most common error developers encounter when programmatically stamping headers and footers in PDF files is assuming the coordinate space behaves like web CSS or HTML5 Canvas (where $(0, 0)$ is the top-left corner). In the PostScript/PDF model (ISO 32000), the origin $(0, 0)$ is fixed at the lower-left corner of the page.

PDF CARTESIAN COORDINATE SPACE & HEADER/FOOTER SLOTS Header: Y = Height - Margin Footer: Y = Margin Origin (0,0) +Y (Points) +X (Points) 1. Vertical Y-Positioning: Y_footer = margin_bottom Y_header = pageHeight - margin_top - fontCapHeight 2. Horizontal X-Positioning: Left: X = margin_left Center: X = (pageWidth - textWidth) / 2 Right: X = pageWidth - margin_right - textWidth 3. String Width Derivation: textWidth = font.widthOfTextAtSize(str, fontSize)
Figure 1: PDF Cartesian coordinate space where (0,0) is at the lower-left corner, and exact horizontal alignment requires string width subtraction.

Font Metric Calculations

Because PDF renderers draw glyphs starting from the left baseline anchor of the text, placing text flush-right requires looking up the exact glyph width metrics of each character in the string at the target font size (e.g., 9pt or 10pt Helvetica). Subtracting textWidth from the right margin ensures the final digit aligns perfectly with the margin line across all pages.

Add Page Numbers & Bates Stamps to PDFs

Number single documents or batch-stamp legal bundles with custom prefixes, zero padding, and header/footer positioning in your browser.

Launch In-Browser PDF Page Numbering Tool →

Bates Stamping Standards in Civil & Criminal Discovery

Federal Rules of Civil Procedure (FRCP Rule 34) and judicial standing orders in courts worldwide prescribe strict formats for document production. Standard Bates numbers follow an explicit alphanumeric formula:

[PARTY_PREFIX]-[DOC_CATEGORY]-[ZERO_PADDED_NUMBER]
Example: ACME-CORP-PROD-0001429 or PLTF-EXHIBIT-000045
MULTI-FILE LEGAL BUNDLE BATES NUMBERING FLOW Contract.pdf (12 Pages) Start: 000001 End: 000012 DEF-000001 to 012 Emails.pdf (35 Pages) Start: 000013 End: 000047 DEF-000013 to 047 Audit.pdf (50 Pages) Start: 000048 End: 000097 DEF-000048 to 097
Figure 2: Sequential Bates numbering continuous across multiple distinct PDF files in a litigation production set.

Bates Stamping Key Requirements

  1. Uniform Zero-Padding: Numbers must be padded with leading zeros (e.g., 000001 to 000100) to prevent string-sorting errors in litigation databases like Relativity, Concordance, or Everlaw. Standard padding widths range between 6 and 8 digits.
  2. Continuous Bundle Sequence: When producing a bundle of 50 distinct PDF files, the sequence counter must not reset to 1 on each file; Document 2 must start at $(N_{\text{Doc1\_pages}} + 1)$.
  3. Confidentiality Label Conjunction: Under Protective Orders, pages subject to trade secret or privacy protections must pair the Bates stamp with a confidentiality legend (e.g., "CONFIDENTIAL - ATTORNEYS' EYES ONLY").

JavaScript Code: In-Browser Bates Stamping Engine

The following standalone TypeScript/JavaScript function applies continuous Bates numbering or Page X of Y formulas to a PDF in the browser using pdf-lib:

import { PDFDocument, rgb, StandardFonts } from 'pdf-lib';

/**
 * Stamps sequential Bates numbers and page counts onto a PDF document.
 * @param {ArrayBuffer} pdfBuffer - Input PDF binary
 * @param {Object} options - Numbering configuration
 * @returns {Promise<Uint8Array>} Modified PDF binary
 */
export async function applyBatesStamping(pdfBuffer, options = {}) {
  const {
    prefix = 'PLTF-',
    startNumber = 1,
    padding = 6,
    format = '{prefix}{bates}', // or 'Page {page} of {total}'
    position = 'bottom-right',  // 'top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right'
    fontSize = 9,
    margin = 36, // 0.5 inch (36 points)
    confidentialText = null
  } = options;

  const pdfDoc = await PDFDocument.load(pdfBuffer);
  const pages = pdfDoc.getPages();
  const totalPages = pages.length;
  const font = await pdfDoc.embedStandardFont(StandardFonts.HelveticaBold);

  let currentSequence = startNumber;

  for (let i = 0; i < totalPages; i++) {
    const page = pages[i];
    const { width, height } = page.getSize();
    const pageNum = i + 1;

    // 1. Format zero-padded number
    const batesStr = String(currentSequence).padStart(padding, '0');
    currentSequence++;

    // 2. Interpolate template string
    let stampText = format
      .replace('{prefix}', prefix)
      .replace('{bates}', batesStr)
      .replace('{page}', pageNum)
      .replace('{total}', totalPages);

    const textWidth = font.widthOfTextAtSize(stampText, fontSize);
    const textHeight = font.heightAtSize(fontSize);

    // 3. Compute X coordinate
    let x = margin;
    if (position.includes('center')) {
      x = (width - textWidth) / 2;
    } else if (position.includes('right')) {
      x = width - margin - textWidth;
    }

    // 4. Compute Y coordinate
    let y = margin;
    if (position.includes('top')) {
      y = height - margin - textHeight;
    }

    // 5. Draw text
    page.drawText(stampText, {
      x,
      y,
      size: fontSize,
      font: font,
      color: rgb(0.1, 0.1, 0.1)
    });

    // Optional Confidential Label on opposite corner
    if (confidentialText) {
      const confWidth = font.widthOfTextAtSize(confidentialText, fontSize);
      const confX = position.includes('right') ? margin : width - margin - confWidth;
      page.drawText(confidentialText, {
        x: confX,
        y: y,
        size: fontSize,
        font: font,
        color: rgb(0.8, 0.1, 0.1)
      });
    }
  }

  return await pdfDoc.save();
}

Dynamic Page X of Y Formulas vs. Fixed Indices

For non-litigation business applications, the Page X of Y format is the universal standard for financial prospectuses, technical specifications, and contracts. It provides immediate notice if a page has been omitted or detached from a physical printout.

When generating dynamic headers/footers, developers should support token variables:

  • {page}: Current 1-based page number.
  • {total}: Total count of pages in the current document.
  • {date}: Export or generation date formatted as ISO 8601 or localized.
  • {title}: Document title extracted from the PDF Info dictionary.

Frequently Asked Questions

If an evidentiary document is a full-bleed scanned image without existing margins, drawing a Bates stamp in the footer can overlap with bottom text. Legal document processing suites address this by slightly scaling down the page content (e.g., to 95% scale) to introduce a clean white margin band before stamping.
Standard monospace or sans-serif fonts such as Courier or Helvetica Bold at 9pt or 10pt are standard across federal and state courts. Monospace fonts ensure consistent stamp widths across changing digit values.
Yes. Because client-side tools execute entirely within the local web browser using WebAssembly or JavaScript ArrayBuffers without sending data packets over the network, no Protected Health Information (PHI) or proprietary client data leaves the local machine, ensuring 100% HIPAA, GDPR, and attorney-client privilege compliance.
Landscape pages (where width exceeds height or the page dictionary contains /Rotate 90) require dynamic coordinate checking. A robust stamping engine dynamically reads each page's specific width, height, and rotation matrix, recalculating $(x, y)$ coordinates per page rather than applying fixed coordinates across the entire document.

Summary & Implementation Checklist

Mastering PDF coordinate space, typographical alignment mathematics, and zero-padding sequential logic allows legal and software engineering teams to produce flawless discovery sets, professional corporate documentation, and regulatory filings directly in the browser with speed, precision, and privacy.

CS

Collabsource Editorial Team

Experts in legal technology, PDF engineering specifications (ISO 32000), client-side privacy architecture, and document automation.