Build a Chrome Extension in a Day or Two with Claude Code

Developer 1-2 days Intermediate

What you'll build

Chrome extensions are the most underrated weekend project and one of the best first paid products a builder can ship. Manifest v3 has a sharp learning curve, but Claude Code knows it cold - ask it to scaffold a wxt project and you have hot-reload, TypeScript, and a working content script in minutes. Pick one site or one task, write the content script with a MutationObserver, add a small React popup, store settings in chrome.storage.sync, and submit to the web store. The whole thing fits in a long Saturday.

What you're building

You're building a Chrome extension that does one thing on one site, or one thing across the open web. Examples that fit the format: a Twitter tab that hides replies under a certain follower count, a LinkedIn highlighter that flags recruiter spam, a YouTube tool that strips Shorts from the homepage, a Gmail helper that snoozes newsletters. Small, opinionated, one user setting. The smaller the surface, the better the extension. Big do-everything extensions get rejected during review and abandoned by users within a week.

Output by Sunday is a packed extension you've sideloaded on your own browser, used for a day, and either published to the Chrome Web Store or shipped as an unpacked download with a one-page install guide. Don't skip the install guide. Most users have never sideloaded an extension and will give up at step two without one. A two-screenshot guide with arrows pointing at the developer mode toggle and the load unpacked button is the entire onboarding.

Extensions are also the perfect first paid product. The Chrome Web Store doesn't take a cut, you can license your own download from a Gumroad page, and the audience that installs niche browser tools is the audience most willing to pay nine dollars for something that saves them ten minutes a day. The economics are friendly and the build is small.

What you need before you start

Comfort with TypeScript and a passing familiarity with how the DOM works. A Chrome browser. A Google account willing to pay the five dollar one-time developer fee if you want to publish. A clear picture of which page you're modifying and what the user will see change. If you can't sketch the before-and-after in two screenshots before you write a line of code, the idea isn't sharp enough yet, and the build will drift.

  • Node 20 and a package manager
  • Claude Code with access to your repo
  • Vite plus a plugin like @crxjs/vite-plugin or wxt for hot-reload
  • A Chrome Web Store developer account if publishing
  • An icon at 16, 32, 48, and 128 pixels
  • A privacy policy URL if your extension touches any user data

Friday night: scaffolding

Use wxt or @crxjs/vite-plugin to scaffold a TypeScript extension with hot reload. Both handle the manifest v3 plumbing that's painful to write by hand. Ask Claude Code to set up a new wxt project with React for the popup and a content script targeting the host you care about. Don't bother with the optional sidebar or devtools surfaces in v1. Popup plus content script covers ninety percent of useful extensions, and the rest can wait for v2 if anyone actually asks.

Open chrome://extensions, turn on developer mode, load the dev build as an unpacked extension, and confirm the puzzle-piece icon appears with your popup. From here on, hot reload handles updates. If your script doesn't run after a code change, you forgot to hit the reload button on the chrome://extensions card. It's the universal first debugging step, and the answer to nine out of ten 'why isn't this working' moments on Saturday afternoon.

Pin the extension's icon to the toolbar while you're developing. Out of the box it sits under the puzzle-piece menu, which adds an extra click to every test cycle. Pinned, the popup opens with one click, and you'll iterate twice as fast over the course of a weekend.

Saturday: the content script

The content script is where the actual work happens. It runs in the page context with limited Chrome APIs. Use a MutationObserver to react to DOM changes if you're modifying a site like Twitter or LinkedIn where new content streams in. Don't poll. Don't use setInterval. MutationObserver is faster, lighter, and the only sustainable choice. Debounce its callback by at least 100ms so a burst of DOM changes triggers your handler once, not fifty times.

Tell Claude Code which DOM nodes you're targeting and paste in the actual outerHTML of one example. The selectors on social sites change every few months, so you'll be back here. Keep your selectors in a single constants file so you only have to edit one place when X breaks your extension on a Tuesday morning. The club at claudecodeclub.ai keeps a shared list of selector breakages for the popular sites, which often saves you from being the first to notice.

Avoid attaching React or any framework inside the content script. The page already has its own React, and a second copy will fight the first for DOM ownership and double your bundle size. Render content script UI with plain DOM APIs or with a tiny library like nanostores. Keep React inside the popup where it has the page to itself.

Saturday afternoon: the popup

The popup is a tiny React app rendered in a 320 by 480 pixel window. Use shadcn/ui components if you want it to look nice without effort. Read and write settings to chrome.storage.sync, which syncs settings across the user's signed-in browsers automatically and gives you a free settings backup. Don't use localStorage. It's not shared with the content script and breaks the moment your extension touches a second tab.

Three controls is plenty for a popup. A toggle to enable or disable the extension, a setting that changes the main behavior, and a link to a support page. Anything more belongs on a dedicated options page reached from a small link in the popup footer. Users open the popup to flip a switch, not to configure a control panel.

Choices to make along the way

wxt versus @crxjs/vite-plugin versus plain manifest editing: wxt is the friendliest, has the best docs, and handles Firefox cross-builds if you ever want them. @crxjs is closer to the Vite metal and is fine if you already love Vite. Editing manifest.json by hand works and teaches you the platform but slows the first build by a few hours.

Free download versus paid extension: the Chrome Web Store doesn't process payments, which means you handle licensing yourself if you charge. Use Gumroad or LemonSqueezy to issue license keys, and verify the key in the popup against a tiny endpoint. It's not as smooth as in-app purchase on mobile but it works fine and you keep more of the revenue.

React versus Preact versus vanilla TS for the popup: React is fine because the popup is tiny and bundle size doesn't matter much for an extension that loads from disk. Preact saves a few kilobytes if you care. Vanilla TS is the right answer if your popup has only a switch and a number input.

Wire message passing on Saturday night. The popup can't talk to the content script directly. You pass messages through chrome.runtime. The pattern is: popup sends a message with chrome.runtime.sendMessage, the background service worker receives it, forwards to the active tab with chrome.tabs.sendMessage, and the content script responds. Write the message types in a shared types.ts file so popup and content script agree on the shape. Skipping the shared types file is the source of most extension bugs.

Pick one direction as the primary channel. Most extensions only need popup-to-content-script. Content-script-to-popup is rare and usually a sign you're over-engineering. If the content script needs to ping the popup, it usually wants the background worker instead, where state survives across popup opens and closes.

How to test it

Manual testing on the target site for an afternoon. Open and close tabs, refresh the page, change a setting, watch the content script react. Test in an incognito window with the extension allowed in incognito, because that catches storage and permission bugs you won't see otherwise. If you're doing anything CPU-intensive in the content script, watch the Performance tab in DevTools while you scroll. Extensions that lag the host site get one-star reviews and never recover.

Test against logged-out states explicitly. Many extensions break when the user signs out of the host site because the DOM the content script expected isn't there. Add a guard at the top of every selector lookup that bails silently if the node is missing, rather than throwing and clogging the console with errors that nobody will report.

Also test across the four screen sizes Chrome users actually have: a laptop at 1440 pixels, a 4K monitor at 2560 pixels, a small laptop at 1280 pixels, and a phone via Chrome on Android if your extension supports mobile. Layouts that look right on one size often drift on another, and one ugly review of the wrong screenshot hurts conversion.

How to ship it

Build for production with wxt build, which produces a zip in .output/chrome-mv3. Go to the Chrome Web Store developer dashboard, upload the zip, fill out the listing, point at a privacy policy URL, and submit for review. Review takes anywhere from a day to a week. While you wait, make the unpacked zip available as a direct download with an install guide for users who don't want to wait. Mention the club at claudecodeclub.ai if your extension solves a problem builders complain about, because that's how the first hundred installs happen.

Listing copy matters more than most developers think. The first sentence of the description shows in search results. Lead with the concrete benefit, not the technology. 'Hides Twitter replies from accounts with under 100 followers' beats 'A browser extension for filtering social media content' every time. Two clean screenshots with captions, a one-minute walkthrough video, and a privacy policy that fits on one page round it out.

How to extend it

Add a second target site once the first is stable. Add an options page for power-user settings the popup is too small for. Add a context-menu entry for users who want to trigger the extension on a selection. Add Firefox support, which wxt makes nearly free. Each of those is a couple of hours, not a day. If you start charging, add a license-key field in the popup and verify against a tiny Cloudflare Worker endpoint. The whole paywall is fifty lines of code and unlocks the business model.

Common gotchas

Forgetting to reload the extension after a code change is the daily one. Hardcoding selectors that break when the site updates is the weekly one. Forgetting that manifest v3 service workers go to sleep, so any setTimeout longer than a few seconds vanishes, is the monthly one. Use chrome.alarms instead. Finally, treating chrome.storage.sync like a database. It's capped at a hundred kilobytes total. Big data goes in chrome.storage.local, which holds ten megabytes.

Permissions creep is the gotcha that gets your extension flagged in review. Every host permission you request triggers a scarier install warning. Use activeTab where possible, which doesn't show a warning and grants access only when the user clicks the icon. Add broader host permissions only when you genuinely need background access, and document why in the listing description so the review team understands.

What Claude Code does well on this build

Manifest v3 has enough quirks - service worker lifecycle, the activeTab model, the difference between scripting.executeScript and a content script, the correct way to wire chrome.runtime.onMessage - that most developers spend their first extension weekend reading error messages rather than shipping. Claude Code has absorbed all of it. When you tell it 'set up a wxt TypeScript project with a content script that runs on twitter.com and a React popup with a toggle,' the scaffold it produces is immediately runnable. You see the extension icon in Chrome within minutes of starting, which changes how the whole day feels.

The message-passing architecture is where Claude Code particularly earns its place. Popup to background to content script, the shared types, the handler registration - it produces a clean typed implementation in one pass. Without it, this is a two-hour exercise in reading Chrome extension docs and deciphering error messages like 'Could not establish connection. Receiving end does not exist.' With it, you spend that time on the actual feature instead.

When the target site updates its DOM and breaks your selector - and it will, especially on Twitter, LinkedIn, and YouTube - you paste the new outerHTML into Claude Code and ask it to update the selectors. That feedback loop is ten minutes. Without Claude Code, it is a debugging session with no clear end. The club at claudecodeclub.ai tracks selector breakages for the high-traffic sites and posts alerts when a major site ships a DOM change, which often saves you from discovering the breakage via a one-star review.

Monetizing the extension after launch

The Chrome Web Store has no built-in payment mechanism beyond a one-time purchase price. The practical path for a subscription or freemium model is a license key field in the popup that validates against a small endpoint you control. Claude Code builds the whole thing - the popup field, the validation call, the Cloudflare Worker endpoint, and the Gumroad or LemonSqueezy webhook that issues keys after purchase - in about two hours. The experience is not as smooth as an app store in-app purchase, but it works, and you keep a meaningfully larger share of revenue.

A freemium model where the core feature is free and one power-user setting is paid is the highest-converting structure for niche browser tools. Free gets the installs, which get the word-of-mouth, which drives paid conversions from the ten percent of users who use the extension daily. Set the paywall at the setting that only daily users need, not at the feature that onboards them. Extensions that put the paywall too early get uninstalled, reviewed badly, and never recover.

Members at claudecodeclub.ai have shipped extensions for Twitter filtering, LinkedIn signal-to-noise improvement, YouTube decluttering, and Gmail automation. The builds typically take one to two days with Claude Code and Claude Code AI assistance throughout - writing the content script, the popup UI, the message-passing layer, and the web store listing description. The $9/month membership includes a browser extension starter project and a thread of member-built extensions you can study for patterns and permission scope decisions.

Common questions

  • Which framework should I use to scaffold the extension?

    wxt is the friendliest, has the best docs, and gives you Firefox cross-builds for free. @crxjs/vite-plugin is fine if you already love Vite. Editing manifest.json by hand teaches you the platform but slows the first build by hours.

  • Why use MutationObserver instead of setInterval?

    MutationObserver fires only when the DOM actually changes, which makes the extension faster, lighter, and less likely to lag the host site. Polling with setInterval wastes CPU and gets you one-star reviews.

  • Where should I store user settings?

    chrome.storage.sync. It syncs across the user's signed-in browsers, works from both popup and content script, and survives extension updates. localStorage breaks all three of those promises.

  • How do the popup and content script communicate?

    Through chrome.runtime message passing. The popup sends a message, the background service worker forwards it to the active tab, and the content script responds. Define the message shapes in a shared types.ts so both sides agree.

  • How long does Chrome Web Store review take?

    Anywhere from a day to a week. While you wait, offer the packed zip as a direct download with a short install guide so early users can sideload it without delay.

  • Why do my long-running timers disappear?

    Manifest v3 service workers go to sleep when idle, killing any setTimeout longer than a few seconds. Use chrome.alarms for scheduled work that needs to survive the worker going dormant.

More to build

Build it. Ship it. Get paid.

Step-by-step lessons for every one of these inside the club. Join Claude Code Club for $9/month.

Related: the library, guides, and comparisons.