How to Monitor Competitor Prices Automatically

Published July 24, 2026 · 6 min read

Manually checking competitor prices is a losing game. By the time you open 20 tabs, copy-paste numbers into a spreadsheet, and spot a change, your competitor already changed prices again. The only way to win is automation.

In this guide, I'll show you how to build a price monitoring system that scrapes competitor product pages, detects price changes, and alerts you — all running on a schedule with zero manual effort.

What You'll Build

A Node.js script that:

  1. Fetches product pages from a list of competitor URLs
  2. Extracts product name, price, and availability
  3. Compares against previously stored prices
  4. Alerts you when prices change
  5. Runs automatically on a cron schedule

Step 1: Define Your Targets

Start with a focused list. 5-10 competitor products is enough to prove value before scaling:

// targets.json
[
  { "id": "comp-a-widget", "name": "Widget Pro", "competitor": "CompA", "url": "https://competitor-a.com/products/widget-pro" },
  { "id": "comp-b-widget", "name": "Widget Pro", "competitor": "CompB", "url": "https://competitor-b.com/products/widget-pro" },
  { "id": "comp-a-gadget", "name": "Super Gadget", "competitor": "CompA", "url": "https://competitor-a.com/products/super-gadget" }
]

Step 2: Extract Prices with ExtractAPI

Instead of building and maintaining a headless browser infrastructure, use ExtractAPI. One POST request per URL — it handles browser rendering, JavaScript execution, and returns structured JSON:

const EXTRACT_API_KEY = process.env.EXTRACT_API_KEY;

async function extractPrice(target) {
  const res = await fetch('https://extractapi.app/v1/extract', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${EXTRACT_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url: target.url,
      selector: '.product-price, .price, [data-price]',
      waitFor: '.product-price, .price',
      javascript: true
    })
  });

  const data = await res.json();
  if (data.status !== 'ok') throw new Error(`Extraction failed: ${data.error}`);

  // Parse price from text (handles "$49.99", "49,99 €", "$ 49.99", etc.)
  const priceText = data.data.selectorText || data.data.h1 || '';
  const priceMatch = priceText.match(/[\d,.]+/);
  return {
    id: target.id,
    name: target.name,
    competitor: target.competitor,
    price: priceMatch ? parseFloat(priceMatch[0].replace(',', '')) : null,
    currency: priceText.includes('$') ? 'USD' : priceText.includes('€') ? 'EUR' : 'unknown',
    title: data.data.title,
    extractedAt: new Date().toISOString()
  };
}

Step 3: Detect Changes

Store previous prices in a simple JSON file and compare:

const fs = require('fs/promises');

async function detectChanges(currentPrices) {
  let previous = {};
  try {
    previous = JSON.parse(await fs.readFile('price-history.json', 'utf-8'));
  } catch { /* first run, no history */ }

  const changes = [];

  for (const item of currentPrices) {
    const prev = previous[item.id];
    if (!prev) {
      changes.push({ ...item, change: 'new', previousPrice: null });
    } else if (prev.price !== item.price) {
      const direction = item.price < prev.price ? 'decrease' : 'increase';
      const pctChange = ((item.price - prev.price) / prev.price * 100).toFixed(1);
      changes.push({ ...item, change: direction, previousPrice: prev.price, pctChange });
    }
  }

  // Save new prices
  const newHistory = {};
  for (const item of currentPrices) newHistory[item.id] = item;
  await fs.writeFile('price-history.json', JSON.stringify(newHistory, null, 2));

  return changes;
}

Step 4: Send Alerts

When prices change, you want to know immediately. Email, Slack, or Telegram are all good options:

async function sendAlert(changes) {
  if (changes.length === 0) {
    console.log('No price changes detected.');
    return;
  }

  const message = changes.map(c =>
    `${c.change === 'decrease' ? '🔻' : '🔺'} ${c.competitor} — ${c.name}\n` +
    `   ${c.change === 'decrease' ? 'Dropped' : 'Increased'} from $${c.previousPrice} to $${c.price} (${c.pctChange}%)\n` +
    `   URL: ${c.url}`
  ).join('\n\n');

  // Send to Slack webhook (or Telegram, email, Discord — your choice)
  await fetch(process.env.SLACK_WEBHOOK_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ text: `📊 Price Changes Detected\n\n${message}` })
  });

  console.log(`Alert sent: ${changes.length} price changes`);
}

Step 5: Automate with Cron

Wire it up to run on a schedule:

// monitor.js — the full script combined
const TARGETS = require('./targets.json');

async function main() {
  console.log(`Starting price check: ${new Date().toISOString()}`);

  const currentPrices = [];
  for (const target of TARGETS) {
    try {
      const result = await extractPrice(target);
      currentPrices.push(result);
      console.log(`  ${target.competitor} — ${target.name}: $${result.price}`);
    } catch (err) {
      console.error(`  Failed: ${target.competitor} — ${target.name}: ${err.message}`);
    }
    // Rate limit: 1 request/second to stay within free tier limits
    await new Promise(r => setTimeout(r, 1000));
  }

  const changes = await detectChanges(currentPrices);
  await sendAlert(changes);
}

main().catch(console.error);

Add to crontab to run twice daily:

# crontab -e
0 8,20 * * * cd /app && node monitor.js >> /var/log/price-monitor.log 2>&1

Why This Approach Works

ApproachBuild TimeMaintenanceReliability
DIY headless browserWeeksHigh (browser updates, anti-bot changes)Medium
Scraping API (ExtractAPI)HoursLow (API handles rendering)High
Manual checking0Extreme (hours/week)Low (missed changes)
Pro tip: Start with 5 products, one pricing source, and Slack alerts. You'll have a working system in an afternoon. Add more competitors and alert channels once you've validated the data quality.

Handling Edge Cases

Real-world product pages throw curveballs. Here's how to handle the common ones:

Bottom line: A price monitoring system that takes an afternoon to build and costs $9/month to run can save you thousands in missed pricing opportunities. ExtractAPI handles the hard part (browser rendering and extraction) so you can focus on the business logic.
Start Monitoring Prices — $9/month