HomeBuild Guides › Build a Chrome Extension
Advanced ⏱ 3-4 hours

Build a Chrome Extension

Ship a Chrome extension with user auth, cloud storage, and payments

VS Code
VS CodeEditor
GitHub
GitHubVersion Control
Supabase
SupabaseBackend
Stripe
StripePayments
Vercel
VercelLanding Page

What You'll Build

A published Chrome extension with user authentication, cloud data storage, premium tier with Stripe payments, and a landing page for distribution.

Prerequisites

Architecture

The Chrome extension runs locally in the browser with a popup UI, content scripts for page interaction, and a background service worker for persistent logic. Supabase handles user auth (via OAuth popup) and stores user data in Postgres. Stripe manages premium subscriptions through a checkout flow hosted on your Vercel landing page. GitHub stores the code and triggers Vercel deployments.

Extension (Chrome) → Supabase (Auth + DB) → Stripe (Payments) → Vercel (Landing Page + Checkout)

5 Steps

1
VS Code

Scaffold extension with manifest.json and popup

~20 min

Set up the Chrome extension project structure with Manifest V3, a popup UI, and the basic file scaffolding.

  1. Create a new project directory and open it in VS Code
  2. Create the manifest.json file with Manifest V3 format - this is the extension's config file
  3. Create popup.html and popup.js for the extension's popup UI
  4. Create a styles.css for your popup styling
  5. Load the extension in Chrome: go to chrome://extensions, enable Developer Mode, click "Load unpacked", and select your project folder
manifest.json
{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0.0",
  "description": "A useful Chrome extension",
  "permissions": ["storage", "activeTab"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon-48.png"
  },
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content.js"]
  }],
  "icons": {
    "16": "icon-16.png",
    "48": "icon-48.png",
    "128": "icon-128.png"
  }
}
popup.html
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div id="app">
    <h1>My Extension</h1>
    <div id="auth-section">
      <button id="login-btn">Sign In</button>
    </div>
    <div id="main-section" style="display:none">
      <p>Welcome! Extension is active.</p>
      <button id="action-btn">Do Something</button>
    </div>
  </div>
  <script src="popup.js"></script>
</body>
</html>
background.js
// Background service worker
chrome.runtime.onInstalled.addListener(() => {
  console.log('Extension installed')
})

// Listen for messages from popup or content scripts
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'GET_DATA') {
    // Handle data requests
    sendResponse({ status: 'ok' })
  }
  return true // Keep message channel open for async
})
💡
Tip: Keep chrome://extensions open in a pinned tab during development. Click the refresh icon on your extension after every change to reload it.
2
VS Code

Build the core feature in content and background scripts

~40 min

Implement your extension's main functionality using content scripts for page interaction and the background service worker for logic.

  1. Create content.js - this runs on every page the user visits and can read or modify the DOM
  2. Use chrome.runtime.sendMessage() in the content script to communicate with the background worker
  3. In background.js, handle messages and use chrome.storage.local to persist data between sessions
  4. Build the popup UI logic in popup.js - query the active tab and display relevant data
  5. Test thoroughly: load the extension, visit a page, open the popup, and verify all communication works
content.js
// Content script - runs on web pages
(function() {
  // Example: extract page data
  const pageData = {
    title: document.title,
    url: global.location.href,
    text: document.body.innerText.substring(0, 1000)
  }

  // Send data to background script
  chrome.runtime.sendMessage(
    { type: 'PAGE_DATA', data: pageData },
    (response) => console.log('Saved:', response)
  )
})()
💡
Tip: Use Chrome DevTools to debug your extension: right-click the popup → Inspect for popup debugging, and check the "Service Worker" link on chrome://extensions for background script logs.
⚠️
Warning: Content scripts run in an isolated world - they can access the DOM but not the page's JavaScript variables directly. Use global.postMessage if you need to communicate with page scripts.
3
Supabase

Set up Supabase for user data and auth

~30 min

Add user authentication and cloud data storage so users can sync their extension data across devices.

  1. Create a Supabase project at supabase.com and grab your project URL and anon key
  2. Install the Supabase JS client by including it via CDN in your popup.html or bundling it
  3. Implement Google OAuth login in your popup - Supabase handles the OAuth flow, you just need to open the auth URL
  4. Create a user_data table in Supabase to store user-specific extension data
  5. Enable Row Level Security so users can only access their own data
lib/supabase.js
import { createClient } from '@supabase/supabase-js'

const supabaseUrl = 'https://your-project.supabase.co'
const supabaseKey = 'your-anon-key'

export const supabase = createClient(supabaseUrl, supabaseKey)

export async function signInWithGoogle() {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'google',
    options: {
      redirectTo: chrome.identity.getRedirectURL()
    }
  })
  return { data, error }
}

export async function saveUserData(userId, data) {
  return await supabase
    .from('user_data')
    .upsert({ user_id: userId, ...data })
}
💡
Tip: Use chrome.identity.getRedirectURL() for your OAuth redirect - Chrome provides a special URL for extension auth flows that avoids CORS issues.
⚠️
Warning: Never hardcode your Supabase service_role key in the extension. Only use the anon key - the extension code is readable by anyone who installs it.
4
Stripe

Add Stripe for premium features

~30 min

Gate premium features behind a Stripe subscription and manage entitlements from your backend.

  1. Create a Stripe account and set up a product with monthly and yearly price tiers
  2. Build a checkout API route on your Vercel landing page that creates Stripe Checkout Sessions
  3. From the extension popup, redirect free users to your Vercel-hosted pricing page when they try premium features
  4. Set up a Stripe webhook on Vercel to update the user's subscription status in Supabase when they pay
  5. In the extension, check the user's subscription status from Supabase before enabling premium features
popup.js (premium check)
async function checkPremiumStatus(userId) {
  const { data } = await supabase
    .from('subscriptions')
    .select('status, plan')
    .eq('user_id', userId)
    .single()

  if (data?.status === 'active') {
    // Enable premium features
    document.getElementById('premium-features').style.display = 'block'
    document.getElementById('upgrade-banner').style.display = 'none'
  } else {
    // Show upgrade prompt
    document.getElementById('upgrade-banner').style.display = 'block'
  }
}
💡
Tip: Offer a generous free tier. Extensions grow through word of mouth - free users who love your tool will upgrade when they hit the limit.
⚠️
Warning: Never process payments inside the extension popup. Always redirect to an external checkout page - Chrome Web Store policy prohibits in-extension payment processing.
5
Vercel

Create landing page on Vercel and publish to Chrome Web Store

~30 min

Build a landing page for your extension, push your code to GitHub, and submit to the Chrome Web Store.

  1. Create a Next.js or static landing page with: hero section, feature list, pricing, and a "Add to Chrome" CTA button
  2. Deploy the landing page to Vercel by connecting your GitHub repo
  3. Add your Stripe webhook endpoint and checkout API routes to the Vercel project
  4. Package your extension: zip the extension folder (excluding node_modules and .git)
  5. Go to the Chrome Web Store Developer Dashboard, pay the $5 registration fee, upload your zip, add screenshots and descriptions, and submit for review
Terminal
# Package extension for Chrome Web Store
cd my-extension
zip -r ../my-extension.zip . -x "node_modules/*" ".git/*" "*.map"
💡
Tip: Chrome Web Store review takes 1-3 business days. Have your landing page live and your Stripe integration tested before submitting so you can start selling immediately on approval.
⚠️
Warning: Read the Chrome Web Store developer policies carefully. Extensions that request unnecessary permissions or have unclear privacy policies get rejected.

🎉 You're Done!

A published Chrome extension with user authentication, cloud data storage, premium tier with Stripe payments, and a landing page for distribution.

Done for you

Want this built for you?

Get a step-by-step checklist, setup order, and the exact config for every tool in this guide. Or let me build it for you.

Get the checklist → Want this built for you?