How losing the same code snippet 50 times led me down a rabbit hole
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. Here's what I learned, the challenges I hit, and what I'd do differently.
The Problem (Or: Why I Got Frustrated)
The Daily Frustration
- Copy a code snippet on my laptop, switch to desktop, and it's gone
- Copy an email template, switch tabs, copy something else, and lose the template
- Scroll through 50 clipboard items to find the one I use daily
Why Existing Solutions Didn't Work for Me
I tried several tools:
- Built-in OS clipboard managers - Don't sync across devices
- Cloud clipboard tools - Too slow, clunky, or required too many steps
- Browser extensions - Saved everything but didn't prioritize what I actually used
Most extensions just saved history. I'd have to scroll through dozens of items to find the email signature I paste daily. That defeated the purpose.
What I Built
I built a browser extension that:
- 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 and Reddit
The key difference: it tracks what I actually paste, not what I click. Items I paste frequently automatically move to the top.
The Technical Challenges
Clipboard API Limitations
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 clipboard directly
- Permission handling varies by context
Solution: Message passing between content scripts and background service worker, with fallbacks.
Manifest V3 Gotchas
Service workers can be killed anytime:
// This state gets lost when the service worker dies
let clipboardHistory = [];
// Had to persist everything
chrome.storage.local.set({ clipboardHistory });
Challenges:
- Service worker lifecycle is unpredictable
- Content script injection timing issues
- CSP restrictions block some approaches
Solution: Persist state in chrome.storage.local and handle re-initialization.
Paste Functionality on Complex Sites
Pasting into Google Docs, Reddit, or Notion is tricky:
// Method 1: Modern approach (doesn't always work)
element.dispatchEvent(new ClipboardEvent('paste'));
// Method 2: Deprecated but sometimes the only option
document.execCommand('paste');
// Method 3: Direct DOM manipulation (works on simple sites)
element.textContent = clipboardText;
I ended up trying multiple methods in sequence:
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 Without Constant Polling
I wanted changes to appear instantly across devices without polling:
// Polling approach (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 (using Supabase in my case):
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 same item updated on multiple devices
- Managing subscription lifecycle
Cross-Browser Compatibility
Chrome, Firefox, and Edge have differences:
// Chrome uses chrome.*
chrome.storage.local.get('key', callback);
// Firefox uses browser.*
browser.storage.local.get('key').then(callback);
// Edge uses chrome.* but behaves slightly differently
Solution: 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);
}
},
// ... similar for set, remove, etc.
}
}
};
Smart Prioritization
I wanted frequently used items to surface automatically. This required:
- Tracking usage when items are actually pasted
- Syncing usage data across devices
- Efficient sorting and filtering
The implementation involves tracking paste events and maintaining usage statistics, but the core concept is prioritizing items based on actual usage patterns rather than just recency.
What I Learned
1. Test on Real Sites Early
Don't assume paste works everywhere. Test on Google Docs, Reddit, Notion, CodePen, etc.
2. Service Worker State is Ephemeral
Persist everything. Assume the service worker can die at any moment.
3. Real-Time Sync is Harder Than It Looks
Connection drops, conflicts, edge cases - it's more complex than it seems. Start simple and iterate.
4. User Behavior is Unpredictable
Track what users actually do, not what you think they do. I track pastes, not clicks.
5. Cross-Browser Testing is Essential
Chrome, Firefox, and Edge behave differently. Test all of them.
What I'd Do Differently
- Start with simpler MVP - Local-only first, then add sync
- Better conflict resolution - Should have planned this earlier
- More error handling - Add retry logic from the start
- Better testing - Should have built testing infrastructure earlier
- Get user feedback sooner - Built in isolation too long
Open Questions
I'm still figuring out:
- How do you handle clipboard permissions in extensions reliably?
- Better approaches for paste compatibility across complex sites?
- How would you architect real-time sync for this use case?
- Manifest V3 service worker lifecycle - 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.
The Result
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: https://www.linkedin.com/in/anu95
Top comments (0)