Skip to main content
Back to Guides

Use Cases

Ecommerce Price Monitoring: Build Your Own Price Tracker

Track competitor prices, monitor product availability, and get automated alerts on price changes. Learn how to build a comprehensive price monitoring system.

14 min readUpdated January 15, 2025

Why Price Monitoring Matters

In the competitive world of ecommerce, pricing strategy can make or break your business. Price monitoring gives you the intelligence needed to optimize your pricing, protect margins, and capture more market share.

Competitive Intelligence

Know exactly what your competitors are charging. Identify pricing gaps and opportunities to win price-sensitive customers.

Dynamic Pricing

Adjust your prices in real-time based on market conditions, demand, and competitor movements.

MAP Enforcement

Monitor Minimum Advertised Price (MAP) compliance across your distribution network and resellers.

Revenue Optimization

Find the optimal price point that maximizes revenue without sacrificing profit margins.

Price Monitoring Architecture

A robust price monitoring system consists of several components working together:

1

Product URL Management

Maintain a database of products to monitor with their competitor URLs.

2

Scheduled Scraping

Run scraping jobs on a schedule (hourly, daily) to collect current pricing data.

3

Data Extraction & Parsing

Extract prices, availability, and promotions from product pages using AI-powered extraction.

4

Price History Storage

Store all price observations with timestamps for historical analysis and trend detection.

5

Change Detection & Alerting

Compare current prices with previous observations and trigger alerts for significant changes.

Extracting Price Data

Price extraction is challenging because every ecommerce site displays prices differently. AI-powered extraction handles this variability automatically.

Basic Price Extraction

const response = await fetch('https://api.robotscraping.com/extract', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': process.env.API_KEY
  },
  body: JSON.stringify({
    url: 'https://example.com/product/laptop-123',
    fields: [
      'product_title',
      'current_price',
      'original_price',
      'currency',
      'availability',
      'in_stock',
      'discount_percentage',
      'promotion_text'
    ],
    instructions: 'Extract the main product title, the current selling price, any crossed-out original price, the currency symbol, whether the item is in stock, and any promotional text or discount badges.'
  })
});

const priceData = await response.json();
// {
//   product_title: "Dell XPS 15 Laptop",
//   current_price: "999.99",
//   original_price: "1299.99",
//   currency: "$",
//   availability: "In Stock",
//   in_stock: true,
//   discount_percentage: "23% off",
//   promotion_text: "Flash Sale - Limited Time"
// }

Handling Variant Prices

Many products have variants (size, color) with different prices. Extract all variant prices for complete monitoring.

body: JSON.stringify({
  url: 'https://example.com/product/tshirt',
  fields: ['variants'],
  instructions: 'Extract all product variants. For each variant, return the size, color, price, and whether it is in stock. Return as an array of objects.'
})

Price Normalization

Always normalize prices to a standard format (numeric value without currency symbols) for storage and comparison. Handle international currencies by converting to a base currency using current exchange rates.

Storing Price History

Building a price history database enables trend analysis and informed pricing decisions. Here's how to structure your data:

Database Schema

-- Products table (items you're tracking)
CREATE TABLE products (
  id INTEGER PRIMARY KEY,
  sku TEXT,
  name TEXT,
  category TEXT,
  brand TEXT,
  created_at TIMESTAMP
);

-- Competitor URLs for each product
CREATE TABLE competitor_urls (
  id INTEGER PRIMARY KEY,
  product_id INTEGER,
  competitor_name TEXT,
  url TEXT UNIQUE,
  is_active BOOLEAN,
  FOREIGN KEY (product_id) REFERENCES products(id)
);

-- Price observations (time series data)
CREATE TABLE price_observations (
  id INTEGER PRIMARY KEY,
  competitor_url_id INTEGER,
  price_cents INTEGER,
  currency TEXT,
  original_price_cents INTEGER,
  availability TEXT,
  in_stock BOOLEAN,
  promotion_text TEXT,
  observed_at TIMESTAMP,
  raw_html_reference TEXT,
  FOREIGN KEY (competitor_url_id) REFERENCES competitor_urls(id)
);

-- Price change alerts
CREATE TABLE price_alerts (
  id INTEGER PRIMARY KEY,
  competitor_url_id INTEGER,
  old_price_cents INTEGER,
  new_price_cents INTEGER,
  change_percent REAL,
  alert_type TEXT,
  sent_at TIMESTAMP,
  acknowledged BOOLEAN
);

Inserting Price Observations

async function recordPriceObservation(db, competitorUrlId, priceData) {
  const priceCents = Math.round(parseFloat(priceData.current_price) * 100);
  const originalPriceCents = priceData.original_price
    ? Math.round(parseFloat(priceData.original_price) * 100)
    : null;

  await db.prepare(`
    INSERT INTO price_observations (
      competitor_url_id, price_cents, currency,
      original_price_cents, availability, in_stock,
      promotion_text, observed_at
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
  `).bind(
    competitorUrlId,
    priceCents,
    priceData.currency || 'USD',
    originalPriceCents,
    priceData.availability || 'Unknown',
    priceData.in_stock ?? true,
    priceData.promotion_text || null,
    Date.now()
  ).run();
}

Detecting Price Changes

The value of price monitoring comes from detecting and responding to changes. Implement smart change detection that filters noise and alerts on significant movements.

Change Detection Logic

async function detectPriceChanges(db, threshold = 0.05) {
  // Get the most recent price for each competitor URL
  const latestPrices = await db.prepare(`
    SELECT DISTINCT ON (competitor_url_id)
      competitor_url_id,
      price_cents,
      observed_at
    FROM price_observations
    ORDER BY competitor_url_id, observed_at DESC
  `).all();

  // Get the previous price for comparison
  for (const latest of latestPrices) {
    const previous = await db.prepare(`
      SELECT price_cents
      FROM price_observations
      WHERE competitor_url_id = ?
        AND observed_at < ?
      ORDER BY observed_at DESC
      LIMIT 1
    `).bind(latest.competitor_url_id, latest.observed_at).first();

    if (previous) {
      const changePercent =
        (latest.price_cents - previous.price_cents) / previous.price_cents;

      if (Math.abs(changePercent) >= threshold) {
        await createPriceAlert(db, {
          competitorUrlId: latest.competitor_url_id,
          oldPrice: previous.price_cents,
          newPrice: latest.price_cents,
          changePercent: changePercent * 100,
          alertType: changePercent < 0 ? 'price_drop' : 'price_increase'
        });
      }
    }
  }
}

async function createPriceAlert(db, alertData) {
  await db.prepare(`
    INSERT INTO price_alerts (
      competitor_url_id, old_price_cents, new_price_cents,
      change_percent, alert_type, sent_at, acknowledged
    ) VALUES (?, ?, ?, ?, ?, ?, ?)
  `).bind(
    alertData.competitorUrlId,
    alertData.oldPrice,
    alertData.newPrice,
    alertData.changePercent,
    alertData.alertType,
    Date.now(),
    false
  ).run();
}

Advanced: Anomaly Detection

Use statistical methods to detect unusual price patterns beyond simple percentage changes.

// Detect prices that deviate significantly from historical average
async function detectPriceAnomalies(db, stdDevThreshold = 2) {
  const stats = await db.prepare(`
    SELECT
      competitor_url_id,
      AVG(price_cents) as mean_price,
      STDDEV(price_cents) as std_dev,
      MAX(observed_at) as last_observed
    FROM price_observations
    WHERE observed_at > datetime('now', '-30 days')
    GROUP BY competitor_url_id
  `).all();

  for (const stat of stats) {
    const latest = await db.prepare(`
      SELECT price_cents FROM price_observations
      WHERE competitor_url_id = ?
      ORDER BY observed_at DESC LIMIT 1
    `).bind(stat.competitor_url_id).first();

    if (latest) {
      const zScore = (latest.price_cents - stat.mean_price) / stat.std_dev;
      if (Math.abs(zScore) > stdDevThreshold) {
        // Flag as anomalous
        console.log(`Anomaly detected for URL ${stat.competitor_url_id}: Z-score = ${zScore.toFixed(2)}`);
      }
    }
  }
}

Setting Up Scheduled Monitoring

Automated monitoring requires scheduled scraping. Use cron expressions to define when to check prices.

Creating a Monitoring Schedule

// Create a schedule for price monitoring
const response = await fetch('https://api.robotscraping.com/schedules', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': process.env.API_KEY
  },
  body: JSON.stringify({
    name: 'daily-price-monitoring',
    cron: '0 */4 * * *', // Every 4 hours
    urls: [
      'https://amazon.com/dp/B08X5...',
      'https://walmart.com/ip/12345...',
      'https://bestbuy.com/site/...'
    ],
    config: {
      fields: ['current_price', 'original_price', 'availability', 'in_stock'],
      instructions: 'Extract current price, original price if shown, and stock availability.'
    },
    webhook_url: 'https://your-app.com/api/price-webhook'
  })
});

Handling Webhook Results

// Your webhook handler receives extraction results
app.post('/api/price-webhook', async (req, res) => {
  const { job_id, url, result, timestamp } = req.body;

  // Verify webhook signature
  const signature = req.headers['x-webhook-signature'];
  if (!verifySignature(signature, req.body, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // Store the price observation
  const competitorUrl = await findCompetitorUrl(url);
  await recordPriceObservation(db, competitorUrl.id, result);

  // Check for price changes
  await detectPriceChanges(db);

  res.sendStatus(200);
});

Price Monitoring Best Practices

1. Respect Rate Limits

Don't scrape too frequently. Hourly checks are usually sufficient for most products. High-frequency scraping can trigger blocks.

2. Use Proxies

Distribute requests across multiple IP addresses to avoid detection. Residential proxies are most effective for ecommerce sites.

body: JSON.stringify({
  url: 'https://amazon.com/dp/B08X5...',
  fields: ['price', 'availability'],
  options: {
    proxy: {
      type: 'residential',
      country: 'us'
    }
  }
})

3. Handle Dynamic Pricing

Some sites change prices based on user behavior, location, or device. Use consistent scraping parameters.

4. Monitor Availability

Stock availability is as important as price. Track out-of-stock events to identify demand patterns.

5. Validate Data Quality

Implement validation to catch bad data. Prices should be positive numbers within reasonable ranges for the product category.

Using RobotScraping.com for Price Monitoring

RobotScraping.com simplifies price monitoring with built-in scheduling, proxy rotation, and AI-powered extraction that works across all major ecommerce sites.

// Complete price monitoring workflow
const products = [
  { sku: 'LAPTOP-001', url: 'https://amazon.com/dp/B08X5...' },
  { sku: 'LAPTOP-001', url: 'https://bestbuy.com/site/...' },
  { sku: 'PHONE-002', url: 'https://amazon.com/dp/B09Y4...' }
];

// Create a schedule for monitoring
await fetch('https://api.robotscraping.com/schedules', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': process.env.API_KEY
  },
  body: JSON.stringify({
    name: 'ecommerce-price-monitor',
    cron: '0 */2 * * *', // Every 2 hours
    urls: products.map(p => p.url),
    config: {
      fields: ['product_title', 'current_price', 'original_price', 'in_stock', 'prime_eligible'],
      options: {
        proxy: { type: 'residential', country: 'us' }
      }
    },
    webhook_url: 'https://your-app.com/api/price-alerts'
  })
});

Related Guides