Back to Blog
January 29, 2024
E-commerce Team
3 min read
E-commerce

Build an E-commerce Price Monitoring System with Zapserp

Create an automated price tracking system to monitor competitor prices, track product availability, and send alerts when prices drop. Perfect for e-commerce businesses and deal hunters.

price-monitoringe-commerceautomationcompetitive-analysisalerts

Build an E-commerce Price Monitoring System with Zapserp

Stay competitive in the e-commerce landscape by monitoring competitor prices automatically. This guide shows you how to build a comprehensive price tracking system that monitors products across multiple platforms and sends alerts when opportunities arise.

What We're Building

A smart price monitoring system that:

  • Tracks competitor prices across multiple sites
  • Monitors product availability and stock status
  • Sends alerts when prices drop below thresholds
  • Generates competitive analysis reports
  • Supports multiple product categories

Core Price Monitoring Engine

const { Zapserp } = require('zapserp')

class PriceMonitor {
  constructor(apiKey) {
    this.zapserp = new Zapserp({ apiKey })
    this.priceHistory = new Map()
    this.alertThresholds = new Map()
  }

  async trackProduct(productName, targetPrice = null) {
    const searchQueries = [
      `${productName} buy online price`,
      `${productName} shop compare prices`,
      `${productName} best deal discount`
    ]

    const allPrices = []

    for (const query of searchQueries) {
      try {
        const searchResults = await this.zapserp.search({
          query,
          engines: ['google', 'bing'],
          limit: 10,
          country: 'us'
        })

        // Filter for e-commerce sites
        const ecommerceResults = this.filterEcommerceSites(searchResults.results)
        
        if (ecommerceResults.length > 0) {
          const urls = ecommerceResults.slice(0, 5).map(result => result.url)
          const contentResults = await this.zapserp.readerBatch({ urls })

          contentResults.results.forEach(content => {
            if (content && content.content) {
              const priceData = this.extractPriceData(content)
              if (priceData.price > 0) {
                allPrices.push({
                  ...priceData,
                  source: this.extractStoreName(content.url),
                  url: content.url,
                  timestamp: new Date().toISOString(),
                  productName
                })
              }
            }
          })
        }
      } catch (error) {
        console.error(`Price tracking failed for query: ${query}`, error)
      }
    }

    // Update price history
    const currentPrices = this.deduplicateByStore(allPrices)
    this.updatePriceHistory(productName, currentPrices)

    // Check for alerts
    if (targetPrice) {
      this.checkPriceAlerts(productName, currentPrices, targetPrice)
    }

    return {
      product: productName,
      currentPrices: currentPrices.sort((a, b) => a.price - b.price),
      lowestPrice: Math.min(...currentPrices.map(p => p.price)),
      averagePrice: this.calculateAverage(currentPrices.map(p => p.price)),
      priceRange: {
        min: Math.min(...currentPrices.map(p => p.price)),
        max: Math.max(...currentPrices.map(p => p.price))
      },
      totalStores: currentPrices.length
    }
  }

  filterEcommerceSites(results) {
    const ecommerceDomains = [
      'amazon.com', 'ebay.com', 'walmart.com', 'target.com',
      'bestbuy.com', 'costco.com', 'homedepot.com', 'lowes.com',
      'newegg.com', 'bhphotovideo.com', 'adorama.com', 'etsy.com',
      'aliexpress.com', 'shopify.com', 'overstock.com'
    ]

    return results.filter(result => 
      ecommerceDomains.some(domain => result.url.includes(domain)) ||
      this.containsPriceIndicators(result.snippet)
    )
  }

  containsPriceIndicators(text) {
    const priceIndicators = ['$', 'price:', 'buy now', 'add to cart', 'in stock', 'free shipping']
    return priceIndicators.some(indicator => 
      text.toLowerCase().includes(indicator.toLowerCase())
    )
  }

  extractPriceData(content) {
    const text = content.content
    const title = content.title

    // Multiple price extraction patterns
    const pricePatterns = [
      /\$(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/g,
      /USD\s*(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/gi,
      /Price[:\s]*\$?(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/gi
    ]

    const prices = []
    
    pricePatterns.forEach(pattern => {
      let match
      while ((match = pattern.exec(text)) !== null) {
        const price = parseFloat(match[1].replace(/,/g, ''))
        if (price > 0 && price < 10000) { // Reasonable price range
          prices.push(price)
        }
      }
    })

    // Extract additional product info
    const stockStatus = this.extractStockStatus(text)
    const rating = this.extractRating(text)
    const reviewCount = this.extractReviewCount(text)

    return {
      price: prices.length > 0 ? Math.min(...prices) : 0,
      originalPrice: this.extractOriginalPrice(text),
      currency: 'USD',
      inStock: stockStatus.inStock,
      stockText: stockStatus.text,
      rating,
      reviewCount,
      title: title || 'Unknown Product'
    }
  }

  extractStockStatus(text) {
    const inStockIndicators = ['in stock', 'available', 'ships today', 'ready to ship']
    const outOfStockIndicators = ['out of stock', 'unavailable', 'sold out', 'temporarily unavailable']

    const lowerText = text.toLowerCase()

    if (outOfStockIndicators.some(indicator => lowerText.includes(indicator))) {
      return { inStock: false, text: 'Out of Stock' }
    }

    if (inStockIndicators.some(indicator => lowerText.includes(indicator))) {
      return { inStock: true, text: 'In Stock' }
    }

    return { inStock: null, text: 'Unknown' }
  }

  extractRating(text) {
    const ratingPattern = /(\d\.\d)\s*(?:out of|\/)\s*5|(\d\.\d)\s*star/gi
    const match = ratingPattern.exec(text)
    return match ? parseFloat(match[1] || match[2]) : null
  }

  extractReviewCount(text) {
    const reviewPattern = /(\d{1,3}(?:,\d{3})*)\s*reviews?/gi
    const match = reviewPattern.exec(text)
    return match ? parseInt(match[1].replace(/,/g, '')) : null
  }

  extractOriginalPrice(text) {
    const originalPricePattern = /(?:was|originally|list price)[:\s]*\$?(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/gi
    const match = originalPricePattern.exec(text)
    return match ? parseFloat(match[1].replace(/,/g, '')) : null
  }

  extractStoreName(url) {
    try {
      const hostname = new URL(url).hostname.replace('www.', '')
      const storeName = hostname.split('.')[0]
      return storeName.charAt(0).toUpperCase() + storeName.slice(1)
    } catch {
      return 'Unknown Store'
    }
  }

  deduplicateByStore(prices) {
    const storeMap = new Map()
    
    prices.forEach(price => {
      const existing = storeMap.get(price.source)
      if (!existing || price.price < existing.price) {
        storeMap.set(price.source, price)
      }
    })
    
    return Array.from(storeMap.values())
  }

  updatePriceHistory(productName, currentPrices) {
    if (!this.priceHistory.has(productName)) {
      this.priceHistory.set(productName, [])
    }
    
    const history = this.priceHistory.get(productName)
    history.push({
      timestamp: new Date().toISOString(),
      prices: currentPrices,
      lowestPrice: Math.min(...currentPrices.map(p => p.price))
    })
    
    // Keep only last 30 entries
    if (history.length > 30) {
      history.splice(0, history.length - 30)
    }
  }

  checkPriceAlerts(productName, currentPrices, targetPrice) {
    const lowestPrice = Math.min(...currentPrices.map(p => p.price))
    
    if (lowestPrice <= targetPrice) {
      const bestDeal = currentPrices.find(p => p.price === lowestPrice)
      this.sendPriceAlert(productName, bestDeal, targetPrice)
    }
  }

  sendPriceAlert(productName, deal, targetPrice) {
    console.log(`🚨 PRICE ALERT: ${productName}`)
    console.log(`Target: $${targetPrice} | Current: $${deal.price} | Store: ${deal.source}`)
    console.log(`URL: ${deal.url}`)
    
    // Here you would integrate with email, SMS, or webhook notifications
    // Example: await this.sendEmail({ productName, deal, targetPrice })
  }

  calculateAverage(prices) {
    return prices.length > 0 ? 
      Math.round((prices.reduce((sum, price) => sum + price, 0) / prices.length) * 100) / 100 : 0
  }

  // Get price trend analysis
  getPriceTrend(productName, days = 7) {
    const history = this.priceHistory.get(productName) || []
    const recent = history.slice(-days)
    
    if (recent.length < 2) return { trend: 'insufficient_data' }
    
    const firstPrice = recent[0].lowestPrice
    const lastPrice = recent[recent.length - 1].lowestPrice
    const change = lastPrice - firstPrice
    const changePercent = (change / firstPrice) * 100
    
    return {
      trend: change > 0 ? 'increasing' : change < 0 ? 'decreasing' : 'stable',
      change,
      changePercent: Math.round(changePercent * 100) / 100,
      dataPoints: recent.length
    }
  }
}

module.exports = PriceMonitor

Usage Examples

Basic Price Tracking

const monitor = new PriceMonitor('your-zapserp-api-key')

// Track a specific product
const results = await monitor.trackProduct('iPhone 15 Pro 256GB', 999)

console.log(`Found ${results.totalStores} stores`)
console.log(`Lowest price: $${results.lowestPrice}`)
console.log(`Average price: $${results.averagePrice}`)

results.currentPrices.forEach(price => {
  console.log(`${price.source}: $${price.price} (${price.inStock ? 'In Stock' : 'Out of Stock'})`)
})

Bulk Product Monitoring

const products = [
  { name: 'MacBook Pro M3', targetPrice: 1800 },
  { name: 'Sony WH-1000XM5', targetPrice: 300 },
  { name: 'Nintendo Switch OLED', targetPrice: 320 }
]

for (const product of products) {
  const results = await monitor.trackProduct(product.name, product.targetPrice)
  console.log(`${product.name}: Best price $${results.lowestPrice}`)
  
  // Wait between requests to be respectful
  await new Promise(resolve => setTimeout(resolve, 2000))
}

Price Trend Analysis

// Check price trends over time
const trend = monitor.getPriceTrend('iPhone 15 Pro 256GB', 14)

if (trend.trend === 'decreasing') {
  console.log(`📉 Price dropped ${Math.abs(trend.changePercent)}% in last 14 days`)
} else if (trend.trend === 'increasing') {
  console.log(`📈 Price increased ${trend.changePercent}% in last 14 days`)
}

Advanced Features

Automated Monitoring Schedule

// Set up automated monitoring every 6 hours
setInterval(async () => {
  const watchlist = [
    'iPhone 15 Pro', 'Samsung Galaxy S24', 'MacBook Air M3'
  ]
  
  for (const product of watchlist) {
    try {
      await monitor.trackProduct(product)
      console.log(`✅ Updated prices for ${product}`)
    } catch (error) {
      console.error(`❌ Failed to update ${product}:`, error.message)
    }
  }
}, 6 * 60 * 60 * 1000) // 6 hours

Custom Alerts Integration

// Extend the monitor with webhook alerts
class AlertingPriceMonitor extends PriceMonitor {
  async sendPriceAlert(productName, deal, targetPrice) {
    const alertData = {
      product: productName,
      currentPrice: deal.price,
      targetPrice,
      store: deal.source,
      url: deal.url,
      savings: targetPrice - deal.price,
      timestamp: new Date().toISOString()
    }
    
    // Send to webhook, email, or Slack
    await fetch('https://your-webhook-url.com/price-alert', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(alertData)
    })
  }
}

Deployment Tips

  1. Scheduling: Use cron jobs or cloud functions for automated monitoring
  2. Rate Limiting: Add delays between requests to respect website policies
  3. Data Storage: Store price history in a database for long-term analysis
  4. Notifications: Integrate with email services or messaging platforms
  5. Error Handling: Implement retry logic for failed price extractions

Conclusion

You now have a powerful price monitoring system that can track products across multiple e-commerce sites, detect price changes, and alert you to deals. This system is perfect for dropshippers, retail businesses, or anyone who wants to stay on top of pricing trends.

Ready to expand? Consider adding features like price prediction algorithms, competitor product discovery, or integration with inventory management systems.

Found this helpful?

Share it with your network and help others discover great content.

Related Articles

Build an automated SEO content gap analysis tool to discover ranking opportunities, analyze competitor content strategies, and identify high-value keywords your competitors rank for but you don't.

3 min read
Digital Marketing

Build an intelligent research assistant that finds academic papers, extracts key findings, and generates literature reviews automatically. Perfect for researchers, students, and academics.

3 min read
Education

Build an automated competitive intelligence system to track competitor activities, product launches, marketing campaigns, and industry trends. Stay ahead of the competition with real-time insights.

3 min read
Business Strategy