Intercepting Clipboard Events with JavaScript

Abstract image used to represent Intercepting Clipboard Events with JavaScript
Image by Victor Li.

The JavaScript copy event allows us to react to clipboard events within our web applications. Although still in a working draft state, support is pretty good across modern browsers.

Handling this event we are able to modify clipboard contents, but cannot read from the clipboard data (as this would otherwise be a security concern). What we can do however is use window.getSelection() to identify the highlighted items.

After defining handleClipboard as shown below, register it for the document's copy event:

document.addEventListener('copy', handleClipboard);

From there, we can modify what happens. If we really just wanted to stop people from being able to copy at all, we can just use event.preventDefault():

const handleClipboard = e => e.preventDefault();

My use for this is a little involved: I want to make sure that people can copy off my website, but I also want to make sure that they are aware that they are copying copyrighted work.

const handleClipboard = (e) => {
  const selectedText = window.getSelection();
  if (!selectedText || !e.clipboardData) return;

  const selection = selectedText.toString();
  if (!selection) return;

  const copyright = `Copyright (c) ${new Date().getFullYear()} John Kavanagh. All rights reserved.`;
  const source = `Original source: https://johnkavanagh.co.uk${window.location.pathname}`;
  const newClipboard = `${selection}\n\n${copyright}\n${source}`;

  e.clipboardData.setData('text/plain', newClipboard);
  e.preventDefault();
};

What this is doing is:

  1. Getting the selected text from the window object, as a string;
  2. Building a copyright notice (over two lines);
  3. Combining the selection and copyright notice together with line breaks;
  4. Placing this within the clipboard (in place of the original copy) via setData.

To leave code copies alone, add this guard at the start of handleClipboard, before writing clipboard data. It checks the event path and the elements' ancestors, so a syntaxhighlighting span inside code or pre is covered too:

const isCode = e.composedPath().some((node) =>
  node instanceof Element && node.closest('pre, code') !== null
);

if (isCode) {
  return;
}

I also modify this a little further so that I can avoid intercepting very short copies (e.g., where somebody is copying my email address), and to generate a store of what has been copied off the site to try and head off potential duplicate content issues. You can probably work those bits out for yourself, though!


Permissions and User Expectation

Clipboard behaviour is more sensitive than ordinary click handling because it touches something the user is deliberately taking away from the page. If you intercept a copy event, keep the change predictable and visible. Quietly adding tracking text, changing the copied content or blocking copy altogether usually creates more distrust than value.

The modern Clipboard API also has permission and security constraints, especially for reading from the clipboard. Writing during an explicit copy action is one thing; reading clipboard contents without a clear user action is treated much more carefully by browsers.


Prefer Explicit Controls

For code snippets, share text or generated references, a visible "copy" button is often better than intercepting every copy event on the page. It gives the user a clear target and keeps the behaviour scoped to the content that actually needs it.

Postscript

September 2026: The retained sample below was captured in 2021. The handler uses new Date().getFullYear(), so running it in another year produces that year instead.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum fringilla arcu.

Copyright (c) 2021 John Kavanagh. All rights reserved. 
Original source: https://johnkavanagh.co.uk/page-visited/

Need a senior engineer involved?

I can work directly in the codebase, review the architecture, or support the team through delivery when the work needs more than extra hands.