Building a Chrome Extension Price Match Finder
Creating a Chrome extension that identifies lower prices across multiple retailers is a practical project that demonstrates core extension development concepts. This guide walks through building a price match finder extension using manifest V3, with patterns you can adapt for your own projects.
Understanding the Architecture
Chrome extensions with manifest V3 follow a specific architecture. Your extension needs three primary components working together:
- Background service worker handles long-running tasks and API calls
- Content scripts interact with web page DOM
- Popup UI provides user controls and displays results
For a price match finder, the typical flow involves detecting product pages, extracting product identifiers, querying price APIs, and displaying savings to users.
Project Structure
A minimal extension structure looks like this:
price-match-finder/
├── manifest.json
├── background.js
├── content.js
├── popup/
│ ├── popup.html
│ └── popup.js
└── styles.css
Manifest Configuration
Your manifest.json defines capabilities and permissions:
{
"manifest_version": 3,
"name": "Price Match Finder",
"version": "1.0.0",
"description": "Find lower prices across multiple retailers",
"permissions": [
"activeTab",
"scripting",
"storage"
],
"host_permissions": [
"*://*.amazon.com/*",
"*://*.walmart.com/*",
"*://*.target.com/*"
],
"action": {
"default_popup": "popup/popup.html",
"default_icon": "icon.png"
},
"background": {
"service_worker": "background.js"
}
}
The host_permissions array specifies which sites your extension can access. Add retailers relevant to your price comparison logic.
Extracting Product Information
Content scripts run in the context of web pages and can extract product data. Here’s a pattern for detecting product pages:
// content.js
const PRODUCT_SELECTORS = {
amazon: '[data-asin]',
walmart: '[data-product-id]',
target: '[data-test="product-title"]'
};
function detectProductInfo() {
const hostname = window.location.hostname;
if (hostname.includes('amazon')) {
const asin = document.querySelector('[data-asin]')?.dataset.asin;
return asin ? { retailer: 'amazon', id: asin, type: 'asin' } : null;
}
if (hostname.includes('walmart')) {
const productId = document.querySelector('[data-product-id]')?.dataset.productId;
return productId ? { retailer: 'walmart', id: productId, type: 'walmart-id' } : null;
}
if (hostname.includes('target')) {
const title = document.querySelector('[data-test="product-title"]')?.textContent;
return title ? { retailer: 'target', id: title, type: 'name' } : null;
}
return null;
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'getProductInfo') {
const productInfo = detectProductInfo();
sendResponse(productInfo);
}
return true;
});
This script detects which retailer you’re on and extracts the appropriate product identifier. Extend the selectors for additional retailers.
Background Service Worker Logic
The service worker handles API calls and data processing:
// background.js
const PRICE_API_ENDPOINT = 'https://api.your-price-service.com/v1/search';
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'findPrices') {
fetchPrices(request.productInfo)
.then(prices => sendResponse({ success: true, prices }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true;
}
});
async function fetchPrices(productInfo) {
const response = await fetch(PRICE_API_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${await getApiKey()}`
},
body: JSON.stringify({
retailer: productInfo.retailer,
product_id: productInfo.id,
id_type: productInfo.type
})
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
async function getApiKey() {
const result = await chrome.storage.local.get(['apiKey']);
return result.apiKey;
}
Popup Interface
The popup provides user controls:
<!-- popup/popup.html -->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="../styles.css">
</head>
<body>
<div class="container">
<h2>Price Match Finder</h2>
<div id="product-info">Checking page...</div>
<div id="results" class="hidden">
<h3>Lower Prices Found:</h3>
<ul id="price-list"></ul>
</div>
<div id="error" class="hidden"></div>
</div>
<script src="popup.js"></script>
</body>
</html>
// popup/popup.js
document.addEventListener('DOMContentLoaded', async () => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.tabs.sendMessage(tab.id, { action: 'getProductInfo' }, async (productInfo) => {
if (!productInfo) {
showError('No product detected on this page');
return;
}
displayProductInfo(productInfo);
chrome.runtime.sendMessage(
{ action: 'findPrices', productInfo },
(response) => {
if (response.success) {
displayPrices(response.prices);
} else {
showError(response.error);
}
}
);
});
});
function displayProductInfo(info) {
document.getElementById('product-info').textContent =
`Detected: ${info.retailer} - ${info.id}`;
}
function displayPrices(prices) {
const list = document.getElementById('price-list');
prices.forEach(price => {
const li = document.createElement('li');
li.innerHTML = `
<a href="${price.url}" target="_blank">${price.retailer}</a>
- $${price.price.toFixed(2)} (save $${price.savings.toFixed(2)})
`;
list.appendChild(li);
});
document.getElementById('results').classList.remove('hidden');
}
function showError(message) {
const errorDiv = document.getElementById('error');
errorDiv.textContent = message;
errorDiv.classList.remove('hidden');
}
Testing Your Extension
Load your extension in Chrome through chrome://extensions/. Enable Developer mode, click “Load unpacked”, and select your extension directory. Test on various retailer pages to verify product detection works correctly.
For development, use Chrome’s DevTools on the extension popup. Right-click the extension icon and choose “Inspect popup” to open console and debug issues.
Price API Considerations
Building a comprehensive price database requires either aggregating multiple retailer APIs or using a third-party service. Options include:
- Retailer affiliate APIs — Many retailers offer affiliate programs with product data access
- Price aggregation services — Services like PriceAPI, Pronto, or Keepa provide product data
- Web scraping — More complex but gives full control (ensure compliance with retailer terms)
For personal projects, starting with a single retailer’s API or a limited dataset helps validate your architecture before scaling.
Extension Distribution
When ready to distribute:
- Create a Chrome Web Store developer account
- Package your extension using
chrome://extensions/→ Pack extension - Upload through the Chrome Web Store developer dashboard
- Submit for review (typically 24-72 hours)
Summary
Building a price match finder demonstrates several Chrome extension concepts: content script injection, message passing between components, manifest configuration, and popup UI development. The architecture scales well—you can add more retailers, implement price alerts, or integrate with deal notification systems.
Start with a minimal viable product that detects products on two or three major retailers, then expand based on your use case and API access.
Related Reading
- Claude Code for Beginners: Complete Getting Started Guide
- Best Claude Skills for Developers in 2026
- Claude Skills Guides Hub
Built by theluckystrike — More at zovo.one