Claude Skills Guide

Chrome Extension Used Item Price Checker: A Developer’s Guide

Price comparison for used items presents unique challenges that differ from new product pricing. Multiple marketplaces, varying item conditions, and inconsistent listing formats make automated price checking complex but valuable. This guide covers building Chrome extensions that help developers and power users track used item prices across platforms.

Why Build a Used Item Price Checker Extension

The secondary market for used goods has grown substantially with platforms like eBay, Facebook Marketplace, Poshmark, Mercari, and OfferUp. Each platform operates independently with different search APIs, listing formats, and pricing conventions. A well-designed Chrome extension can aggregate prices across these sources, helping users identify fair market values and spotting underpriced listings.

For developers, this project combines several interesting technical challenges: cross-origin API requests, data normalization, price parsing from unstructured text, and creating intuitive UI overlays. The extension architecture also demonstrates practical patterns applicable to other comparison tools.

Core Architecture

A price checker extension typically consists of three main components:

Content scripts inject JavaScript into marketplace pages to extract listing data. Each marketplace requires custom extraction logic because HTML structures differ significantly.

Background service worker handles cross-origin requests, caches results, and coordinates communication between content scripts and any external APIs.

Popup or side panel displays price comparisons to users in real-time.

// manifest.json - Extension configuration
{
  "manifest_version": 3,
  "name": "Used Item Price Checker",
  "version": "1.0.0",
  "permissions": ["activeTab", "storage"],
  "host_permissions": [
    "https://*.ebay.com/*",
    "https://*.facebook.com/*",
    "https://*.poshmark.com/*"
  ],
  "content_scripts": [{
    "matches": ["*://*.ebay.com/*", "*://*.facebook.com/*"],
    "js": ["content-script.js"]
  }],
  "background": {
    "service_worker": "background.js"
  }
}

Extracting Listing Data from Marketplaces

The most challenging aspect involves extracting structured data from marketplace pages. Here’s a practical approach using mutation observers to handle dynamic content:

// content-script.js - Extract listing data from eBay
function extractListingData() {
  const listings = document.querySelectorAll('.s-item');
  return Array.from(listings).map(item => {
    const title = item.querySelector('.s-item__title')?.textContent?.trim();
    const priceElement = item.querySelector('.s-item__price');
    const price = parsePrice(priceElement?.textContent);
    const condition = item.querySelector('.s-item__subtitle')?.textContent;
    const url = item.querySelector('.s-item__link')?.href;
    
    return { title, price, condition, url };
  }).filter(item => item.price > 0);
}

function parsePrice(text) {
  // Handle various price formats: "$25.00", "$25", "US $25.00"
  const match = text?.match(/[\d,]+\.?\d*/);
  return match ? parseFloat(match[0].replace(',', '')) : null;
}

// Observe DOM changes for dynamic listings
const observer = new MutationObserver(() => {
  const listings = extractListingData();
  if (listings.length > 0) {
    chrome.runtime.sendMessage({ 
      type: 'LISTINGS_EXTRACTED', 
      data: listings,
      source: window.location.hostname 
    });
  });
});

observer.observe(document.body, { 
  childList: true, 
  subtree: true,
  attributes: false 
});

Building the Price Comparison Engine

Once you have listing data from multiple sources, normalize and compare prices to generate meaningful insights. The comparison logic should account for item condition, shipping costs, and platform fees.

// background.js - Price comparison logic
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'LISTINGS_EXTRACTED') {
    const normalizedListings = normalizeListings(message.data, message.source);
    const analysis = analyzePrices(normalizedListings);
    
    // Store in extension storage for popup access
    chrome.storage.local.set({
      currentAnalysis: {
        listings: normalizedListings,
        statistics: analysis,
        timestamp: Date.now()
      }
    });
    
    sendResponse({ analyzed: true });
  }
  return true;
});

function normalizeListings(listings, source) {
  return listings.map(listing => ({
    title: listing.title,
    price: listing.price,
    condition: extractCondition(listing.condition, source),
    source: source,
    url: listing.url,
    shipping: estimateShipping(listing.price, source)
  }));
}

function analyzePrices(listings) {
  const prices = listings.map(l => l.price + l.shipping).filter(p => p > 0);
  if (prices.length === 0) return null;
  
  const sorted = [...prices].sort((a, b) => a - b);
  return {
    average: prices.reduce((a, b) => a + b, 0) / prices.length,
    median: sorted[Math.floor(sorted.length / 2)],
    min: sorted[0],
    max: sorted[sorted.length - 1],
    count: prices.length
  };
}

function extractCondition(conditionText, source) {
  if (!conditionText) return 'unknown';
  const text = conditionText.toLowerCase();
  
  if (text.includes('new') || text.includes('nwt')) return 'new';
  if (text.includes('like new') || text.includes('lnwt')) return 'like new';
  if (text.includes('good')) return 'good';
  if (text.includes('fair') || text.includes('poor')) return 'fair';
  return 'used';
}

Creating the User Interface

The popup or side panel should display price statistics and highlight potential deals. Use a clean, information-dense design that doesn’t obstruct the underlying marketplace:

// popup.js - Display price analysis
document.addEventListener('DOMContentLoaded', async () => {
  const { currentAnalysis } = await chrome.storage.local.get('currentAnalysis');
  
  if (!currentAnalysis || !currentAnalysis.statistics) {
    document.getElementById('results').innerHTML = '<p>No price data available</p>';
    return;
  }
  
  const { statistics, listings } = currentAnalysis;
  
  // Calculate potential deals (items below median)
  const deals = listings
    .filter(l => (l.price + l.shipping) < statistics.median)
    .sort((a, b) => (a.price + a.shipping) - (b.price + b.shipping))
    .slice(0, 5);
  
  renderStatistics(statistics);
  renderDeals(deals);
});

function renderStatistics(stats) {
  const container = document.getElementById('statistics');
  container.innerHTML = `
    <div class="stat">
      <span class="label">Average</span>
      <span class="value">$${stats.average.toFixed(2)}</span>
    </div>
    <div class="stat">
      <span class="label">Median</span>
      <span class="value">$${stats.median.toFixed(2)}</span>
    </div>
    <div class="stat">
      <span class="label">Listings</span>
      <span class="value">${stats.count}</span>
    </div>
  `;
}

Handling API Rate Limits and Data Quality

Real-world implementations face practical challenges that require thoughtful solutions:

Rate limiting prevents your extension from getting blocked by marketplaces. Implement exponential backoff and cache results aggressively. Store price data with timestamps and refresh only when necessary.

Data validation ensures you aren’t comparing incompatible items. Use fuzzy string matching on titles to filter listings that are likely different products. A simple Jaccard similarity check on tokenized titles works well:

function calculateSimilarity(title1, title2) {
  const tokens1 = new Set(title1.toLowerCase().split(/\s+/));
  const tokens2 = new Set(title2.toLowerCase().split(/\s+/));
  const intersection = new Set([...tokens1].filter(x => tokens2.has(x)));
  const union = new Set([...tokens1, ...tokens2]);
  return intersection.size / union.size;
}

Error handling becomes critical when dealing with multiple external sources. Wrap API calls in try-catch blocks and provide graceful degradation when data unavailable.

Extension Deployment Considerations

When distributing your extension, ensure compliance with each marketplace’s terms of service. Some platforms explicitly prohibit automated data collection. Review their robots.txt files and developer policies before deploying.

Performance matters for extensions that inject content scripts. Minimize DOM queries, use event delegation, and remove observers when pages navigate away. Users notice sluggish behavior in their browser.

Privacy-conscious implementations avoid sending listing data to external servers. Process everything locally within the extension’s context, only using storage APIs for persistence.

Conclusion

Building a used item price checker Chrome extension combines web scraping, data normalization, and UI development into a practical project with real utility. The patterns demonstrated here—content script injection, message passing between components, and storage-backed caching—transfer directly to other comparison tools.

Start by supporting a single marketplace thoroughly before expanding to additional sources. Focus on accurate price extraction and condition detection first, then add comparison features. The resulting extension provides genuine value for anyone buying or selling used items regularly.

Built by theluckystrike — More at zovo.one