Issue with the license API not getting called

Which product are you using?
PDF.js Express Viewer

PDF.js Express Version
8.7.4

Detailed description of issue
We implement the viewer on our website to be able to view pdfs in List 1 section of the screenshot below. It worked great, no issues.


Now we need to do the same for List 2. However, once we implemented it in similar fashion we run into a problem when the viewer doesn’t want to load. For example, if I can open pdfs in List 1 then I can’t open any pdf in List 2, or vice versa - if I can open pdfs in List 2 then I can’t open any pdf in List 1.
The error that we see is this:
PDFJSDocumentType.js:118 A license key is required to use the view only build of PDF.js Express. Get your free license key at PDF.js Express (account required)

We verified that we are passing the license key. We noticed that when the viewer doesn’t load there is no call to auth api
image
This is what we see
image

Our project is made of small react apps. So list 1 and list 2 are separate react apps that share some components. The viewer opens up in a modal which is a reusable component.

Expected behaviour
We expect for the document to open

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

Link to document
n/a

Code snippet
This is the document viewer component.
file.file is the blob we are passing in

import WebViewer from “@pdftron/pdfjs-express-viewer”;
import { useEffect, useRef, useState } from “react”;
import { ViewerFile } from “./typings”;

type Props = {
file: ViewerFile;
onDownload?: (file: ViewerFile) => void;
};

const DocumentViewer = ({ file, onDownload }: Props) => {
const viewer = useRef(null);
const [instance, setInstance] = useState(null);

useEffect(() => {
WebViewer(
{
path: “/Resources/dist/js/pdfjsexpress”,
licenseKey: “licenseKey”
css: “/Resources/dist/styles/app.css”,
disableLogs: true,
enableAnnotations: false,
disabledElements: [
“moreButton”,
“menuButton”,
“searchButton”,
“printButton”,
“downloadButton”,
“fullscreenButton”,
“toggleNotesButton”,
“panToolButton”,
“selectToolButton”,
“thumbnailsPanelButton”,
“thumbnailsSizesSlider”,
“thumbnailsPanel”,
“leftPanelButton”,
“stickyToolButton”,
“textSelectButton”,
“contextMenuPopup”,
],
},
viewer.current
).then(instance => {
setInstance(instance);
});
}, );

useEffect(() => {
if (instance) {
const { UI, Core } = instance;
const isDesktop = window.innerWidth > 992;

  UI.setPrintQuality(3);

  //Print options
  UI.setDefaultPrintOptions({
    includeComments: false,
    includeAnnotations: false,
  });

  // Custom buttons
  UI.setHeaderItems((header: any) => {
    const defaultHeader = header.getHeader("default");
    defaultHeader.push({
      img: "icon-header-download",
      index: -1,
      title: "Download",
      type: "actionButton",
      element: "downloadButton",
      onClick: () => {
        if (onDownload) {
          onDownload(file);
        } else {
          UI.downloadPdf();
        }
      },
    });
    defaultHeader.push({
      img: "icon-header-print-line",
      index: -1,
      title: "Print",
      type: "actionButton",
      element: "printButton",
      onClick: () => UI.printInBackground(),
    });
    if (isDesktop) {
      defaultHeader.push({
        img: "icon-header-full-screen",
        index: -1,
        title: "Toggle full screen",
        type: "actionButton",
        element: "fullscreenButton",
        onClick: () => UI.toggleFullScreen(),
      });
    }
  });

  if (isDesktop) {
    // Default zoom to 120% on bigger screens
    Core.documentViewer.addEventListener("documentLoaded", () => {
      Core.documentViewer.zoomTo(1.2);
    });
  }
}

}, [file, onDownload, instance]);

useEffect(() => {
if (instance && file?.file) {
instance.UI.loadDocument(file.file, { filename: file.fileName });
}
}, [instance, file]);

if (!file?.file) {
return null;
}
return (
<div className=“App” style={{ height: “100%” }}>
<div className=“webviewer” ref={viewer} style={{ height: “100%” }} />

);
};

export default DocumentViewer;

The viewer component is wrapped in a modal, which we then use like this for each page/section where we want to add ability to open pdf document
<DocumentViewerModal
show={state.showDocViewerModal}
onClose={() =>
setState({
showDocViewerModal: false,
})
}
file={state.file}
/>

Hi there,

Thank you for contacting pdf.js express forums,

While we do generally recommend that you use one instance and share that to load documents, for your case it looks like you need both to run at the same time. Since you are sharing the WebViewer instance between the 2 lists when you want them to run concurrently, could you please try loading one instance per viewer element with its own license key and see if that loads both instances at the same time?

Best regards,
Kevin Kim

Best regards,
Kevin Kim

@kkim I tried to use additional license so loaded viewer in list 1 with license #1 and viewer in list 2 with license #2 and it’s still the same issue. Any other solutions for this? We are really stuck.

Hi there,

Thank you for your response,

Please note that pdf.js express may not support multiple instances at the same time, see similar post here:

Best regards,
Kevin Kim

hi @kimm Thanks for fast response. So, are you saying that with the project setup my team has it’s definitely not possible to use pdfjs express viewer?
Does the paid version have the same limitation?

Hi there,

While it is possible to do so in localhost (without a license key requirement):

It looks like you had an issue with the auth api and thus the viewer is not instantiated. Could you please try with a second domain for the 2nd viewer and see if that resolves your issue?

You can find the details between the viewer and the plus version here:

Best regards,
Kevin Kim

thanks Kevin. I’m not sure if I’m following your suggestion.
If my current license key is for the domain where the viewer opens, are you saying to generate a license key for another domain that doesn’t match the domain where the viewer opens?

Since it is possible in localhost but the second license key’s auth api is rejected in a production environment, one possible way I can think of that may work is configuring you project such that you would have two different domains with 2 different licenses for each Viewer, and this may allow the call to the auth api. However this may not work and does not seem like a viable solution, as having both instances up at the same time is resource heavy.

I recommend you to only use one viewer at a time, but have an event that toggles between the two viewers.

Best regards,
Kevin Kim

sorry for late reply but just wanted to let you know that we got it to work. Followed your suggestion to use a single viewer and custom event to toggle it.
thanks!

hi @kkim We run into similar issue with the authentication api again.
We have another page in our app that lists some documents. Sometimes when you click to open a document the viewer throws “A license key is required to use the view only build of PDF.js Express” error. It’s rather random and not easy to reproduce but few times I was able to get it this way:

  1. Clear browser cache
  2. Go to the page, open one of the docs. Viewer throws the error
  3. Refresh the page and try again- viewer works with no error

or

  1. Clear browser cache
  2. Go to the page, open one of the docs. Viewer works with no error
  3. Open the page in another tab, open one of the docs. Viewer throws the error

Before the user can go to this page they have to log in, and they will land on the main page where we show the 2 lists (from the initial problem). We preload the viewer on the main page. Would this intefer with the viewer on another page? When I try the page in another tab, I go directly to that page though, without lading on the main page.

Hi there,

This seems like a tricky setup, do you have only one WebViewer instantiated on your application? If you still show the two lists, it sounds like you have 2 WebViewers being instantiated and this could be the problem.

Do you have a live sample url to showcase your sample or a minimal runnable sample project that can show on development environment?

Best regards,
Kevin Kim