X Xerobit

Base64 PDF Embedding — Inline PDFs in HTML, JSON APIs, and Email

Embed PDF files as Base64 strings in HTML data URIs, JSON API responses, and email attachments. Learn when Base64 embedding makes sense, the size overhead, and alternatives...

Mian Ali Khalid · · 4 min read
Use the tool
Base64 Encoder / Decoder
Encode and decode Base64 strings and files. Client-side, safe for sensitive data.
Open Base64 Encoder / Decoder →

Base64-embedding PDFs avoids separate HTTP requests for inline display. The 33% size overhead is acceptable for small documents but problematic for large files.

Encode and decode Base64 with the base64 decoder and encoder.

Embed PDF in HTML with data URI

<!-- Inline PDF viewer using data URI -->
<iframe
  src="data:application/pdf;base64,JVBERi0xLjQK..."
  width="100%"
  height="600px"
  type="application/pdf"
>
  <p>Your browser doesn't support embedded PDFs.</p>
</iframe>

<!-- Alternative: object tag -->
<object
  data="data:application/pdf;base64,JVBERi0xLjQK..."
  type="application/pdf"
  width="100%"
  height="600px"
>
  <embed src="data:application/pdf;base64,JVBERi0xLjQK..." type="application/pdf">
</object>

Browser support: Chrome and Firefox support PDF data URIs in iframes. Safari requires a direct URL for <iframe> PDFs — use a blob URL instead.

Node.js: read PDF and create data URI

import { readFileSync } from 'fs';

function pdfToDataURI(filePath) {
  const pdf = readFileSync(filePath);
  const base64 = pdf.toString('base64');
  return `data:application/pdf;base64,${base64}`;
}

// For small reports:
const dataURI = pdfToDataURI('report.pdf');
// Pass to HTML template or JSON response

// Size check: 1MB PDF → ~1.37MB Base64 (33% overhead)
const stats = require('fs').statSync('report.pdf');
console.log(`PDF: ${(stats.size / 1024).toFixed(1)} KB`);
console.log(`Base64: ${(dataURI.length / 1024).toFixed(1)} KB`);

Blob URL approach (browser, avoids Safari issues)

// Browser: convert base64 to blob URL for better compatibility
function base64ToBlobURL(base64, mimeType = 'application/pdf') {
  const bytes = atob(base64);
  const buffer = new Uint8Array(bytes.length);
  for (let i = 0; i < bytes.length; i++) {
    buffer[i] = bytes.charCodeAt(i);
  }
  const blob = new Blob([buffer], { type: mimeType });
  return URL.createObjectURL(blob);
}

async function showPDF(base64PDF) {
  const blobURL = base64ToBlobURL(base64PDF);
  const iframe = document.getElementById('pdf-viewer');
  iframe.src = blobURL;
  
  // Revoke URL when done to free memory:
  iframe.onload = () => {
    // Keep the URL alive while the PDF is shown
    // Revoke when navigating away:
  };
  
  window.addEventListener('beforeunload', () => URL.revokeObjectURL(blobURL));
}

JSON API: include PDF in response

// Express: include PDF in JSON response (small reports only)
app.get('/api/invoice/:id', async (req, res) => {
  const invoice = await generateInvoicePDF(req.params.id);
  
  if (invoice.size > 1024 * 1024) {
    // Large PDF: return a URL instead of embedding
    const url = await uploadToS3(invoice);
    return res.json({ downloadUrl: url, expiresIn: 3600 });
  }
  
  const base64 = invoice.toString('base64');
  res.json({
    invoiceId: req.params.id,
    filename: `invoice-${req.params.id}.pdf`,
    contentType: 'application/pdf',
    data: base64,
    size: invoice.size,
  });
});

Email attachment (MIME multipart)

import nodemailer from 'nodemailer'; // npm install nodemailer

async function sendEmailWithPDF(to, subject, pdfBuffer) {
  const transporter = nodemailer.createTransport({ /* config */ });
  
  await transporter.sendMail({
    from: 'sender@example.com',
    to,
    subject,
    text: 'Please find your invoice attached.',
    attachments: [
      {
        filename: 'invoice.pdf',
        content: pdfBuffer,     // Buffer — nodemailer handles Base64 encoding
        contentType: 'application/pdf',
      },
    ],
  });
}

// Or with base64 string:
await transporter.sendMail({
  attachments: [{
    filename: 'report.pdf',
    encoding: 'base64',
    content: base64String,
  }],
});

When to use Base64 vs presigned URL

SituationUse
PDF < 500KB, needs to be in JSON responseBase64
PDF > 1MBPresigned S3/GCS URL
Real-time generated PDF, one-time useBlob URL
Email attachmentBase64 (MIME standard)
Long-term storage / CDN deliveryStorage URL
PDF that changes per userOn-demand generation + signed URL

Related posts

Related tool

Base64 Encoder / Decoder

Encode and decode Base64 strings and files. Client-side, safe for sensitive data.

Written by Mian Ali Khalid. Part of the Encoding & Crypto pillar.