The Clipboard Problem That Drove Me to Build My Own Solution

Published: (January 13, 2026 at 10:54 AM EST)
5 min read
Source: Dev.to

Source: Dev.to

I lost my clipboard again. I’d copied a complex SQL query, switched to another tab, copied something else, and the query was gone. I had to rebuild it from memory.

This kept happening. As a remote worker constantly switching between my laptop and desktop, I’d copy something on one device, switch to the other, and it was gone. I tried a few clipboard managers, but they didn’t fit my workflow.

So I built my own. Below is what I learned, the challenges I hit, and what I’d do differently.

The Pain Points

  • Cross‑device loss – copy a code snippet on my laptop, switch to desktop, and it’s gone.
  • Accidental overwrite – copy an email template, switch tabs, copy something else, and lose the template.
  • Scrolling through history – need to scroll through 50 clipboard items to find the one I use daily.

Tools I Tried

ToolWhy It Fell Short
Built‑in OS clipboard managersNo sync across devices.
Cloud clipboard toolsToo slow, clunky, or required too many steps.
Browser extensionsSaved everything but didn’t prioritize what I actually used.

Most extensions just saved history. I had to scroll through dozens of items to find the email signature I paste daily. That defeated the purpose.

My Solution: A Custom Browser Extension

Features

  • Syncs clipboard history across Chrome and Edge browsers.
  • Learns what I paste most and prioritizes those items.
  • Provides a right‑click context menu for quick access.
  • Works on complex sites like Google Docs, Reddit, Notion, etc.

Key difference – it tracks what I actually paste, not just what I click. Items I paste frequently automatically move to the top.

Technical Deep‑Dive

The Clipboard API Has Quirks

// This works in some contexts, not others
navigator.clipboard.readText().then(text => {
  // But what if the page doesn't have focus?
  // What if it's a content script?
});

Issues

  • Requires HTTPS or localhost.
  • Content scripts can’t always access the clipboard directly.
  • Permission handling varies by context.

Solution – use message passing between content scripts and a background service worker, with fallbacks.

Service Worker Lifecycle

// This state gets lost when the service worker dies
let clipboardHistory = [];

// Had to persist everything
chrome.storage.local.set({ clipboardHistory });

Challenges

  • Service workers can be killed at any time.
  • Content‑script injection timing issues.
  • CSP restrictions block some approaches.

Solution – persist state in chrome.storage.local and handle re‑initialisation on start‑up.

Pasting Into Complex Sites

MethodDescriptionReliability
Modernelement.dispatchEvent(new ClipboardEvent('paste'))Works in some contexts, not all.
Deprecateddocument.execCommand('paste')Sometimes the only option.
Direct DOMelement.textContent = clipboardTextWorks on simple sites.

Combined approach

async function pasteText(element, text) {
  // Try modern approach first
  try {
    element.focus();
    await navigator.clipboard.writeText(text);
    element.dispatchEvent(new ClipboardEvent('paste'));
    return true;
  } catch (e) {
    // Fallback to execCommand
    try {
      element.focus();
      document.execCommand('insertText', false, text);
      return true;
    } catch (e2) {
      // Last resort: direct manipulation
      element.textContent = text;
      return true;
    }
  }
}

Real‑Time Sync vs. Polling

Polling (what I wanted to avoid)

setInterval(async () => {
  const latest = await fetchLatestClipboard();
  // Check for changes...
}, 5000); // Too slow, or too resource‑intensive

Solution: Real‑time subscriptions (Supabase example)

const subscription = supabase
  .channel('clipboard-changes')
  .on('postgres_changes', {
    event: 'INSERT',
    schema: 'public',
    table: 'clipboard_items'
  }, payload => {
    // Handle new item instantly
    updateLocalClipboard(payload.new);
  })
  .subscribe();

Challenges

  • Handling connection drops.
  • Resolving conflicts when the same item is updated on multiple devices.
  • Managing subscription lifecycle.

Cross‑Browser Compatibility

BrowserAPI Namespace
Chromechrome.*
Firefoxbrowser.*
Edgechrome.* (behaves slightly differently)

Abstraction layer

const browserAPI = {
  storage: {
    local: {
      get: key => {
        if (typeof chrome !== 'undefined' && chrome.storage) {
          return new Promise(resolve => {
            chrome.storage.local.get(key, resolve);
          });
        } else if (typeof browser !== 'undefined') {
          return browser.storage.local.get(key);
        }
      },
      set: items => {
        if (typeof chrome !== 'undefined' && chrome.storage) {
          return new Promise(resolve => {
            chrome.storage.local.set(items, resolve);
          });
        } else if (typeof browser !== 'undefined') {
          return browser.storage.local.set(items);
        }
      },
      // ...similar for remove, clear, etc.
    }
  }
};

Lessons Learned

  • Persist everything – assume the service worker can die at any moment.
  • Start simple – MVP with local‑only storage, then add sync.
  • Track real usage – monitor paste events, not just clicks.
  • Test on all target browsers – Chrome, Firefox, Edge behave differently.
  • Plan conflict resolution early – it becomes a major pain point later.
  • Add robust error handling from the start – retries, fallback logic, etc.
  • Build testing infrastructure early – unit + integration tests save time.
  • Get user feedback sooner – avoid building in isolation for too long.

Open Questions I’m Still Figuring Out

  1. Clipboard permissions – How do you handle them reliably in extensions across browsers?
  2. Paste compatibility – Better approaches for complex sites (Google Docs, Notion, CodePen, etc.)?
  3. Real‑time sync architecture – What’s the most robust way to sync clipboard data with minimal latency and conflict?
  4. Manifest V3 service worker lifecycle – Best practices for persisting state and handling restarts?

If you’ve tackled any of these, I’d love to hear your thoughts!

Best practices?

How do you test extensions across browsers efficiently?

If you’ve built something similar or have ideas, I’d love to hear them.

After a few months of using it, it’s working well. I rarely lose clipboard content, and frequently used items appear quickly. It’s not perfect, but it fits my workflow.

If you want to try it, it’s available for Chrome and Edge. More importantly, I’d love to hear:

  • How you’ve solved similar problems
  • What challenges you’ve faced with browser extensions
  • What features would make this genuinely useful

This is still a work in progress, and I’m learning as I go.

Author: Anurag G.
LinkedIn:

Back to Blog

Related posts

Read more »

Start your meetings at 5 minutes past

Article URL: https://philipotoole.com/start-your-meetings-at-5-minutes-past/ Comments URL: https://news.ycombinator.com/item?id=46560217 Points: 12 Comments: 8...