WebViewer copy functionality is being blocked by Clipboard API

WebViewer Version
8.11.0

Do you have an issue with a specific file(s)?
No

Can you reproduce using one of our samples or online demos?
No

Are you using the WebViewer server?
No

Does the issue only happen on certain browsers?
Yes, Chrome Version 113.0.5672.92 (Official Build) (arm64)

Is your issue related to a front-end framework?
No

Is your issue related to annotations?
No

Please give a brief summary of your issue
When highlighting text in a PDF displayed in WebViewer, the text is not copied to the clipboard and the following error is shown in the console.

DOMException: The Clipboard API has been blocked because of a permissions policy applied to the current document.

Please describe your issue and provide steps to reproduce it
I’m initializing the WebViewer like this.

const viewer = await WebViewer(
  {
    disabledElements: [
      'progressModal',
      'themeChangeButton',
      'toggleNotesButton',
    ],
    licenseKey: '<redacted>',
    isReadOnly: true,
    path: Utils.requireFromCDN('webviewer'),
    preloadWorker: 'pdf',
  },
  element
)

After that, in the UI, I highlight a portion of text in the PDF and click the Copy icon that shows below my highlighted text. The text is not copied to clipboard.

I also tried programmatically adding the allow attribute to the iframe rendered by WebViewer to set the Permissions Policy, but that didn’t work.

cont initializeWebViewer = async (element) => {
  const iframes = element.getElementsByTagName('iframe')  
  const viewer = await WebViewer({ ... },  element)
  iframes[0]?.setAttribute('allow', 'clipboard-read; clipboard-write')
}

I’ve looked through the WebViewer API documentation for a property that allows copy but could not find one. Is there a property in the config passed upon WebViewer initialization so that the copy functionality works?

Please provide a link to a minimal sample where the issue is reproducible:
Cannot repro

1 Like

Hi Brandonitga
Thanks for contacting us for support.
Is it the Webviewer wrapped in your iframe?
Is it possible you could provide us a small sample to reproduce your issue?

Best
Jack

1 Like

I’m not sure I understand your question. Instantiating a new WebViewer creates an iframe programmatically, I’m not creating the iframe.

Hi Brandonitga
It is hard to reproduce your issue on my end.
Can I know more detail about it? It would be better you could provide us a sample so that I can deep dive on your issue.

Best
Jack

I’m not able to reproduce it in codesandbox, but I have more info for you…

Our domain is xxx.example.com, however the assets for WebViewer are served from our CDN at cdn.example.com. This includes webviewer-core, webviewer-ui and all other dependent files - making the iframes src="cdn.example.com/..."

I believe this is the cause of the issue. Is there a property (or other way) for WebViewer to add the correct allow attribute to the iframe, specifying the domain in the properties value? I’ll update my code to programmatically add the domain and see if that works.

Here are some resources discussing the problem and solution in more detail.

Just an update…

Programmatically setting the allow property on the iframe created by WebViewer is not working.

iframes[0]?.setAttribute('allow', 'clipboard-write *')

I tried different mutations of defined origins, finally settled on * and it still doesn’t work. Perhaps programmatically setting the Permissions Policy on an iframe is not respected.

Hi Brandonitga
You are using the different domain to load the library. In this case, you should check out this guide.
Please let me know if it works or not for you.

Best,
Jack

Could you give me an example of how we’d use the postMessage API to know when a user has used the copy functionality from WebViewer?

Also, is there an event we can listen to on the DocumentViewer class or any other class as a third option?

Hello,

This is most likely an issue in your application that is blocking the clipboard API. Please look through this guide: Unblocking clipboard access

Best regards,
Tyler

Hi Tyler,

As I stated in my original post and a follow-on post, I’ve tried programmatically adding the allow attribute in different mutations without any luck - please read my posts. Before posting here, I read the article you’re referencing and the MDN Permissions Policy page it links to.

I’m asking for either an example of how I’d use the PostMessage API to send/receive when text is copied to the clipboard within the WebViewer iframe, or if there’s a WebViewer event I can listen to when text is copied from the displayed PDF.

Hello brandonitga,

Its a pretty simple addEventListener and then accessing the clipboard:

instance.UI.iframeWindow.addEventListener("copy",async (event) => {
        console.log(await navigator.clipboard.readText())
      });

Best regards,
Tyler

Was this ever marked as resolved? I am having a similar issue. We’ve got an angular app with an iframe to a second angular app which then contains WebViewer. We’ve also tried using the WebComponent.

So basically we’ve got

<iframe title="App1" allow="clipboard-write">
    <iframe title="WebViewer" ...>

or with WC

<iframe title="App1" allow="clipboard-write">
    <apryse-webviewer ...>

But Clipboard is getting blocked within the WebViewer iframe or WC when copying from the document. The webviewer path is within the 2nd app’s domain:

path: './pdftron-source',

I’m trying to avoid writing some custom copy logic because I really do just want the user to be able to copy anything out that they can select. Is my only choice to listen for the event and use navigator to write the selected text to clipboard?

Hello gsmammarella,

Can you try adding:

allow="clipboard-read; clipboard-write"

to both iframes?

Best regards,
Tyler

Certainly can try. To clarify, how do you recommend modifying the internal WebViewer iframe? With a config like…?

instance.UI.addEventListener(instance.UI.Events.VIEWER_LOADED, () => {
  const iframe = instance.UI.iframeWindow;
  iframe?.setAttribute('allow', 'clipboard-read; clipboard-write');
});

Ok, I figured out our issue. Some mixed information online misled us, but the primary issue is that we had set the allow attribute on our top level iframe with the angular hook [attr.allow]. This seems to set the value too late for the browser to catch the policy, and so the direct attribute allow must be used. From there, simply setting the clipboard permissions on the top level iframe worked.

Tyler, if you still have time, I would love to get some updated information about the config.js regardless. My code above did not work as the iframeWindow was undefined at the time of the load event, which seems incorrect…