TryGhost/Ghost · error · Error

Clipboard API not supported in this browser

Error message

Clipboard API not supported in this browser

What it means

Thrown by captureScreenshot() when copyToClipboard:true is requested but the browser lacks the async Clipboard API (navigator.clipboard.write or the global ClipboardItem constructor). html2canvas has already succeeded and produced a PNG blob; only the clipboard-write step fails because the capability is absent. It reports a browser-capability gap, not a runtime defect.

Source

Thrown at apps/activitypub/src/utils/screenshot.ts:62

            allowTaint: true,
            imageTimeout: 0,
            onclone: (_document, clonedElement) => fixFirefoxTextSpacing(clonedElement)
        });

        await new Promise<void>((resolve, reject) => {
            canvas.toBlob(async (blob) => {
                if (!blob) {
                    reject(new Error('Failed to create blob from canvas'));
                    return;
                }

                try {
                    if (copyToClipboard) {
                        if (navigator.clipboard && 'write' in navigator.clipboard && typeof ClipboardItem !== 'undefined') {
                            const clipboardItem = new ClipboardItem({'image/png': blob});
                            await navigator.clipboard.write([clipboardItem]);
                        } else {
                            throw new Error('Clipboard API not supported in this browser');
                        }
                    } else {
                        const url = URL.createObjectURL(blob);
                        const link = document.createElement('a');
                        link.href = url;
                        link.download = filename;

                        document.body.appendChild(link);
                        link.click();

                        document.body.removeChild(link);
                        URL.revokeObjectURL(url);
                    }

                    resolve();
                } catch (error) {
                    reject(error);
                }

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Feature-detect before calling: if (!(navigator.clipboard && 'write' in navigator.clipboard && typeof ClipboardItem !== 'undefined')), pass copyToClipboard:false so the function uses its download path instead.
  2. Serve the admin over HTTPS or localhost (both are secure contexts) so navigator.clipboard is available.
  3. Wrap the call in try/catch and, on failure, retry with copyToClipboard:false to deliver the screenshot as a file download.

Example fix

// before
await captureScreenshot({copyToClipboard: true});

// after
const canCopy = !!(navigator.clipboard && 'write' in navigator.clipboard && typeof ClipboardItem !== 'undefined');
try {
    await captureScreenshot({copyToClipboard: canCopy});
} catch (e) {
    // clipboard unsupported — fall back to download
    await captureScreenshot({copyToClipboard: false});
}
Defensive patterns

Strategy: validation

Validate before calling

// Run before calling captureScreenshot({copyToClipboard: true})
export function canCopyScreenshotToClipboard(): boolean {
    return typeof navigator !== 'undefined'
        && !!navigator.clipboard
        && 'write' in navigator.clipboard
        && typeof ClipboardItem !== 'undefined';
}
// usage: captureScreenshot({copyToClipboard: canCopyScreenshotToClipboard()})

Try / catch

import {captureScreenshot} from '../utils/screenshot';
try {
    await captureScreenshot({copyToClipboard: true});
} catch (e) {
    // capability missing — fall back to a plain file download
    if (e instanceof Error && e.message.includes('Clipboard API not supported')) {
        await captureScreenshot({copyToClipboard: false});
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling captureScreenshot({copyToClipboard:true}) where navigator.clipboard is undefined (insecure context / plain HTTP, since the async Clipboard API requires a secure context), or where ClipboardItem is undefined (legacy browsers). Also fires when an extension or incognito mode blocks clipboard writes.

Common situations: Staging served over http:// (not HTTPS) where the secure-context clipboard API is unavailable; corporate-locked browsers that disable clipboard access; testing in an older Safari/Edge build that predates ClipboardItem; headless test runners without clipboard emulation.

Related errors


AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13). Data as JSON: /api/errors/008c34b7fd65be59. Report an issue: GitHub.