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.
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:
Product URL Management
Maintain a database of products to monitor with their competitor URLs.
Scheduled Scraping
Run scraping jobs on a schedule (hourly, daily) to collect current pricing data.
Data Extraction & Parsing
Extract prices, availability, and promotions from product pages using AI-powered extraction.
Price History Storage
Store all price observations with timestamps for historical analysis and trend detection.
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'
})
});