Skip to content

Track Copy & Paste

Tracking text copies tells you which content is compelling enough that users want to take it with them. On documentation sites, it shows which code snippets get used. On news sites, it shows which quotes get shared. On pricing pages, it can indicate research behavior.

dataLayer.push() text_copy

Fires when a user copies text from the page. Identifies the section and a preview of the copied text.

(function() {
document.addEventListener('copy', function(event) {
var selection = window.getSelection();
if (!selection || selection.toString().trim().length === 0) return;
var copiedText = selection.toString().trim();
// Identify which section the copy happened in
var sectionEl = null;
var anchorNode = selection.anchorNode;
var el = anchorNode.nodeType === Node.TEXT_NODE
? anchorNode.parentElement
: anchorNode;
// Walk up to find a section, article, or heading
while (el && el !== document.body) {
if (el.dataset.trackSection || el.tagName === 'SECTION' || el.tagName === 'ARTICLE') {
sectionEl = el;
break;
}
el = el.parentElement;
}
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'text_copy',
copy_text_preview: copiedText.substring(0, 100),
copy_text_length: copiedText.length,
copy_section: sectionEl
? (sectionEl.dataset.trackSection || sectionEl.id || sectionEl.tagName.toLowerCase())
: 'unknown',
page_path: window.location.pathname,
page_title: document.title
});
});
})();
  1. Add the code as a Custom HTML tag in GTM

    • Trigger: DOM Ready (All Pages, or limit with Page Path condition)
  2. Create a Custom Event Trigger

    • Trigger type: Custom Event
    • Event name: text_copy
  3. Create Data Layer Variables

    • DLV - copy_text_previewcopy_text_preview
    • DLV - copy_text_lengthcopy_text_length
    • DLV - copy_sectioncopy_section
  4. Create a GA4 Event Tag

    • Tag type: Google Analytics: GA4 Event
    • Event name: text_copy
    • Parameters:
      • copy_text_preview{{DLV - copy_text_preview}}
      • copy_text_length{{DLV - copy_text_length}}
      • copy_section{{DLV - copy_section}}
      • page_path{{Page Path}}
    • Trigger: the Custom Event trigger
  5. Add section attributes to your HTML for better section identification:

    <section data-track-section="introduction">
    <h2>Introduction</h2>
    <p>Content here...</p>
    </section>
    <section data-track-section="pricing-table">
    ...
    </section>
  6. Test in Preview Mode

    Select some text on the page and press Ctrl+C (or Cmd+C). A text_copy event should appear in the Summary pane.

Tag Configuration

GA4 - text_copy

Type
Google Analytics: GA4 Event
Trigger
Custom Event - text_copy
Variables
DLV - copy_text_previewDLV - copy_text_lengthDLV - copy_section

Do not send the full copied text to GA4. Always truncate or hash it:

  • Truncate to 100 characters: good for previewing what was copied without capturing full PII
  • Send length only: if the text might contain PII, send only copy_text_length — no content
  • Filter by page type: only track copies on clearly non-PII pages like documentation or pricing
// Extra-safe version: only track copies on documentation pages
if (!window.location.pathname.startsWith('/docs/')) return;
window.dataLayer.push({
event: 'text_copy',
copy_text_length: copiedText.length,
copy_section: sectionId,
is_code_block: copiedText.match(/\{|\}|=>|function/) ? true : false
});

On documentation sites, knowing which code blocks users copy is particularly valuable:

document.addEventListener('copy', function(event) {
var selection = window.getSelection();
var anchor = selection.anchorNode;
var el = anchor.nodeType === Node.TEXT_NODE ? anchor.parentElement : anchor;
var inCodeBlock = false;
var codeId = null;
while (el && el !== document.body) {
if (el.tagName === 'CODE' || el.tagName === 'PRE') {
inCodeBlock = true;
codeId = el.id || el.dataset.codeId || null;
break;
}
el = el.parentElement;
}
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'text_copy',
copy_type: inCodeBlock ? 'code' : 'text',
code_block_id: codeId || undefined,
copy_text_length: selection.toString().length
});
});
  1. Open GTM Preview, visit a page with content
  2. Select a sentence and press Ctrl+C (or Cmd+C on Mac)
  3. Verify text_copy event fires in the Summary pane
  4. Check copy_section matches the expected section
  5. Verify copy_text_preview shows a truncated version, not the full text

copy event fires on programmatic copies too. If your page uses document.execCommand('copy') or the Clipboard API to copy text programmatically (e.g., a “Copy to clipboard” button), this handler will also fire. Check the event’s isTrusted property to distinguish user-initiated copies: if (!event.isTrusted) return;

Selection can be empty. Right-clicking without a selection, or keyboard shortcuts for other operations, can fire the copy event with no text selected. The selection.toString().trim().length === 0 guard handles this.