Capabilities · API
Async Clipboard API: reading and writing the clipboard
Published
In one line: The Async Clipboard API — navigator.clipboard — lets you read from
and write to the system clipboard programmatically. Writing plain text requires no
permission; reads are tightly gated: Chromium may use the clipboard-read permission,
while Firefox and Safari require transient activation and the browser’s own paste prompt
(no persistent grant is stored). All operations require a secure context (HTTPS or localhost).
Writing to the clipboard
Section titled “Writing to the clipboard”Plain text (most common)
Section titled “Plain text (most common)”try { await navigator.clipboard.writeText('Hello, clipboard!');} catch (err) { console.error('Clipboard write failed:', err);}writeText requires:
- A secure context (HTTPS or
localhost). - Either a user activation or that the page has focus (the exact rule is browser-dependent, but calling from a click handler is always safe).
Rich content (images, HTML)
Section titled “Rich content (images, HTML)”const blob = new Blob(['<b>hello</b>'], { type: 'text/html' });const item = new ClipboardItem({ 'text/html': blob });await navigator.clipboard.write([item]);write() accepts an array of ClipboardItem objects. Each item can carry multiple
MIME types so the paste target can pick the richest format it understands.
Reading from the clipboard
Section titled “Reading from the clipboard”Plain text
Section titled “Plain text”const text = await navigator.clipboard.readText();Rich content
Section titled “Rich content”const items = await navigator.clipboard.read();for (const item of items) { for (const type of item.types) { const blob = await item.getType(type); // process blob }}Permission model
Section titled “Permission model”Permission behavior differs significantly by browser family.
Chromium (Chrome, Edge, Opera)
Section titled “Chromium (Chrome, Edge, Opera)”Chromium uses the clipboard-read and clipboard-write Permissions API names:
- Writing (
writeText/write): no permission prompt forwriteTextwhen called from a focused, user-activated context.write()with certain MIME types (e.g., images) may prompt forclipboard-write. - Reading (
readText/read): requires theclipboard-readpermission; a browser prompt is shown the first time. You can query the current state without triggering a prompt:
// Chromium only — clipboard-read is not a recognised name in Firefox or Safariconst { state } = await navigator.permissions.query({ name: 'clipboard-read' });// state: 'granted' | 'denied' | 'prompt'Firefox
Section titled “Firefox”Firefox does not recognise clipboard-read or clipboard-write as Permissions API
names — navigator.permissions.query({ name: 'clipboard-read' }) will reject or return
a nonsense state. Instead:
- Writing: requires transient activation (a user gesture such as a click).
- Reading: requires transient activation and triggers a one-time browser paste confirmation dialog the user must accept; there is no persistent grant.
Safari
Section titled “Safari”Safari also does not expose clipboard-read/clipboard-write to the Permissions
API. Its model is similar to Firefox:
- Writing: requires transient activation.
- Reading: requires transient activation and a user-initiated paste prompt; no persistent permission is stored.
Secure context (HTTPS)
Section titled “Secure context (HTTPS)”User-gesture and focus requirement
Section titled “User-gesture and focus requirement”Both read and write operations should be called from within a user-gesture handler or
while the document has focus. Browsers differ slightly, but calling from a click
handler is always safe. Attempting to call outside a user-activated context typically
results in a NotAllowedError.
Fallback: document.execCommand
Section titled “Fallback: document.execCommand”The legacy document.execCommand('copy') and document.execCommand('paste') work in
older browsers but are deprecated and do not support rich content. Use them only as a
last resort:
function legacyCopy(text) { const textarea = document.createElement('textarea'); textarea.value = text; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); textarea.remove();}Decision framework
Section titled “Decision framework”| Decision question | Recommended action | Rationale |
|---|---|---|
| Copy plain text on button click? | navigator.clipboard.writeText() inside a click handler. |
No permission prompt; works in all modern browsers with HTTPS. |
| Copy an image or HTML to clipboard? | navigator.clipboard.write([new ClipboardItem(...)]). |
Allows multi-format payloads; the paste target picks the best type. |
| Read clipboard contents? | Always call from a user-gesture handler. In Chromium you can query clipboard-read permission first; in Firefox and Safari rely on transient activation and the browser’s own paste prompt — do not use navigator.permissions.query for this. |
Permission model is browser-family-specific; transient activation is the portable baseline. |
| Need to support older browsers? | Feature-detect navigator.clipboard; fall back to execCommand. |
execCommand is deprecated but still works in older engines. |
| Clipboard in a Service Worker or background context? | Not possible — clipboard access requires a focused document. | By spec and browser policy, clipboard is not available in background contexts. |
Practical checklist
Section titled “Practical checklist”- Serve the page over HTTPS —
navigator.clipboardis undefined on plain HTTP. - Call clipboard methods from user-gesture handlers or while the document has focus.
- Use
writeTextfor plain text; usewritewithClipboardItemfor rich content. - Always call read methods from a user-gesture handler. In Chromium, optionally query the
clipboard-readpermission state first; in Firefox and Safari, depend on transient activation and the browser’s paste prompt —navigator.permissions.query({ name: 'clipboard-read' })is not portable across browser families. - Catch errors from all clipboard calls — permissions can be denied or revoked.
- Provide a
document.execCommandfallback for browsers that do not support the Async Clipboard API.
Specifications
| Specification | Status |
|---|---|
| Async Clipboard API | W3C draft |
- Legend
- Yes
- Partial
- Flag
- No
- Unknown
| Browser / Platform | Support | Versions | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Desktop) | Yes | 76 | high | source | 1 |
| Chrome (Android) | Yes | 76 | high | source | 23 |
| Edge (Desktop) | Yes | 79 | high | source | 45 |
| Firefox (Desktop) | Yes | 127 | high | source | 678 |
| Firefox (Android) | Yes | 127 | high | source | 9101112 |
| Safari (macOS) | Yes | 13.1 | high | source | — |
| Safari (iOS) | Yes | 13.4 | high | source | 13 |
| Samsung Internet | Yes | 12.0 | high | source | 1415 |
| WebView (Android) | Yes | 76 | high | source | 1617 |
- The user must grant the `clipboard-read` permission.
- The user must grant the `clipboard-read` permission.
- Derived by browser-compat-data mirroring from Chrome.
- The user must grant the `clipboard-read` permission.
- Derived by browser-compat-data mirroring from Chrome.
- This method must be called within user gesture event handlers.
- A paste prompt is displayed when the clipboard is read. If the clipboard contains same-origin content, the prompt is suppressed.
- Web extensions with the `clipboardRead` permission in their manifest can read data without the paste prompt displaying. Prior to Firefox 147, extensions without this permission were unable to read clipboard data.
- This method must be called within user gesture event handlers.
- A paste prompt is displayed when the clipboard is read. If the clipboard contains same-origin content, the prompt is suppressed.
- Web extensions with the `clipboardRead` permission in their manifest can read data without the paste prompt displaying. Prior to Firefox 147, extensions without this permission were unable to read clipboard data.
- Derived by browser-compat-data mirroring from Firefox.
- Derived by browser-compat-data mirroring from Safari.
- The user must grant the `clipboard-read` permission.
- Derived by browser-compat-data mirroring from Chrome Android.
- The user must grant the `clipboard-read` permission.
- Derived by browser-compat-data mirroring from Chrome Android.