Ask Anvil

Answers to questions about automating PDFs, e-signatures, Webforms, and other paperwork problems.
Webforms
Categories

How do I capture a drawn signature in a web form and add it to a PDF?

Draw on an HTML canvas with pointer events, copy the drawing into a hidden form field with canvas.toDataURL('image/png'), then embed that PNG into the PDF on the server. Two short pieces of code cover it.

1. The signature pad (browser)

<form method="post" action="/sign">
  <canvas id="sig" width="400" height="150"
          style="border:1px solid #999; touch-action:none"></canvas>
  <button type="button" id="clear">Clear</button>
  <input type="hidden" name="signature" id="signature">
  <button type="submit">Submit</button>
</form>

<script>
const canvas = document.getElementById('sig');
const ctx = canvas.getContext('2d');
ctx.lineWidth = 2;
ctx.lineCap = 'round';
let drawing = false;
let hasInk = false;

function point(e) {
  const r = canvas.getBoundingClientRect();
  return [
    (e.clientX - r.left) * (canvas.width / r.width),
    (e.clientY - r.top) * (canvas.height / r.height),
  ];
}

canvas.addEventListener('pointerdown', (e) => {
  drawing = true;
  canvas.setPointerCapture(e.pointerId);
  ctx.beginPath();
  ctx.moveTo(...point(e));
});
canvas.addEventListener('pointermove', (e) => {
  if (!drawing) return;
  ctx.lineTo(...point(e));
  ctx.stroke();
  hasInk = true;
});
canvas.addEventListener('pointerup', () => { drawing = false; });

document.getElementById('clear').addEventListener('click', () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  hasInk = false;
});

canvas.closest('form').addEventListener('submit', (e) => {
  if (!hasInk) {
    e.preventDefault();
    alert('Please sign before submitting.');
    return;
  }
  document.getElementById('signature').value = canvas.toDataURL('image/png');
});
</script>

Pointer events handle mouse, pen, and touch with one set of listeners. setPointerCapture() keeps the stroke going if the pointer drifts off the canvas mid-signature. The point() helper converts screen coordinates to canvas pixels, so the ink lines up even when CSS resizes the canvas. touch-action: none stops the browser from panning or zooming while someone signs with a finger. The submit handler refuses an empty pad.

2. Stamp it onto the PDF (Node.js)

This uses pdf-lib, which runs in plain Node with no native dependencies:

import { PDFDocument } from 'pdf-lib';

export async function stampSignature(pdfBytes, dataUrl) {
  if (!dataUrl.startsWith('data:image/png;base64,')) {
    throw new Error('Expected a PNG data URL');
  }

  const pdfDoc = await PDFDocument.load(pdfBytes);
  const png = await pdfDoc.embedPng(dataUrl); // data URLs work as-is

  // Fit the signature into a 200 x 60 box, keeping its aspect ratio
  const { width, height } = png.scaleToFit(200, 60);

  const page = pdfDoc.getPages()[0];
  page.drawImage(png, { x: 72, y: 100, width, height });

  return pdfDoc.save(); // Uint8Array, ready to write or upload
}

// Usage in your form handler:
// const signed = await stampSignature(await readFile('contract.pdf'), req.body.signature);

embedPng() accepts the data URL string directly, so you do not need to strip the prefix or decode the base64 yourself. scaleToFit() shrinks the image into the box without distorting it.

The gotcha: PDF coordinates start at the bottom-left corner of the page, not the top-left like the browser. y: 100 puts the signature near the bottom of the page. If it lands in the wrong spot, measure your signature line from the bottom edge.

Caveats

Limit the payload. toDataURL() returns the whole image as a single string, so cap the request body size on the route that receives the form, and keep the prefix check so only PNG data gets embedded.

An image is not an audit trail. A PNG shows what was drawn, not who drew it or when. If the document needs to hold up later as a signed agreement, also store who signed, the time, and a hash of the final PDF, or send the document through an e-signature service that records those details for you.

Back to All Questions

The fastest way to build software for documents

Anvil Document SDK is a comprehensive toolbox for product teams launching document flows where PDF filling, signing, and complex conditional scenarios are necessary.
Explore Anvil
Anvil Webforms