Viewer displays PDF correctly / Merged PDF file missing form fields

Which product are you using?
PDF JS Express

PDF.js Express Version

UI version ‘8.7.0’
Core version ‘8.7.0’
webviewer.min.js ‘8.7.0’
WebViewer Server false

Detailed description of issue
We are able to load an empty pdf, retrieve annotations from our db, merge them using the api, and view it in the Viewer. However, when we attempt to save the PDF from the merge URL, several but not all of the text boxes are missing and all checkboxes are missing. This previews perfectly in the Viewer, so it’s just the combined PDF that isn’t working.

Expected behaviour
Merged PDF should look exactly like the previewed PDF.

Does your issue happen with every document, or just one?

Link to document

Resulting PDF

Code snippet
$(document).ready(function() {

    var config = {
        path: '/Scripts/pdf-js-express/lib',
        licenseKey: 'VALID KEY',
        initialDoc: '/FormDocument/CreateFormTemplate/15',
        disableFlattenedAnnotations: true

    var viewerElement = document.getElementById('viewer');

    WebViewer(config, viewerElement)
        .then(async instance => {
            const { documentViewer, annotationManager } = instance.Core;
            // call methods from instance, docViewer and annotManager as needed

            // you can also access major namespaces from the instance as follows:
            // const Tools = instance.Tools;
            // const Annotations = instance.Annotations;

            documentViewer.addEventListener('documentLoaded', async () => {
                $("#btnSave").click(function() {
                    saveFile(false, documentViewer, annotationManager);
                $("#submitDocumentBtn").click(function() {
                    saveFile(true, documentViewer, annotationManager);

                documentViewer.zoomTo(1.5, 0, 0);
                .addEventListener('annotationsLoaded', async () => {
                        var xfdf = '<?xml version="1.0" encoding="UTF-8" ?><xfdf xmlns="" xml:space="preserve"><fields><field name="CHClient"><value>Katherine Asher</value></field><field name="CHGender"><value></value></field><field name="CHDateOfBirth"><value>11/02/1999</value></field><field name="CHInsurance"><value>Horizon NJ</value></field><field name="CHDate"><value>7/28/22</value></field><field name="CHAcceptServices"><value>Yes</value></field><field name="CHRefuseParticipation"><value>Off</value></field><field name="CHOccupationalTherapy"><value>Yes</value></field><field name="CHPhysicalTherapy"><value>Yes</value></field><field name="CHSpeechTherapy"><value>Yes</value></field><field name="CHHippa--AdmissionStandards"><value>Yes</value></field><field name="CHEmergencyPlan"><value>Yes</value></field><field name="CHNo"><value>Yes</value></field><field name="CHYes"><value>Off</value></field><field name="CHSafetyChangesDescription"><value></value></field><field name="CHSafteyAgreement"><value>Off</value></field><field name="CHNoWill"><value>Yes</value></field><field name="CHYesWill"><value>Off</value></field><field name="CHDoNotResuscitate"><value>Yes</value></field><field name="CHYesResuscitate"><value>Off</value></field><field name="CHNoPowerOfAttorney"><value>Yes</value></field><field name="CHYesPowerOfAttorney"><value>Off</value></field><field name="CHRatePerAssessmentVisit"><value>275.00</value></field><field name="CHRatePerTreatmentVisit"><value>195.00</value></field><field name="CHPaymentSources"><value></value></field><field name="CHFinancialResponsibilities"><value>Yes</value></field><field name="CHNoInsurance"><value>Yes</value></field><field name="CHInsuranceChanges"><value>Yes</value></field><field name="CHParentConsent"><value>Yes</value></field><field name="CHLegalGuardianConsent"><value>Off</value></field><field name="CHPCG"><value>LISA NELSON</value></field><field name="CHParent"><value>Yes</value></field><field name="CHLegalGuardian"><value>Off</value></field><field name="CHLastDayofService"><value></value></field><field name="CHAPartirDeFecha"><value></value></field><field name="CHPhysicalTherapyCancelAuthorizationDate"><value></value></field><field name="CHOccupationalTherapyCancelDate"><value></value></field><field name="CHSpeechCancelAuthDate"><value></value></field><field name="CHReasonForProviderChange"><value></value></field><field name="CHNoTreatmentInLast6Months"><value>Yes</value></field><field name="CHPCGInitials"><value>LMN</value></field><field name="CHPCGInitials2"><value>LMN</value></field><field name="CHTodaysDate"><value>7/28/22</value></field><field name="CHPrintedNameofGuardia/Parent"><value>Lisa Nelson</value></field><field name="CHRelationshipToChild"><value>caregiver</value></field><field name="CHTherapistName"><value>Trish G. </value></field><field name="CHTherapistSignature"><value></value></field></fields><pages><defmtx matrix="1,0,0,-1,0,792" /></pages></xfdf>';
                        await annotationManager.importAnnotations(xfdf);

async function saveFile(isSubmit, docViewer, annotManager) {

    try {

        const xfdf = await annotManager.exportAnnotations({links: false, widgets: false});
        const templateFileData = await fetch("/FormDocument/CreateFormTemplate/15").then(resp => resp.blob());

        var data = new FormData();

        data.append('xfdf', xfdf);
        data.append('file', templateFileData);
        data.append('license', 'VALID KEY');

        // Process the file
        const response = await fetch('',
                method: 'post',
                body: data
            }).then(resp => resp.json());

        const { url, key, id } = response;

        // Download the file
        var mergedBlob = await fetch(url,
                headers: {
                    Authorization: key
            }).then(resp => resp.blob());

        var data = new FormData();
        data.append("id", 15);
        data.append("pdfAnnotations", xfdf);
        data.append("fileStream", mergedBlob);

        return $.ajax({
            url: '/FormDocument/UploadFile',
            method: "POST",
            data: data,
            cache: false,
            contentType: false,
            processData: false,
            success: async data => {
                if (data.success) {
                    if (isSubmit) {
                        return submitFormDocument();
            error: function() {
                bootbox.alert("Sorry, an error has occurred and your changes may not have saved properly. Please try again.")
    } catch (ex) {
        bootbox.alert("Sorry, an error has occurred and your changes may not have saved properly. Please try again.");
    finally {

async function submitFormDocument() {

    return $.ajax({
        url: "/FormDocument/Submit",
        type: "POST",
        data: {
            formDocumentId: "15",
            timeZone: getClientSideTimeZone(),
            signatureDate: getClientSideDateString()
        success: function (data) {
            if (data.success) {
                var hasOpener = !isNullOrWhiteSpace(window.opener);

                if (hasOpener) {
                else {
                    var isPatient = true;
                    var isClinician = false;
                    var id = 3700;
                    var url;

                    if (isPatient) {
                        url = "/Patient/Chart/3700?patientPage=OtherDocuments";
                    } else if (isClinician) {
                        url = "/Clinician/Edit/3700?page=Documents";
                    } else {
                        url = "/";

            } else {
                if (data.message != "") {
                } else {
                    alert("Something went wrong please try again");
        error: function() {
            bootbox.alert("Sorry, an error has occurred and your changes may not have submitted properly. Please try again.")

Hello, I’m Ron, an automated tech support bot :robot:

While you wait for one of our customer support representatives to get back to you, please check out some of these documentation pages:


This is still an issue in the latest 8.7.

Hello chris1,

Can you provide the document shown in the photos? this would help reproducing the issue reported.

Best regards,
Tyler Gordon
Web Development Support Engineer

Sure. Here you go!

T2K_EngAdmit_CubHub.pdf (402.7 KB)

Hello chris1,

Thank you for the file, reviewing your code I see you have widgets: false in the exportAnnotations, this will not include any widget annotations (such as text boxes and check boxes) in the export.

Best regards,
Tyler Gordon
Web Development Support Engineer

Hey Tyler,

These aren’t new textboxes that have been added by the user via the PDFJS. They are in the original document. If it were the widget exporting option, I would think that all of the boxes would fail. As you can see in the screenshot though, some of the boxes do work and some do not.


Hello chris1,

I see instead of getting the file directly from the loaded viewer, you get:
const templateFileData = await fetch("/FormDocument/CreateFormTemplate/15").then(resp => resp.blob())
What is the result of this fetch? The requirements are it is the file to be used for the merge, in Blob format.

For example in the documentation:

    const fileData = await documentViewer.getDocument().getFileData({});
    const blob = new Blob([fileData], {type: 'application/pdf'});
    const data = new FormData();
    data.append('file', blob);

It gets the document and converts it to blob, then adds it to the form data.

Best regards,
Tyler Gordon
Web Development Support Engineer