Clipboard API Focus Issue

Created on: September 28, 2024

Answered using OpenAI 01 Preview by OpenAI01

Question

async function simulateClipboardPaste(page, message, x, y) {
// const originalClipboardContent = await page.evaluate(() => navigator.clipboard.readText());

await page.mouse.click(x, y); // Click on input area
await page.evaluate(text => navigator.clipboard.writeText(text), message);
await page.keyboard.down('Control');
await page.keyboard.press('v');
await page.keyboard.up('Control');

// await page.evaluate(text => navigator.clipboard.writeText(text), originalClipboardContent);
}

---
when i uncomment the commented lines i get this error:
[2024-09-28T09:35:50.372Z] [INFO] Sending prompt: hi [Structure: direct]
[2024-09-28T09:35:50.379Z] [ERROR] Error sending prompt: Evaluation failed: DOME
xception: Document is not focused.

Thought

Simulating clipboard paste

The simulateClipboardPaste function clicks on an input spot, writes text to the clipboard, uses Ctrl+v to paste, and tries to restore the original clipboard content.

Unraveling the error

I'm trying to determine why uncommenting lines to save and revert clipboard content causes a "DOMException: Document is not focused" error.

Focusing on clipboard access

I’m digging into the issue of accessing the clipboard in Puppeteer. The error "DOMException: Document is not focused" happens because the Clipboard API needs the document to be focused and secure (HTTPS).

Ensuring focus

I’m figuring out how to ensure the page or a specific element has focus after interacting with it, which might not always be the case.

Accessing clipboard permissions

I’m exploring clipboard permissions in Puppeteer, suggesting the CDP method. It’s interesting to consider if focusing the document or an element aids in clipboard interactions.

Using CDP to manage clipboard

I’m exploring how to use the CDP's Input.setClipboardText method in Puppeteer to manage clipboard content, suggesting this approach might avoid errors caused by focusing issues.

Examining clipboard access

OK, I'm looking at using the chrome-devtools-protocol (CDP) to read clipboard content. Trouble is, 'Browser.getClipboard' doesn't seem to exist in CDP.

Implementing solutions

I'm thinking through fixing the clipboard access error. The document needs to be focused first. Alternatively, direct clipboard content through CDP or simulate pasting via keyboard.

Addressing clipboard access

The error "DOMException: Document is not focused." happens because the Clipboard API demands the document to be active. To rectify this, ensure the window is focused before accessing the clipboard with await page.evaluate(() => window.focus()); or page.bringToFront().

Enhancing clipboard simulation

I modified the code to use CDP for clipboard manipulation, improving reliability and avoiding DOMException. The new method bypasses page context manipulation.

Answer

The error you're encountering—DOMException: Document is not focused.—occurs because the Clipboard API (navigator.clipboard) requires the document to be focused to read from or write to the clipboard. In your Puppeteer script, when you uncomment the lines that read and restore the clipboard content, the document isn't focused at the time of execution, leading to the exception.

Why the Error Occurs

  • Clipboard API Requirements: The Clipboard API is only accessible when the document is focused and active. This is a security measure to prevent unauthorized access to the user's clipboard.
  • Puppeteer Context: When you use page.evaluate(), the function runs in the context of the page, but Puppeteer may not automatically focus the page or the document before executing the function.

Solutions

Option 1: Ensure the Document is Focused

Before accessing the clipboard, make sure the document is focused. You can achieve this by focusing the window within the page.evaluate() function.

async function simulateClipboardPaste(page, message, x, y) { await page.mouse.click(x, y); // Click on input area // Focus the window and write to the clipboard await page.evaluate(async (text) => { window.focus(); await navigator.clipboard.writeText(text); }, message); await page.keyboard.down('Control'); await page.keyboard.press('v'); await page.keyboard.up('Control'); // Optionally read and restore the original clipboard content const originalClipboardContent = await page.evaluate(async () => { window.focus(); return await navigator.clipboard.readText(); }); // ... your code ... await page.evaluate(async (text) => { window.focus(); await navigator.clipboard.writeText(text); }, originalClipboardContent); }

Option 2: Use page.bringToFront()

Puppeteer's page.bringToFront() brings the page to the front and focuses it, which can also solve the issue.

async function simulateClipboardPaste(page, message, x, y) { await page.bringToFront(); // Focus the page await page.mouse.click(x, y); // Click on input area // Access the clipboard const originalClipboardContent = await page.evaluate(async () => { return await navigator.clipboard.readText(); }); await page.evaluate(async (text) => { await navigator.clipboard.writeText(text); }, message); await page.keyboard.down('Control'); await page.keyboard.press('v'); await page.keyboard.up('Control'); // Restore the original clipboard content await page.evaluate(async (text) => { await navigator.clipboard.writeText(text); }, originalClipboardContent); }

Option 3: Use Chrome DevTools Protocol (CDP) to Set Clipboard Content

Manipulating the clipboard via the CDP can bypass the focus issue and is more reliable in automated scripts.

async function simulateClipboardPaste(page, message, x, y) { // Create a CDP session const client = await page.target().createCDPSession(); // Set the clipboard content await client.send('Browser.grantPermissions', { origin: page.url(), permissions: ['clipboardReadWrite', 'clipboardSanitizedWrite'], }); await client.send('Clipboard.setClipboardData', { data: message, label: 'plainText', }); await page.mouse.click(x, y); // Click on input area await page.keyboard.down('Control'); await page.keyboard.press('v'); await page.keyboard.up('Control'); // Optionally, clear the clipboard or restore original content }

Note: The Clipboard.setClipboardData method might not be available in all versions of Puppeteer or Chrome. Make sure your environment supports it.

Recommendation

For automated testing and scripting, Option 3 is generally more robust because it doesn't rely on the page's focus state and leverages the browser's debugging protocol directly.

Additional Tips

  • Permissions: Ensure that the page has the necessary permissions to access the clipboard. You can use page.browserContext().overridePermissions() to grant permissions.
  • Security Considerations: Accessing the clipboard can have security implications. Always ensure you're complying with best practices and only accessing the clipboard when necessary.

Summary

The error is due to the Clipboard API's requirement for the document to be focused. By ensuring the document is focused or by using the CDP to manipulate the clipboard, you can resolve the error and successfully read from and write to the clipboard in your Puppeteer script.

Share this Q&A