Skip to main content

Building DebugClip

ReactTypeScriptViteTailwind CSSChrome ExtensionManifest V3Cloudflare WorkersNext.js

The Problem​

You're debugging a React app. Something broke in production β€” a user reported a white screen.

You open DevTools. You find a red wall of console errors. You copy the first one. You switch to ChatGPT. You paste it. You realize you forgot the stack trace. Back to DevTools. Copy again. Paste again. Now the AI asks for the network request that failed. Back to the Network tab. Find the request. Copy the URL, the status code, the response body. Paste. The AI gives you a generic answer because it's missing the request headers. Back to DevTools. Copy headers. Paste.

Five minutes gone. And you still haven't started fixing the bug.

This is the workflow for every single front-end bug:

  1. Copy β€” hunt through DevTools tabs, selecting error messages, stack traces, network details
  2. Switch β€” alt-tab to your AI tool of choice, losing context with every window change
  3. Paste β€” dump fragments of information that are already incomplete and decontextualized
  4. Repeat β€” answer follow-up questions by going back to DevTools for more data you should have sent in the first place

Multiply that by the 10, 20, 50 bugs you encounter in a week. That's hours lost to clipboard gymnastics.

The real cost isn't just time β€” it's the context loss. By the time you've assembled all the pieces manually, you've lost your train of thought. The AI gets incomplete data, gives incomplete answers, and you start the cycle over.

❌ Before β€” Manual workflow

~5 minutes per bug. Copy-paste fragments across tabs, lose context, get generic AI answers, repeat.

βœ“ After β€” DebugClip

~10 seconds per bug. One click captures everything, formats it into a structured prompt, and delivers it directly to the AI.

I built DebugClip because I was tired of being a human clipboard between DevTools and ChatGPT.


The Solution​

DebugClip is a browser extension that captures front-end errors automatically and sends structured debug context to AI β€” in one click.

Instead of manually hunting through DevTools tabs, DebugClip watches everything in the background. When something breaks, it's already captured β€” with full context, properly formatted, ready to be analyzed by an AI of your choice.

What It Captures​

DebugClip monitors four categories of front-end failures:

πŸ”΄ Console Errors

console.error(), console.warn(), uncaught TypeError/ReferenceError, and unhandled Promise rejections.

🌐 Network Failures

Failed fetch() calls (4xx, 5xx), network timeouts, DNS failures, CORS blocks, and XHR errors.

πŸ“¦ Resource Loading Failures

Broken images, missing stylesheets, and failed script loads (404, DNS resolution failures).

πŸ”’ Security Violations

CSP violations, mixed content warnings, and deprecated API notices that silently break functionality.

Every captured error includes timestamps, stack traces, request/response headers, and body payloads β€” the complete picture that AI needs to actually diagnose the problem, not just guess at it.

One Click to AI​

Here's where DebugClip eliminates the clipboard workflow entirely. Once errors are captured, you hit one button and the extension:

  1. Formats everything into a structured Markdown prompt β€” token-optimized so the AI gets maximum context without wasted tokens
  2. Opens your AI provider of choice
  3. Auto-injects the formatted debug context directly into the AI's input field β€” no paste required

DebugClip supports seven AI providers out of the box:

Claude Β· ChatGPT Β· Gemini Β· DeepSeek Β· Copilot Β· Mistral Β· Groq

No lock-in. Use whichever AI gives you the best answers for your specific problem. Switch between them freely β€” the structured prompt format works with all of them.

The result: what used to take 5 minutes of manual copy-paste-switch-repeat now takes 10 seconds. Click capture, click send, get an answer that actually helps because the AI has the full picture from the start.


Architecture​

Building a browser extension that captures errors sounds straightforward β€” until you realize that no single browser API covers every scenario. Some pages lock down their environment with Content Security Policy. Some errors only surface at the network level. And the browser itself can kill your background process at any moment.

Here's how the pieces fit together:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Service Worker (MV3) β”‚
β”‚ orchestrates all messaging β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ chrome.scripting β”‚ β”‚ β”‚ chrome.debugger β”‚ β”‚
β”‚ β”‚ (main-world inject) β”‚ β”‚ β”‚ (CDP attach) β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β€’ patches console β”‚ β”‚ β”‚ β€’ Network.* events β”‚ β”‚
β”‚ β”‚ β€’ wraps fetch/XHR β”‚ β”‚ β”‚ β€’ Runtime.* events β”‚ β”‚
β”‚ β”‚ β€’ error event listenβ”‚ β”‚ β”‚ β€’ full headers/bodyβ”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β–Ό β”‚ β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Shared Error Store β”‚ β”‚
β”‚ β”‚ (in-memory, per tab session) β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ Duplicate Detection (URL + message + timestamp) β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ prevents redundant entries from both paths β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ LLM Injection (Content Scripts) β”‚ β”‚
β”‚ β”‚ injected into AI sites β†’ handles React inputs & β”‚ β”‚
β”‚ β”‚ ProseMirror editors β†’ delivers formatted prompt β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The Dual-Capture Strategy​

DebugClip uses two complementary capture methods to cover the full spectrum of front-end errors:

Approach 1: Main-World Script Injection β€” via chrome.scripting with world: "MAIN", DebugClip injects a script directly into the page's execution context. This script patches console.error, wraps fetch and XHR, and listens for error and unhandledrejection events. It works silently on most sites without any user-visible indicator.

Approach 2: Chrome DevTools Protocol β€” via the chrome.debugger API, DebugClip attaches to a tab and subscribes to Network.* and Runtime.* CDP events. This captures everything β€” including requests blocked by CSP or errors the page intentionally suppresses. The tradeoff: Chrome shows a "debugger attached" banner, so this mode is opt-in for users who want maximum coverage.

Both capture paths feed into the same shared error store. Since both methods can catch the same error (a failed fetch triggers both the XHR wrapper and a CDP Network.loadingFailed event), a duplicate detection layer compares entries by URL, message content, and timestamp proximity to prevent redundant entries. The result: users get complete coverage without seeing the same error twice.

Service Worker Constraints (Manifest V3)​

Chrome extensions running on Manifest V3 have no persistent background page. The Service Worker wakes on events and dies when idle β€” typically after 30 seconds of inactivity. This creates a fundamental constraint: you cannot rely on long-lived in-memory state.

DebugClip handles this by splitting data into two categories:

  • Transient data (captured errors for the current session) β€” held in memory while the Service Worker is alive. If it dies mid-session, active tab connections re-send their state on reconnect.
  • Persistent data (user settings, license status, session history) β€” written to chrome.storage.local immediately on change. The Service Worker reads it back on wake.

All message handling uses the return true pattern in onMessage listeners to keep the message channel open for async responses β€” without this, the Service Worker would close the port before the response arrives.

LLM Injection Mechanism​

The "one-click send to AI" feature works through content scripts injected into AI provider sites (Claude, ChatGPT, Gemini, DeepSeek, Copilot, Mistral, Groq). When the user clicks "Send", the Service Worker passes the formatted prompt to the appropriate content script, which then inserts it into the AI's input field.

This sounds simple until you realize every AI site uses a different editor:

  • React-controlled inputs (ChatGPT, Gemini, DeepSeek, Copilot, Mistral, Groq) β€” you can't just set input.value. React ignores DOM mutations it didn't initiate. DebugClip uses the native setter trick: calling the native HTMLTextAreaElement.prototype.value setter directly, then dispatching synthetic input and change events so React's reconciler picks up the change.
  • ProseMirror editors (Claude) β€” Claude uses a ProseMirror-based rich text editor that doesn't respond to value setters at all. Instead, DebugClip focuses the editor and uses document.execCommand("insertText") to insert content as if the user typed it.

The injection script retries at 1.5s, 3.5s, 6s, and 10s after page load using a module-level flag to prevent duplicate injections β€” because AI sites are SPAs that may not have their editor mounted immediately on navigation.


Tech Stack​

TechnologyVersionPurpose
React18Popup and options page UI
TypeScript5.xType safety across the entire extension codebase
Vite + @crxjs/vite-pluginβ€”Manifest V3 native extension bundler with HMR
Tailwind CSS3.xUtility-first styling with dark theme design tokens
chrome.debugger CDPβ€”Network capture via Chrome DevTools Protocol
chrome.scriptingβ€”Main-world script injection for console/error capture

Key Features​

πŸ”’ Live Badge Counter

Real-time error count displayed on the extension icon. Know instantly when something breaks, even if you're not in DevTools.

πŸ“ Structured Markdown Prompts

Errors formatted into token-optimized prompts with full context. AI gets exactly what it needs, structured for maximum comprehension.

πŸš€ One-Click Send to AI

Captured errors delivered to your AI of choice in one click. No copy-paste, no tab switching, no context loss.

πŸ’‰ Auto-Inject into AI Input

The prompt is injected directly into the AI's text field automatically. No paste required β€” it just appears.

πŸ”’ Zero Data Collection

Everything stays on your machine. No telemetry, no external servers, no data leaves the browser β€” privacy-first by design.

πŸ• Session History

Errors persist across page navigations within a session. Navigate freely without losing your debug context.


Pricing​

Most browser extensions either charge a monthly subscription or shove ads into your workflow. I went a different direction with DebugClip: one-time pricing, pay once, own it forever.

Why Not a Subscription?​

The entire extension runs 100% locally on your machine. There's no database scaling with each new user, no compute per request, no bandwidth costs. The only backend is a single Cloudflare Workers endpoint for license validation β€” running at $0/month regardless of user count.

When your marginal cost per user is literally zero, charging a recurring subscription is just extracting value without delivering ongoing cost. One-time pricing is honest. You pay for the work that went into building the tool, not for the privilege of continuing to use it.

Total monthly infrastructure cost: $0.

The Three Tiers​

πŸ†“ Free β€” $0

Full error & network capture, live badge counter, view all captured errors, and prompt preview (blurred). Everything you need to see the value before committing.

⚑ Pro β€” $4 one-time

Everything in Free, plus: send to AI, auto-inject into AI input, session history, smart filtering, custom prompt templates, localStorage snapshots, and priority support. One payment, lifetime access.

πŸ‘‘ Ultimate β€” $19 one-time

Everything in Pro, plus: AI answers inside the popup (BYOK with 6 providers), MCP server for AI agents (Cursor, Kiro), multi-tab capture, and webhook & Slack notifications. The full toolkit β€” forever.

The philosophy is simple: if you find DebugClip useful enough to send errors to AI, $4 unlocks that permanently. If you want the extension to be your entire debugging interface β€” with AI responses inline and agent integrations β€” $19 gets you there. No renewals, no "your trial expired" popups, no dark patterns.


Challenges & Lessons​

Building the extension was the easy part. Getting it into users' hands β€” and keeping it working across every edge case β€” was the real engineering challenge.

Challenges​

1. Chrome Web Store "keyword spam" rejection. The extension description listed every supported AI provider by name: "Works with Claude, ChatGPT, Gemini, DeepSeek, Copilot, Mistral, Groq." Store reviewers flagged this as keyword stuffing and rejected the submission outright. No warning, no specific guidance β€” just a generic policy violation email.

Fix: Rewrote the entire description using generic phrasing β€” "send to your AI assistant of choice" instead of naming competitors. Removed brand names from the feature list. Resubmitted unchanged code with only metadata differences. Approved within 24 hours.

2. Double injection bug. Both capture methods β€” chrome.scripting (console patching) and chrome.debugger (CDP) β€” could catch the same error. A failed fetch call would trigger the XHR wrapper and a CDP Network.loadingFailed event. Users saw duplicate entries in their error list, which made the output confusing and wasted AI tokens on redundant context.

Fix: Added a duplicate detection layer that compares entries by URL, message content, and timestamp proximity (within 100ms). If two entries match on all three, the later one is discarded. Also added a single module-level boolean flag (let injected = false) to prevent the main-world injection script from running twice on the same page β€” because chrome.scripting.executeScript can fire multiple times during SPA navigations.

3. CSP blocking API calls from content scripts. Content scripts injected into pages with strict Content Security Policy couldn't make API calls to the license validation server. The page's CSP applies to scripts running in its context, so fetch("https://api.debugclip.online/...") was blocked with a connect-src violation.

Fix: Routed all API calls through the Service Worker, which is exempt from page-level CSP. Content scripts send a message to the background, the Service Worker makes the request, and sends the response back. Also added the API domain to the extension's own connect-src directive in the manifest to satisfy Chrome's extension CSP requirements.

4. Service Worker dying mid-API-call. Manifest V3 Service Workers die after ~30 seconds of inactivity. During license activation, if a user was slow to complete payment and the callback arrived late, the worker would die mid-request β€” leaving the license in a half-activated state. The user would see "activating..." forever.

Fix: Write pending activation state to chrome.storage.local before starting the API call. On worker wake, check for pending states and retry. All message listeners use return true to keep the message channel open for async responses. The activation flow is now idempotent β€” if it fails or the worker dies, it picks up exactly where it left off on next wake.

5. React SPA input injection. Each AI provider uses a different editor implementation. Claude uses ProseMirror. ChatGPT uses React-controlled textareas. Setting input.value = "..." directly doesn't work for React β€” the framework ignores DOM mutations it didn't initiate, so the value reverts on the next render cycle.

Fix: Per-provider injection strategies. For React-controlled inputs (ChatGPT, Gemini, DeepSeek, Copilot, Mistral, Groq): call the native HTMLTextAreaElement.prototype.value setter directly, then dispatch synthetic input and change events so React's reconciler acknowledges the change. For ProseMirror (Claude): focus the editor and use document.execCommand("insertText") to simulate typing. The injection script retries at 1.5s, 3.5s, 6s, and 10s after page load β€” because AI sites are SPAs that may not have their editor mounted on initial navigation.

Lessons Learned​

1. The product is 30% of the work. Building the extension took about 2 weeks. Getting it listed on the Chrome Web Store, setting up one-time payments via Creem, writing the marketing site, dealing with store rejections, and handling edge cases in license activation took 4+ weeks. Marketing, compliance, and payments dominate the timeline for any product you want people to actually use.

2. Chrome Web Store reviews are inconsistent. The same extension β€” identical code, identical description β€” was rejected once and approved on resubmission without any changes. Different reviewer, different result. Don't take rejections personally. Just resubmit and hope for a more reasonable reviewer.

3. Ship earlier, polish later. I launched with core capture and send functionality. No session history, no custom templates, no multi-tab support. Real user feedback from that initial launch was more valuable than three more weeks of tweaking animations and edge cases in isolation. The features I thought users wanted were different from the ones they actually asked for.

4. Developers will pay for tools that save time. $4 is a no-brainer when the alternative is 5 minutes of clipboard gymnastics per bug, multiplied across dozens of bugs per week. Price anchoring against time saved makes the value proposition obvious.

5. Build what you use daily. DebugClip exists because I needed it every single day. Personal pain drives sustained motivation. When you're your own first user, you notice friction immediately, you test in real conditions constantly, and you never run out of motivation to improve the tool β€” because every improvement makes your own workflow better.