How to use JavaScript to capture signatures in PDFs

Table of contents

    How to use JavaScript to capture signatures in PDFs
    Summary

    Learn how to capture and embed electronic signatures in PDFs using JavaScript — from basic signature drawing with Signature Pad, to advanced integration with a professional PDF annotation library. This guide covers client-side signature capture using HTML canvas, programmatic signature insertion with pdf-lib, and enterprise-grade eSignature features using Nutrient’s JavaScript SDK.

    In this tutorial, you’ll walk through the process of creating a web-based app that enables users to capture and save signatures as images, as well as insert these signatures into a PDF document. You’ll be using HTML, JavaScript, and two external libraries — Signature Pad(opens in a new tab) and pdf-lib(opens in a new tab) — to achieve this functionality. The app will provide a canvas for users to draw their signatures, save them as PNG images, and embed them into a PDF for download.

    In the second part, you’ll explore using the Nutrient JavaScript PDF library to incorporate electronic signatures (eSignatures) into PDF documents. The post will cover:

    • Adding eSignatures via the user interface (UI)
    • Adding eSignatures programmatically
    • Adding ink signatures programmatically
    • Adding image signatures programmatically
    • Creating signature fields in PDF documents

    Step 1 — Setting up the HTML structure

    To begin, set up a basic HTML file. Include a canvas element that acts as a signature pad and a placeholder div to display the PDF. Additionally, add the necessary JavaScript libraries — Signature Pad and pdf-lib — which will be crucial for signature drawing and PDF manipulation:

    <!DOCTYPE html>
    <html>
    <head>
    <title>Signature Capture</title>
    <!-- Include Signature Pad library -->
    <script src="https://cdn.jsdelivr.net/npm/signature_pad@4.0.0/dist/signature_pad.umd.min.js"></script>
    <!-- Include pdf-lib library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf-lib/1.16.0/pdf-lib.min.js"></script>
    </head>
    <body>
    <!-- Placeholder for PDF display -->
    <div id="pdfViewer"></div>
    <!-- Signature Canvas -->
    <canvas id="signatureCanvas" width="400" height="200"></canvas>
    <!-- Add a button to trigger signature saving and insertion -->
    <button onclick="saveSignatureAndInsertIntoPDF()">
    Save Signature and Insert into PDF
    </button>
    <script>
    // JavaScript code will be added here.
    </script>
    </body>
    </html>

    Step 2 — Initializing the signature pad

    In your JavaScript section, access the canvas element and initialize the signature pad:

    // Accessing the canvas element.
    const signatureCanvas = document.getElementById("signatureCanvas");
    const signaturePad = new SignaturePad(signatureCanvas);

    This enables you to interact with the canvas and capture user-drawn signatures.

    Step 3 — Saving the signature as an image

    When users click the Save Signature and Insert into PDF button, you’ll capture the signature from the canvas as an image and save it for further use. You achieve this by calling the toDataURL method of the signature pad and creating a temporary link element to initiate the download:

    // Function to save the signature as an image and insert it into the PDF.
    async function saveSignatureAndInsertIntoPDF() {
    const signatureDataUrl = signaturePad.toDataURL("image/png");
    // You can now send this data to the server for processing or save it locally.
    console.log(signatureDataUrl); // Log the signature data URL for demonstration purposes.
    // Call the function to insert the signature into the PDF.
    const modifiedPDFBytes = await insertSignatureIntoPDF(signatureDataUrl);
    // Download the modified PDF with the inserted signature.
    downloadModifiedPDF(modifiedPDFBytes);
    }

    Step 4 — Inserting the signature into the PDF

    To embed the signature image into a PDF, you’ll use the pdf-lib library. Load the existing PDF document from a file and convert it to a Uint8Array. Then, embed the signature image as a custom image using the embedPng method. Finally, add the image to the PDF document at the desired position:

    // Function to insert the signature into the PDF.
    async function insertSignatureIntoPDF(signatureDataURL) {
    const pdfBytes = await fetch("document.pdf").then((res) => res.arrayBuffer());
    const pdfDoc = await PDFLib.PDFDocument.load(pdfBytes);
    // Convert the data URL to a `Uint8Array`.
    const signatureImageArray = dataURLToUint8Array(signatureDataURL);
    // Embed the signature image as a custom image.
    const signatureImage = await pdfDoc.embedPng(signatureImageArray);
    const { width, height } = signatureImage;
    const pages = pdfDoc.getPages();
    const firstPage = pages[0];
    const x = firstPage.getWidth() - 100 - width; // Adjust the value 100 for the horizontal position.
    const y = firstPage.getHeight() - 100 - height; // Adjust the value 100 for the vertical position.
    // Add the signature image to the first page at the desired location.
    firstPage.drawImage(signatureImage, {
    x: x,
    y: y,
    width: width,
    height: height,
    });
    // Save the modified PDF.
    const modifiedPDFBytes = await pdfDoc.save();
    return modifiedPDFBytes;
    }
    // Function to convert data URL to a `Uint8Array`.
    function dataURLToUint8Array(dataURL) {
    // Extract the Base64-encoded data from the data URL.
    const base64 = dataURL.split(",")[1];
    // Decode the Base64-encoded data into a binary string.
    const binaryString = atob(base64);
    // Create a new `Uint8Array` with the length of the binary string.
    const array = new Uint8Array(binaryString.length);
    // Iterate through the binary string and convert each character to a number and store it in the `Uint8Array`.
    for (let i = 0; i < binaryString.length; i++) {
    array[i] = binaryString.charCodeAt(i);
    }
    return array;
    }

    The Signature Pad library provides the signature as a data URL in Base64 format. However, the pdf-lib library requires the signature data in Uint8Array format, which is a common method for handling binary data. To insert the signature into the PDF, you need to convert it from Base64 to Uint8Array.

    Make sure to replace document.pdf with the path to your PDF document.

    Step 5 — Triggering the download of the modified PDF

    Finally, create a function to trigger the download of the modified PDF with the embedded signature. Convert the PDF bytes into a Blob and create a temporary URL for the download:

    // Function to trigger the download of the modified PDF.
    function downloadModifiedPDF(modifiedPDFBytes) {
    const blob = new Blob([modifiedPDFBytes], {
    type: "application/pdf",
    });
    const url = URL.createObjectURL(blob);
    // Create a link element to trigger the download.
    const downloadLink = document.createElement("a");
    downloadLink.href = url;
    downloadLink.download = "modified_document.pdf"; // Specify the filename for the downloaded PDF.
    // Append the link to the body and click it to trigger the download.
    document.body.appendChild(downloadLink);
    downloadLink.click();
    document.body.removeChild(downloadLink);
    }
    0:00
    0:00

    Capturing signatures in PDFs using the Nutrient Web SDK JavaScript library

    Nutrient offers a commercial PDF viewer SDK that integrates into your web application. Nutrient Web SDK includes 30+ features, enabling users to view, annotate, edit, and sign PDFs directly in the browser.

    Requirements

    Adding Nutrient to your project

    1. Install the @nutrient-sdk/viewer package from npm. If you prefer, you can also download Nutrient Web SDK manually:
    Terminal window
    npm install @nutrient-sdk/viewer
    1. For Nutrient Web SDK to work, it’s necessary to copy the directory containing all the required library files (artifacts) to the assets folder. Use the following command to do this:
    Terminal window
    cp -R ./node_modules/@nutrient-sdk/viewer/dist/ ./assets/

    Make sure your assets directory contains the nutrient-viewer.js file and a nutrient-viewer-lib directory with the library assets.

    Integrating into your project

    1. Add the PDF document you want to display to your project’s directory. You can use our demo document as an example.
    2. Add an empty <div> element with a defined height to where Nutrient will be mounted:
    <div id="nutrient" style="height: 100vh;"></div>
    1. Include nutrient-viewer.js in your HTML page:
    <script src="assets/nutrient-viewer.js"></script>
    1. Initialize Nutrient Web SDK in JavaScript by calling NutrientViewer.load():
    <script>
    async function loadNutrientViewer() {
    try {
    const instance = await NutrientViewer.load({
    container: '#nutrient',
    document: 'document.pdf',
    });
    console.log('Nutrient Web SDK loaded', instance);
    } catch (error) {
    console.error(error.message);
    }
    }
    loadNutrientViewer();
    </script>

    Adding eSignatures via the Nutrient UI

    To sign PDF documents using Nutrient’s UI, open the demo and locate the sign icon. Clicking it will prompt a dialog box where you can sign your name. Nutrient offers options to customize your signature, such as selecting the pen color and inserting an image or text as your signature. You can also resize and reposition your signature.

    In the following sections, you’ll learn how to programmatically add ink and image signatures to PDF documents using JavaScript.

    Adding eSignatures programmatically in JavaScript

    Nutrient offers two distinct types of signatures that can be added to PDF documents: ink signatures and image signatures. In this section, you’ll learn how to create these signature types programmatically and add them to PDF documents.

    Adding ink signatures programmatically

    Ink signatures are freehand drawings that resemble traditional pen and paper signatures. To add an ink signature programmatically, modify the NutrientViewer.load() function as follows:

    // Create Ink Annotation
    const inkAnnotation = new NutrientViewer.Annotations.InkAnnotation({
    pageIndex: 0,
    isSignature: true,
    lines: NutrientViewer.Immutable.List([
    NutrientViewer.Immutable.List([
    new NutrientViewer.Geometry.DrawingPoint({ x: 5, y: 5 }),
    new NutrientViewer.Geometry.DrawingPoint({ x: 95, y: 95 }),
    ]),
    NutrientViewer.Immutable.List([
    new NutrientViewer.Geometry.DrawingPoint({ x: 95, y: 5 }),
    new NutrientViewer.Geometry.DrawingPoint({ x: 5, y: 95 }),
    ]),
    ]),
    boundingBox: new NutrientViewer.Geometry.Rect({
    left: 0,
    top: 0,
    width: 100,
    height: 100,
    }),
    });
    await instance.create(inkAnnotation);
    console.log("Ink annotation created successfully.");

    The NutrientViewer.load() function initializes the Nutrient instance, and NutrientViewer.Annotations.InkAnnotation creates freehand drawings for ink signatures, with the isSignature property set to true. The lines and boundingBox parameters define the signature path and position. NutrientViewer.Geometry.DrawingPoint specifies the coordinates for each point in the signature, while boundingBox determines its position and size on the page.

    PDF document with an ink signature annotation displayed as crossed lines in the top-left corner

    Adding image signatures programmatically

    An image annotation allows you to add an image to a PDF document. To add an image signature programmatically, update the NutrientViewer.load() function:

    // Create Image Annotation
    const request = await fetch("image.png");
    const blob = await request.blob();
    const attachmentId = await instance.createAttachment(blob);
    const imageAnnotation = new NutrientViewer.Annotations.ImageAnnotation({
    pageIndex: 0,
    contentType: "image/jpeg",
    imageAttachmentId: attachmentId,
    description: "Image Description",
    boundingBox: new NutrientViewer.Geometry.Rect({
    left: 30,
    top: 20,
    width: 300,
    height: 150,
    }),
    });
    await instance.create(imageAnnotation);
    console.log("Image annotation created successfully.");

    In the code snippet, NutrientViewer.Annotations.ImageAnnotation is created by passing several properties — such as pageIndex, contentType, imageAttachmentId, description, and boundingBox — which are defined below:

    • pageIndex — Specifies the page number on which the image annotation is added.
    • isSignature — When an image annotation is created via the signature UI, this flag is set to true.
    • contentType — Specifies the MIME type of the image file.
    • imageAttachmentId — Specifies the ID of the attachment that contains the image data.
    • description — An optional property that provides a description for the image.
    • boundingBox — Specifies the position and size of the image on the PDF document.

    Once the image annotation is created, it can be added to the PDF document using the instance.create() method.

    To see the image, upload an image file named image.png to the root directory of your project.

    PDF document with an image signature embedded as an annotation on the first page

    Creating signature fields in PDF documents

    Nutrient lets you create signature fields in your PDF documents for adding signatures. Update the NutrientViewer.load() function in the index.html file:

    // Create Signature Form Field
    const widget = new NutrientViewer.Annotations.WidgetAnnotation({
    pageIndex: 0,
    boundingBox: new NutrientViewer.Geometry.Rect({
    left: 200,
    top: 200,
    width: 250,
    height: 150,
    }),
    formFieldName: "My signature form field",
    id: NutrientViewer.generateInstantId(),
    });
    const formField = new NutrientViewer.FormFields.SignatureFormField({
    name: "My signature form field",
    annotationIds: NutrientViewer.Immutable.List([widget.id]),
    });
    await instance.create([widget, formField]);
    console.log("Signature form field created successfully.");

    In the code snippet above, you can create a new signature field that allows users to sign within that specific field. The NutrientViewer.Annotations.WidgetAnnotation record(opens in a new tab) is used to define the properties of the signature field, such as its page index, bounding box dimensions, and form field name. The NutrientViewer.FormFields.SignatureFormField record(opens in a new tab) is used to specify the name and IDs of the annotations associated with the signature field. Finally, the instance.create() function is used to create the signature field and add it to the PDF document.

    0:00
    0:00

    Conclusion

    In this tutorial, you first created a simple web app that allows users to capture and save their signatures as images. Additionally, users can insert these signatures into a PDF document, creating a downloadable modified PDF file with the inserted signature.

    You then explored how to capture signatures in PDF documents using the Nutrient Web SDK JavaScript library. Nutrient lets you manage electronic signatures and enhance your PDF documents with annotations, text highlighting, and custom forms.

    To see a list of all web frameworks, you can contact our Sales team. Or, launch our demo to see our viewer in action.

    FAQ

    How do I capture a signature in JavaScript?

    Use the HTML canvas element with a library like Signature Pad to capture freehand signatures. Initialize the signature pad on a canvas element. Then call toDataURL() to export the signature as a PNG image for embedding into documents.

    Can I add signatures to PDFs without a server?

    Yes. Client-side libraries like pdf-lib allow you to embed signature images into PDFs directly in the browser. For enterprise features like signature fields and digital signatures, Nutrient Web SDK provides a complete solution with no server required.

    What’s the difference between ink and image signatures?

    Ink signatures are freehand drawings created with drawing points, resembling traditional pen signatures. Image signatures use uploaded or captured images (PNG, JPEG) embedded as annotations. Both can be added programmatically using Nutrient Web SDK.

    How do I create a signature field in a PDF?

    Use NutrientViewer.Annotations.WidgetAnnotation to define the field’s position and size. Then create a NutrientViewer.FormFields.SignatureFormField with the widget’s ID. The instance.create() method adds both to the PDF document.

    Does Nutrient support digital signatures with certificates?

    Yes. Nutrient Web SDK supports both electronic signatures (visual signatures) and digital signatures with cryptographic certificates for document authentication and non-repudiation. See our signatures guide for implementation details.

    Hulya Masharipov

    Hulya Masharipov

    Technical Writer

    Hulya is a frontend web developer and technical writer who enjoys creating responsive, scalable, and maintainable web experiences. She’s passionate about open source, web accessibility, cybersecurity privacy, and blockchain.

    Explore related topics

    Try for free Ready to get started?