Build a Price Tracker Chrome Extension: Monitor Amazon and E-Commerce Prices
Have you ever added an item to your shopping cart, hesitated at the checkout, and then watched the price drop a week later? Or perhaps you have been manually checking product pages daily, hoping to catch the perfect moment to buy? If you have experienced this frustration, you are not alone. Millions of shoppers worldwide search for tools to help them track prices and get alerts when prices drop. Building an amazon price tracker chrome extension is one of the most practical and profitable projects you can undertake as a developer in 2025.
In this comprehensive guide, we will walk through the complete process of creating a chrome extension price tracker that monitors Amazon and other e-commerce websites. By the end of this tutorial, you will have a fully functional extension that can track product prices, store price history, and send instant notifications when prices drop.
Why Build a Price Tracker Chrome Extension
The demand for price drop notification chrome tools has never been higher. With the rise of e-commerce giants like Amazon, Walmart, eBay, and countless niche online stores, consumers have more options than ever before. However, this abundance also brings price volatility. Products can fluctuate in price multiple times per week, sometimes dramatically.
Building a chrome extension price monitor is not just a great learning exercise—it is also a valuable tool that millions of users actively seek. According to recent surveys, over 60% of online shoppers would use a price tracking tool if one were available. By mastering this skill, you position yourself to create something that solves a real problem while building your portfolio as a Chrome extension developer.
The e-commerce price tracking market is projected to grow significantly in the coming years, making this an excellent time to build your own price tracker chrome extension. Users are becoming increasingly savvy about finding the best deals, and they need automated tools to help them monitor prices across multiple websites without spending hours manually checking each one.
Understanding the Architecture of a Price Tracker Extension
Before we dive into coding, let us understand how a typical chrome extension price tracker works. The architecture consists of several key components that work together to deliver a seamless user experience.
Core Components
The first component is the content script that runs on product pages. This script extracts the current price, product title, product identifier (like ASIN or SKU), and other relevant information from the page. Content scripts have access to the DOM and can parse the HTML to find price elements.
The second component is the background service worker that handles periodic price checks. In Manifest V3, service workers are the backbone of extension functionality. They can run on a schedule to fetch updated prices even when the user is not actively viewing the product page.
The third component is the popup interface where users manage their tracked items. This provides a user-friendly way to add products, view price history, set target prices, and configure notification preferences.
The fourth component is the storage system using Chrome’s storage API. This stores tracked products, price history, user preferences, and notification settings locally or synchronized across the user’s devices.
Finally, the notification system uses Chrome’s native notifications to alert users when prices drop below their target threshold. This is the key feature that makes a price drop notification chrome extension valuable to users.
Technology Stack
For this project, we will use:
- HTML/CSS for the popup interface
- JavaScript (ES6+) for all logic
- Chrome Extension APIs (Manifest V3)
- Local Storage or Chrome Storage API for data persistence
No external frameworks are required, keeping the extension lightweight and fast. However, you can certainly use frameworks like React or Vue if you prefer, though we will stick to vanilla JavaScript for this tutorial to ensure maximum compatibility and understanding of the underlying concepts.
Setting Up the Project Structure
Let us start by creating the project structure for our chrome extension price tracker. Create a new folder for your project and set up the following files and directories.
Manifest File (manifest.json)
Every Chrome extension starts with a manifest file. This JSON file tells Chrome about your extension’s permissions, files, and capabilities. For our price tracker chrome extension, we need to declare the permissions for storage, notifications, and the ability to run on e-commerce websites.
Create a file named manifest.json in your project folder. This file will define the extension’s metadata, including its name, version, description, and the permissions it requires to function properly. The manifest also specifies which scripts run and when, ensuring that our price monitoring logic executes at the appropriate times.
{
"manifest_version": 3,
"name": "Price Watch - E-Commerce Price Tracker",
"version": "1.0.0",
"description": "Track product prices on Amazon and other e-commerce sites. Get notified when prices drop.",
"permissions": [
"storage",
"notifications",
"activeTab",
"scripting"
],
"host_permissions": [
"*://*.amazon.com/*",
"*://*.walmart.com/*",
"*://*.ebay.com/*",
"*://*.target.com/*",
"*://*.bestbuy.com/*"
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": [
"*://*.amazon.com/*",
"*://*.walmart.com/*",
"*://*.ebay.com/*"
],
"js": ["content.js"]
}
],
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}
This manifest declares that our extension needs storage and notification permissions, will run on major e-commerce websites, and includes both a popup interface and a background service worker. The host permissions allow our extension to access product pages on Amazon, Walmart, eBay, Target, and Best Buy.
Building the Content Script
The content script is the heart of our chrome extension price monitor. It runs on product pages and extracts price information automatically. Let us create a robust content script that can handle multiple e-commerce platforms.
content.js
Create a file named content.js. This script will detect which e-commerce site the user is on, extract the relevant product information, and provide functionality to add products to the tracking list directly from the page.
// Content script for extracting product information from e-commerce sites
(function() {
'use strict';
// Product extraction functions for different retailers
const extractors = {
amazon: () => {
const titleEl = document.getElementById('productTitle');
const priceEl = document.querySelector('.a-price .a-offscreen') ||
document.getElementById('priceblock_ourprice') ||
document.getElementById('priceblock_dealprice');
const asinEl = document.querySelector('[data-asin]');
if (!titleEl || !priceEl) return null;
return {
title: titleEl.textContent.trim(),
price: parseFloat(priceEl.textContent.replace(/[^0-9.]/g, '')),
currency: 'USD',
url: window.location.href,
retailer: 'amazon',
productId: asinEl ? asinEl.getAttribute('data-asin') : null,
image: document.querySelector('#landingImage')?.src || null
};
},
walmart: () => {
const titleEl = document.querySelector('[itemprop="name"]');
const priceEl = document.querySelector('[itemprop="price"]');
if (!titleEl || !priceEl) return null;
return {
title: titleEl.textContent.trim(),
price: parseFloat(priceEl.getAttribute('content') || priceEl.textContent.replace(/[^0-9.]/g, '')),
currency: 'USD',
url: window.location.href,
retailer: 'walmart',
productId: window.location.pathname.split('/')[4] || null,
image: document.querySelector('[data-testid="hero-image"] img')?.src || null
};
},
ebay: () => {
const titleEl = document.querySelector('.x-item-title__mainTitle span');
const priceEl = document.querySelector('.x-price-primary span');
if (!titleEl || !priceEl) return null;
return {
title: titleEl.textContent.trim(),
price: parseFloat(priceEl.textContent.replace(/[^0-9.]/g, '')),
currency: 'USD',
url: window.location.href,
retailer: 'ebay',
productId: window.location.pathname.split('/').pop()?.split('?')[0] || null,
image: document.querySelector('.ux-image-carousel-item img')?.src || null
};
}
};
// Detect current retailer
function detectRetailler() {
const hostname = window.location.hostname;
for (const retailer in extractors) {
if (hostname.includes(retailer)) {
return retailer;
}
}
return null;
}
// Extract product information
function extractProduct() {
const retailer = detectRetailler();
if (retailer && extractors[retailer]) {
return extractors[retailer]();
}
return null;
}
// Listen for messages from popup or background
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'getProductInfo') {
const product = extractProduct();
sendResponse(product);
}
});
// Inject floating tracking button
function injectTrackerButton() {
if (document.getElementById('price-tracker-btn')) return;
const button = document.createElement('div');
button.id = 'price-tracker-btn';
button.innerHTML = '📊 Track Price';
button.style.cssText = `
position: fixed;
bottom: 20px;
right: 20px;
background: #4CAF50;
color: white;
padding: 12px 20px;
border-radius: 25px;
cursor: pointer;
font-family: Arial, sans-serif;
font-size: 14px;
z-index: 999999;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
transition: transform 0.2s, background 0.2s;
`;
button.addEventListener('click', async () => {
const product = extractProduct();
if (product) {
// Save to storage
chrome.storage.local.get(['trackedProducts'], (result) => {
const products = result.trackedProducts || [];
products.push({
...product,
trackedAt: new Date().toISOString(),
priceHistory: [{ price: product.price, date: new Date().toISOString() }]
});
chrome.storage.local.set({ trackedProducts: products });
button.textContent = '✓ Tracked!';
button.style.background = '#2196F3';
setTimeout(() => {
button.textContent = '📊 Track Price';
button.style.background = '#4CAF50';
}, 2000);
});
} else {
alert('Could not detect product on this page.');
}
});
document.body.appendChild(button);
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', injectTrackerButton);
} else {
injectTrackerButton();
}
})();
This content script is sophisticated enough to handle multiple retailers. It includes extractors for Amazon, Walmart, and eBay, each tailored to the specific HTML structure of those sites. The script also injects a floating button that users can click to add the current product to their tracking list.
Creating the Background Service Worker
The background service worker is essential for periodic price checks. Even when the user is not viewing a product page, the service worker can fetch updated prices and trigger notifications. Let us create a robust background worker for our chrome extension price monitor.
background.js
// Background service worker for price tracking
const CHECK_INTERVAL_HOURS = 6;
const NOTIFICATION_ICON = 'icons/icon128.png';
chrome.runtime.onInstalled.addListener(() => {
// Initialize storage
chrome.storage.local.set({
trackedProducts: [],
settings: {
checkInterval: CHECK_INTERVAL_HOURS,
notificationsEnabled: true
}
});
// Schedule periodic price checks
schedulePriceCheck();
});
function schedulePriceCheck() {
// Check prices every 6 hours
chrome.alarms.create('priceCheck', {
delayInMinutes: CHECK_INTERVAL_HOURS * 60,
periodInMinutes: CHECK_INTERVAL_HOURS * 60
});
}
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'priceCheck') {
checkAllPrices();
}
});
async function checkAllPrices() {
const result = await chrome.storage.local.get('trackedProducts');
const products = result.trackedProducts || [];
for (const product of products) {
try {
const updatedProduct = await fetchUpdatedPrice(product);
if (updatedProduct && updatedProduct.price !== product.price) {
// Update price history
product.priceHistory.push({
price: updatedProduct.price,
date: new Date().toISOString()
});
// Check if price dropped
const lowestPrice = Math.min(...product.priceHistory.map(p => p.price));
if (updatedProduct.price <= lowestPrice && product.targetPrice &&
updatedProduct.price <= product.targetPrice) {
sendPriceDropNotification(product, updatedProduct.price);
}
// Update stored product
product.price = updatedProduct.price;
}
} catch (error) {
console.error(`Error checking price for ${product.url}:`, error);
}
}
await chrome.storage.local.set({ trackedProducts: products });
}
async function fetchUpdatedPrice(product) {
try {
// Use Chrome's declarativeNetRequest or fetch directly
const response = await fetch(product.url, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
});
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Extract price based on retailer
let price = null;
switch (product.retailer) {
case 'amazon':
const amazonPrice = doc.querySelector('.a-price .a-offscreen') ||
doc.querySelector('#priceblock_ourprice');
if (amazonPrice) {
price = parseFloat(amazonPrice.textContent.replace(/[^0-9.]/g, ''));
}
break;
case 'walmart':
const walmartPrice = doc.querySelector('[itemprop="price"]');
if (walmartPrice) {
price = parseFloat(walmartPrice.getAttribute('content') ||
walmartPrice.textContent.replace(/[^0-9.]/g, ''));
}
break;
case 'ebay':
const ebayPrice = doc.querySelector('.x-price-primary span');
if (ebayPrice) {
price = parseFloat(ebayPrice.textContent.replace(/[^0-9.]/g, ''));
}
break;
}
if (price) {
return { ...product, price };
}
} catch (error) {
console.error('Fetch error:', error);
}
return null;
}
function sendPriceDropNotification(product, newPrice) {
chrome.storage.local.get('settings', (result) => {
if (result.settings?.notificationsEnabled) {
const priceDrop = product.priceHistory[product.priceHistory.length - 2].price - newPrice;
const percentDrop = ((priceDrop / product.priceHistory[product.priceHistory.length - 2].price) * 100).toFixed(0);
chrome.notifications.create({
type: 'basic',
iconUrl: NOTIFICATION_ICON,
title: '💰 Price Drop Alert!',
message: `${product.title.substring(0, 50)}... dropped by ${percentDown}%! Now: $${newPrice}`,
priority: 1
});
}
});
}
// Handle messages from popup
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'getTrackedProducts') {
chrome.storage.local.get('trackedProducts', (result) => {
sendResponse(result.trackedProducts || []);
});
return true;
}
if (request.action === 'removeProduct') {
chrome.storage.local.get('trackedProducts', (result) => {
const products = result.trackedProducts || [];
const filtered = products.filter(p => p.url !== request.url);
chrome.storage.local.set({ trackedProducts: filtered });
sendResponse(filtered);
});
return true;
}
if (request.action === 'setTargetPrice') {
chrome.storage.local.get('trackedProducts', (result) => {
const products = result.trackedProducts || [];
const product = products.find(p => p.url === request.url);
if (product) {
product.targetPrice = request.targetPrice;
chrome.storage.local.set({ trackedProducts: products });
}
sendResponse(products);
});
return true;
}
});
The background worker handles several critical functions. First, it schedules periodic price checks using Chrome’s alarm API. Second, it fetches updated prices from product URLs. Third, it maintains price history and detects price drops. Finally, it sends native notifications when prices fall below the user’s target threshold.
Building the Popup Interface
The popup is the user-facing component of our price tracker chrome extension. It displays tracked products, allows users to set target prices, and provides access to settings. Let us create a clean, functional popup.
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Price Watch</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div class="container">
<header>
<h1>📊 Price Watch</h1>
<p class="subtitle">Track prices across your favorite stores</p>
</header>
<div id="products-list" class="products-list">
<!-- Products will be dynamically inserted here -->
</div>
<div id="empty-state" class="empty-state" style="display: none;">
<p>No products tracked yet!</p>
<p class="hint">Visit an Amazon or e-commerce product page and click "Track Price"</p>
</div>
<footer>
<div class="settings">
<label>
<input type="checkbox" id="notifications-toggle" checked>
Enable notifications
</label>
</div>
</footer>
</div>
<script src="popup.js"></script>
</body>
</html>
popup.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
width: 350px;
min-height: 400px;
background: #f5f5f5;
}
.container {
padding: 16px;
}
header {
text-align: center;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid #e0e0e0;
}
header h1 {
font-size: 20px;
color: #333;
margin-bottom: 4px;
}
.subtitle {
font-size: 12px;
color: #666;
}
.products-list {
max-height: 300px;
overflow-y: auto;
}
.product-card {
background: white;
border-radius: 8px;
padding: 12px;
margin-bottom: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.product-header {
display: flex;
gap: 10px;
margin-bottom: 8px;
}
.product-image {
width: 50px;
height: 50px;
object-fit: contain;
border-radius: 4px;
background: #f9f9f9;
}
.product-info {
flex: 1;
min-width: 0;
}
.product-title {
font-size: 13px;
font-weight: 600;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: 4px;
}
.product-retailer {
font-size: 11px;
color: #888;
text-transform: capitalize;
}
.price-section {
display: flex;
justify-content: space-between;
align-items: center;
}
.current-price {
font-size: 18px;
font-weight: 700;
color: #4CAF50;
}
.price-change {
font-size: 12px;
padding: 2px 8px;
border-radius: 10px;
}
.price-change.down {
background: #ffebee;
color: #c62828;
}
.price-change.up {
background: #e8f5e9;
color: #2e7d32;
}
.target-price-section {
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #f0f0f0;
display: flex;
align-items: center;
gap: 8px;
}
.target-price-section label {
font-size: 11px;
color: #666;
}
.target-price-input {
width: 80px;
padding: 4px 8px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 12px;
}
.remove-btn {
background: none;
border: none;
color: #999;
cursor: pointer;
font-size: 16px;
padding: 4px;
}
.remove-btn:hover {
color: #c62828;
}
.empty-state {
text-align: center;
padding: 40px 20px;
color: #666;
}
.empty-state .hint {
font-size: 12px;
color: #999;
margin-top: 8px;
}
footer {
margin-top: 16px;
padding-top: 12px;
border-top: 1px solid #e0e0e0;
}
.settings label {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: #666;
cursor: pointer;
}
popup.js
document.addEventListener('DOMContentLoaded', () => {
loadProducts();
setupEventListeners();
});
function loadProducts() {
chrome.runtime.sendMessage({ action: 'getTrackedProducts' }, (products) => {
const container = document.getElementById('products-list');
const emptyState = document.getElementById('empty-state');
if (!products || products.length === 0) {
container.style.display = 'none';
emptyState.style.display = 'block';
return;
}
container.style.display = 'block';
emptyState.style.display = 'none';
container.innerHTML = products.map(product => {
const priceHistory = product.priceHistory || [];
const currentPrice = product.price;
const previousPrice = priceHistory.length > 1 ?
priceHistory[priceHistory.length - 2].price : currentPrice;
const priceChange = currentPrice - previousPrice;
const priceChangeClass = priceChange < 0 ? 'down' : priceChange > 0 ? 'up' : '';
const priceChangeText = priceChange !== 0 ?
`${priceChange > 0 ? '+' : ''}$${priceChange.toFixed(2)}` : '';
return `
<div class="product-card" data-url="${product.url}">
<div class="product-header">
${product.image ? `<img src="${product.image}" class="product-image" alt="">` : ''}
<div class="product-info">
<div class="product-title" title="${product.title}">${product.title}</div>
<div class="product-retailer">${product.retailer}</div>
</div>
</div>
<div class="price-section">
<span class="current-price">$${currentPrice.toFixed(2)}</span>
${priceChangeText ? `<span class="price-change ${priceChangeClass}">${priceChangeText}</span>` : ''}
</div>
<div class="target-price-section">
<label>Alert me at:</label>
<input type="number" class="target-price-input"
value="${product.targetPrice || ''}"
placeholder="Target $"
step="0.01"
data-url="${product.url}">
<button class="remove-btn" data-url="${product.url}" title="Remove">🗑️</button>
</div>
</div>
`;
}).join('');
});
}
function setupEventListeners() {
// Remove product buttons
document.getElementById('products-list').addEventListener('click', (e) => {
if (e.target.classList.contains('remove-btn')) {
const url = e.target.dataset.url;
chrome.runtime.sendMessage({ action: 'removeProduct', url }, () => {
loadProducts();
});
}
});
// Target price inputs
document.getElementById('products-list').addEventListener('change', (e) => {
if (e.target.classList.contains('target-price-input')) {
const url = e.target.dataset.url;
const targetPrice = parseFloat(e.target.value);
if (!isNaN(targetPrice) && targetPrice > 0) {
chrome.runtime.sendMessage({
action: 'setTargetPrice',
url,
targetPrice
}, () => {
loadProducts();
});
}
}
});
// Notifications toggle
document.getElementById('notifications-toggle').addEventListener('change', (e) => {
chrome.storage.local.get('settings', (result) => {
const settings = result.settings || {};
settings.notificationsEnabled = e.target.checked;
chrome.storage.local.set({ settings });
});
});
// Load notification setting
chrome.storage.local.get('settings', (result) => {
if (result.settings) {
document.getElementById('notifications-toggle').checked =
result.settings.notificationsEnabled !== false;
}
});
}
Testing Your Price Tracker Extension
Now that we have built all the components, it is time to test your chrome extension price tracker. Open Chrome and navigate to chrome://extensions/. Enable “Developer mode” in the top right corner, then click “Load unpacked” and select your project folder.
Visit any supported product page, such as an Amazon product. You should see the floating “Track Price” button appear in the bottom right corner. Click it to add the product to your tracking list. Then click the extension icon in your browser toolbar to open the popup and see your tracked products.
Test the target price feature by entering a target price below the current price. The extension will check periodically and send a notification when the price drops to your target. This is the core functionality that makes a price drop notification chrome extension valuable to users.
Advanced Features and Improvements
While our basic chrome extension price monitor is functional, there are many ways to enhance it. Consider adding support for more retailers beyond Amazon, Walmart, and eBay. Each new retailer requires a new extractor function in the content script.
Another valuable improvement is price history visualization. You could use a charting library to display price trends directly in the popup, helping users see if they are getting a good deal or should wait longer.
You might also want to add cloud synchronization. Using Chrome’s sync storage, users could keep their tracked products synchronized across multiple devices. This would significantly improve the user experience for people who browse on different computers.
Email notifications could also be valuable. While Chrome notifications work well, some users prefer email alerts that persist until they take action. You could integrate with a service like SendGrid or Sendinblue to handle email delivery.
Finally, consider adding deal-finding features. Users could set preferences for categories, price ranges, and stores, and the extension could actively search for deals matching those criteria. This transforms the extension from a passive tracker into an active shopping assistant.
Best Practices for Price Tracker Extensions
When building a chrome extension price tracker, there are several best practices you should follow. First, respect user privacy. Only collect the data necessary for the extension to function, and be transparent about what data you collect.
Second, handle errors gracefully. Network requests to retailer websites will sometimes fail. Your extension should handle these failures gracefully, retry automatically, and inform users if there are issues with their tracked products.
Third, be respectful of retailer terms of service. Automated price checking may violate some retailer’s terms. Consider adding rate limiting to avoid overwhelming retailer servers, and always comply with robots.txt and terms of service.
Fourth, keep your extension lightweight. Users install extensions that slow down their browser with hesitation. Optimize your code, use lazy loading where appropriate, and keep the extension’s memory footprint small.
Finally, maintain your extension actively. E-commerce websites frequently change their HTML structure, which can break your extractors. Stay on top of these changes and release updates promptly to ensure your price tracker chrome extension continues to work reliably.
Conclusion
Congratulations! You have now built a complete chrome extension price tracker with support for Amazon, Walmart, and eBay. Your extension can extract product information from these retailers, store tracked products, periodically check for price updates, and send notifications when prices drop.
This project demonstrates several important skills for Chrome extension development: working with content scripts to interact with web pages, using service workers for background processing, implementing persistent storage, and creating native notifications. These skills transfer directly to other extension projects you might want to build.
The chrome extension price tracker you have created is a valuable tool that solves a real problem for millions of online shoppers. With some additional features and polish, it has the potential to become a popular extension in the Chrome Web Store. Consider adding more retailers, price history charts, and cloud sync to make it even more useful.
Remember that e-commerce websites change frequently, so ongoing maintenance will be necessary to keep your extension working. Stay responsive to user feedback, monitor for extractor failures, and continue improving your amazon price tracker chrome extension over time.
Start testing your extension today, and happy tracking!