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
- 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.
- Serve the admin over HTTPS or localhost (both are secure contexts) so navigator.clipboard is available.
- 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
- Feature-detect navigator.clipboard.write + ClipboardItem before offering a 'copy to clipboard' button.
- Serve the admin over a secure context (HTTPS or localhost) — the async Clipboard API is unavailable otherwise.
- Always provide the download fallback UX so users on unsupported browsers still get the screenshot.
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.