Claude Skills Guide

Building a Price Comparison Chrome Extension: A Developer’s Guide

Price tracking and comparison tools have become essential for online shoppers and developers building e-commerce platforms. Chrome extensions offer a powerful way to automate price comparisons directly in the browser, providing real-time alerts and historical data without requiring users to visit separate websites.

This guide walks through building a price comparison Chrome extension using modern APIs and best practices.

Understanding the Architecture

A price comparison extension typically consists of three main components:

  1. Content scripts that run on e-commerce pages and extract product information
  2. Background scripts that handle data storage, API calls, and cross-tab coordination
  3. Popup UI for quick access to tracked products and settings

With Chrome’s Manifest V3, background scripts have shifted to service workers, which introduces some architectural considerations around persistence and state management.

Project Setup

Create your extension directory structure:

price-tracker/
├── manifest.json
├── background.js
├── content.js
├── popup/
│   ├── popup.html
│   └── popup.js
├── styles.css
└── icons/
    ├── icon16.png
    ├── icon48.png
    └── icon128.png

Manifest Configuration

The manifest.json defines your extension’s capabilities:

{
  "manifest_version": 3,
  "name": "Price Tracker",
  "version": "1.0",
  "description": "Track and compare prices across e-commerce sites",
  "permissions": [
    "storage",
    "activeTab",
    "scripting"
  ],
  "host_permissions": [
    "https://*.amazon.com/*",
    "https://*.ebay.com/*",
    "https://*.walmart.com/*"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["https://*.amazon.com/*", "https://*.ebay.com/*"],
    "js": ["content.js"]
  }],
  "action": {
    "default_popup": "popup/popup.html",
    "default_icon": {
      "48": "icons/icon48.png"
    }
  }
}

Note the host_permissions array. In Manifest V3, you must explicitly declare which domains your extension can access. This is crucial for price comparison extensions that need to read product pages from multiple retailers.

Extracting Product Data with Content Scripts

Content scripts run in the context of web pages, giving you access to the DOM. Here’s how to extract product information from a typical e-commerce page:

// content.js
function extractProductData() {
  const selectors = {
    title: '[data-feature-name="title"], .product-title, h1[itemprop="name"]',
    price: '[data-feature-name="priceblock_ourprice"], .price-current, [itemprop="price"]',
    currency: '[itemprop="priceCurrency"]',
    availability: '[data-feature-name="availability"], .availability-status'
  };

  const getText = (selector) => {
    const el = document.querySelector(selector);
    return el ? el.textContent.trim() : null;
  };

  const getAttribute = (selector, attr) => {
    const el = document.querySelector(selector);
    return el ? el.getAttribute(attr) : null;
  };

  return {
    url: window.location.href,
    title: getText(selectors.title),
    price: getText(selectors.price),
    currency: getAttribute(selectors.currency, 'content') || 'USD',
    availability: getText(selectors.availability),
    timestamp: new Date().toISOString()
  };
}

// Listen for messages from popup or background
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'getProductData') {
    const data = extractProductData();
    sendResponse(data);
  }
});

This script handles multiple selectors since different retailers use varying class names and data attributes.

Background Service Worker

The background service worker manages the extension’s core logic:

// background.js
const PRICE_HISTORY_KEY = 'price_history';

// Store price data
async function storePriceData(productUrl, productData) {
  const result = await chrome.storage.local.get(PRICE_HISTORY_KEY);
  const history = result[PRICE_HISTORY_KEY] || {};
  
  if (!history[productUrl]) {
    history[productUrl] = {
      currentPrice: productData.price,
      lowestPrice: productData.price,
      highestPrice: productData.price,
      prices: [],
      title: productData.title,
      lastUpdated: productData.timestamp
    };
  } else {
    const product = history[productUrl];
    product.prices.push({
      price: productData.price,
      timestamp: productData.timestamp
    });
    product.currentPrice = productData.price;
    product.lowestPrice = Math.min(product.lowestPrice, parsePrice(productData.price));
    product.highestPrice = Math.max(product.highestPrice, parsePrice(productData.price));
    product.lastUpdated = productData.timestamp;
  }
  
  await chrome.storage.local.set({ [PRICE_HISTORY_KEY]: history });
}

function parsePrice(priceString) {
  const numericMatch = priceString.match(/[\d,]+\.?\d*/);
  return numericMatch ? parseFloat(numericMatch[0].replace(',', '')) : 0;
}

// Handle messages from content scripts and popup
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'saveProduct') {
    storePriceData(request.url, request.productData)
      .then(() => sendResponse({ success: true }))
      .catch(err => sendResponse({ success: false, error: err.message }));
    return true;
  }
  
  if (request.action === 'getHistory') {
    chrome.storage.local.get(PRICE_HISTORY_KEY)
      .then(result => sendResponse(result[PRICE_HISTORY_KEY] || {}))
      .catch(err => sendResponse({ error: err.message }));
    return true;
  }
});

The popup provides quick access to tracked products:

<!-- popup/popup.html -->
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="../styles.css">
</head>
<body>
  <div class="popup-container">
    <h2>Price Tracker</h2>
    <div id="tracked-products"></div>
    <button id="track-current">Track This Product</button>
  </div>
  <script src="popup.js"></script>
</body>
</html>
// popup/popup.js
document.addEventListener('DOMContentLoaded', () => {
  loadTrackedProducts();
  
  document.getElementById('track-current').addEventListener('click', async () => {
    const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
    
    chrome.tabs.sendMessage(tab.id, { action: 'getProductData' }, async (productData) => {
      if (productData && productData.price) {
        await chrome.runtime.sendMessage({
          action: 'saveProduct',
          url: productData.url,
          productData: productData
        });
        loadTrackedProducts();
      }
    });
  });
});

async function loadTrackedProducts() {
  const result = await chrome.runtime.sendMessage({ action: 'getHistory' });
  const container = document.getElementById('tracked-products');
  
  if (!result || Object.keys(result).length === 0) {
    container.innerHTML = '<p>No products tracked yet</p>';
    return;
  }
  
  container.innerHTML = Object.entries(result).map(([url, data]) => `
    <div class="product-card">
      <h3>${data.title || 'Unknown Product'}</h3>
      <p class="current-price">Current: ${data.currentPrice}</p>
      <p class="price-range">
        Low: ${data.lowestPrice} | High: ${data.highestPrice}
      </p>
    </div>
  `).join('');
}

Advanced Features

Once you have the basics working, consider adding:

Price Drop Notifications: Use the Chrome Notifications API to alert users when prices fall below their target:

async function checkPriceAlert(productUrl, targetPrice) {
  const history = await chrome.storage.local.get(PRICE_HISTORY_KEY);
  const product = history[PRICE_HISTORY_KEY][productUrl];
  
  if (parsePrice(product.currentPrice) <= targetPrice) {
    chrome.notifications.create({
      type: 'basic',
      iconUrl: 'icons/icon48.png',
      title: 'Price Drop Alert!',
      message: `${product.title} is now ${product.currentPrice}`
    });
  }
}

Cross-Platform Sync: Implement cloud storage to sync price history across devices using your own backend or services like Firebase.

Analytics Dashboard: Create a dedicated extension page showing price trends with charts using a library like Chart.js.

Best Practices

When building production-ready price comparison extensions:

Building a price comparison extension combines DOM manipulation, Chrome APIs, and data management into a practical project that demonstrates real-world extension development patterns.

Built by theluckystrike — More at zovo.one