If you run a small online store, you already know the problem: keeping up with competitor prices is a manual grind. Open ten tabs, compare SKUs, scribble notes, repeat. By the time you finish, half the prices have changed. A dedicated competitor price tracker built in Python costs nothing to run and does the job automatically while you sleep.

What you’ll build

By the end of this guide you’ll have:

  • A Python script that scrapes product prices from 2-3 competitor sites daily
  • A local CSV database that tracks price history over time
  • A simple alert system that flags products where you’re 10%+ above the competitor
  • A scheduling setup so it runs unattended every morning

Total build time: about an hour. Running cost: $0 (your existing laptop or VPS).

Step 1: Structure your data first

Before writing a single scraper, know what you’re looking for. Create a targets.csv that maps your products to competitor URLs:

product_name,your_price,competitor_url,competitor_name
Blue Denim Jacket,45.00,https://competitor-a.com/products/jacket-denim,CompetitorA
Canvas Sneakers White,32.00,https://competitor-b.com/sneakers/white-canvas,CompetitorB
Wool Beanie Black,15.00,https://competitor-a.com/products/beanie-wool,CompetitorA

Keep this file small — 20 to 50 SKUs. Anything beyond that and you’ll want a proper database, but for most small retailers this CSV is all you need.

Step 2: Build the scraper

Here’s a scraper that reads your targets, fetches prices, and saves history. It’s designed to be polite: one request at a time with a 3-second delay.

import csv
import requests
from bs4 import BeautifulSoup
from datetime import datetime
import time
import os

HISTORY_FILE = "price_history.csv"
HEADERS = {
    "User-Agent": "MyStorePriceChecker/1.0 (contact@mystore.com)"
}

def parse_price(price_text):
    """Clean a price string like '$45.00' or 'Rp 720,000' into a float."""
    cleaned = price_text.strip()
    if cleaned.startswith("Rp"):
        cleaned = cleaned.replace("Rp", "").replace(".", "").replace(",", ".").strip()
        return float(cleaned)
    return float(cleaned.replace("$", "").replace(",", ""))

def scrape_competitor(url):
    try:
        resp = requests.get(url, headers=HEADERS, timeout=15)
        if resp.status_code != 200:
            return None
        soup = BeautifulSoup(resp.text, "html.parser")
        price_el = soup.select_one(".price, .product-price, [data-price]")
        if not price_el:
            return None
        return parse_price(price_el.text)
    except Exception as e:
        print(f"Error on {url}: {e}")
        return None

def load_targets():
    products = {}
    with open("targets.csv", "r") as f:
        reader = csv.DictReader(f)
        for row in reader:
            key = row["product_name"]
            products.setdefault(key, []).append(row)
    return products

def save_history(rows):
    write_header = not os.path.exists(HISTORY_FILE)
    with open(HISTORY_FILE, "a", newline="") as f:
        writer = csv.writer(f)
        if write_header:
            writer.writerow(["date", "product", "competitor", "your_price", "their_price"])
        writer.writerows(rows)

def check_alerts(rows):
    for row in rows:
        their_price = float(row[4])
        your_price = float(row[3])
        if your_price > 0 and their_price < your_price * 0.9:
            print(f"⚠ ALERT: {row[1]} — You're ${your_price - their_price:.2f} above {row[2]}!")

# Main
products = load_targets()
new_rows = []
today = datetime.now().strftime("%Y-%m-%d")

for product, targets in products.items():
    your_price = float(targets[0]["your_price"])
    for t in targets:
        their_price = scrape_competitor(t["competitor_url"])
        if their_price:
            new_rows.append([today, product, t["competitor_name"], your_price, their_price])
        time.sleep(3)

if new_rows:
    save_history(new_rows)
    check_alerts(new_rows)
    print(f"Done. Checked {len(new_rows)} product-competitor pairs.")
else:
    print("No data collected — check your selectors.")

Step 3: Tune the selectors for each site

The line soup.select_one(".price, .product-price, [data-price]") is a guess — every site uses different CSS classes. For each competitor site in your targets.csv, you’ll need to:

  1. Open the product page in a browser
  2. Right-click the price → Inspect
  3. Note the CSS selector (could be .price, span.amount, [itemprop="price"], etc.)
  4. Update the select_one() call accordingly

A common pattern: use multiple fallback selectors. select_one() returns the first match, so put the most specific selector first.

Step 4: Run it on a schedule

On Linux / macOS, use cron. Open your crontab with crontab -e and add:

# Run price check every weekday at 7 AM
0 7 * * 1-5 cd /path/to/your/scraper && python3 price_tracker.py >> price_log.txt 2>&1

On Windows, use Task Scheduler with a daily trigger. In both cases, test the script manually first before trusting the automation.

Step 5: Read the data

After a week, open price_history.csv in any spreadsheet app. Each product has a row per day with your price and the competitor’s. You can:

  • Find pricing gaps quickly. Filter by date=latest and sort by the difference column.
  • Spot trends. If CompetitorB drops prices every Tuesday, you know when to run promotions.
  • Identify stockouts. If a competitor’s price field disappears (returns None), the product might be out of stock — a perfect time to raise your price.

When to upgrade

This CSV-based tracker works well for 50 SKUs across 3 competitors. When you outgrow it, you’ll know because:

  • Your targets.csv has 200+ rows and the script takes 10+ minutes
  • You need historical charts or web-based dashboards
  • Competitors add CAPTCHAs or JavaScript-rendered prices (then you need Playwright or a paid API like ScrapingBee)

At that point, consider a lightweight tool like PricingBot ($29/month) or building a Django dashboard. But for most small retailers, this 50-line script handles 80% of the job at $0.

Final checklist

  • targets.csv with your SKUs and competitor URLs
  • CSS selectors verified for each target site
  • Script runs without errors from the command line
  • Crontab or Task Scheduler set up for daily runs
  • Price history file growing with new rows each day

Start small — five products, one competitor. Once you see the data flow in, scale up. The first morning you open price_history.csv and see a competitor quietly raised prices on two items while you were asleep, the script has already paid for itself.