How to Schedule Recurring Screenshots of Indian Ecommerce Websites for Price Tracking
Track product pages on a schedule with a managed monitor or a self-hosted browser workflow. Learn how to compare captures without mistaking page changes for price changes.
A recurring screenshot workflow loads a product page on a schedule and saves what the page displayed at each check. For price tracking, monitor the price area or relevant text where possible, and keep the capture time, product variant, currency, delivery location, and availability with each image. A screenshot records a moment in time; by itself, it does not prove that a like-for-like product price changed.
There are two practical routes: use a managed monitor that schedules checks and keeps comparisons, or run browser automation yourself and schedule it with a task scheduler. Use the first when you want less runtime maintenance; use the second when you need control over storage and capture logic.
1. Decide what counts as a price change
Before automating, choose the exact product listing and variant. A product page may show multiple colors, sizes, bundles, sellers, or fulfillment options. A changed number is only useful if it refers to the same item and conditions.
- Use a direct URL for the selected listing and variant, if the retailer provides one.
- Record the displayed price and currency, and distinguish a sale price from a crossed-out list price when visible.
- Record delivery location and availability. Those can change what the page displays.
- Decide whether shipping, coupons, membership prices, or seller changes matter to your comparison.
- Check the retailer’s current access terms and automation behavior before scheduling checks. This guide does not establish permission for any specific retailer.
Prefer monitoring the price region or extracting price-related text over treating every pixel change on a whole page as a price alert. Banners, recommendations, stock messages, rotating promotions, and layout changes can all change a screenshot without changing the price you care about.
2. Choose managed monitoring or a self-hosted workflow
| Approach | What you maintain | Useful when |
|---|---|---|
| Managed monitor | Monitor settings, check frequency, alert rules, and periodic review of captures | You want scheduled checks and change comparisons without keeping your own browser runtime online |
| Self-hosted browser capture | Browser installation, scheduler, storage, logs, retries, and notifications | You need direct control over capture files, metadata, and processing |
Visualping describes scheduled page or selected-area comparisons, configurable check frequency, and cloud monitors that continue when your computer is off. Its setup guide recommends choosing the direct URL, configuring what matters, and selecting a frequency; it also discusses false positives and page interaction issues. See What is Visualping? and How to create a basic monitoring job. Available frequencies, history, alerts, regions, and plan limits can vary; check the service’s current settings before choosing it.
For a self-hosted option, ChangeDetection.io documents browser-based fetchers using Playwright or Puppeteer, configurable check intervals, filters, and optional screenshot notifications. Its API also documents watch creation and settings such as fetch backend and notification URLs. See the ChangeDetection.io API documentation. The scheduler and retained files still need to be operated and monitored by you.
3. Set up a managed monitor
- Open the monitor’s dashboard and create a monitor for the product’s direct URL.
- Preview the page and make sure the exact product, variant, and price are visible.
- Select the price region or configure a price-focused text or change condition if the tool supports it. A whole-page monitor is easier to set up but can create more irrelevant alerts.
- Set a check frequency that suits the decision you are making. Checks only observe the page when they run, so a change between checks may not be observed at the moment it occurs.
- Choose notifications and history options. Save enough context to inspect the prior and current versions.
- Run a manual review after the first checks. Confirm the monitor captured the intended price and did not land on a consent screen, login page, bot check, or error.
Visualping’s guide explains that the selected frequency controls how often checks happen and that higher frequencies use more checks. It also notes that a wait time or page actions may help when elements have not loaded or require interaction. These settings do not guarantee that every page can be monitored successfully.
4. Self-hosted recurring screenshots with Playwright
This example runs one capture at a time. A system scheduler triggers it repeatedly. It saves a full-page screenshot and a JSON sidecar containing the capture timestamp and the context you supply. Install Playwright and its Chromium browser in the environment that will run the job:
python -m pip install playwright
python -m playwright install chromium
Save the following as capture_product.py. Set PRODUCT_URL and the metadata environment variables for the exact listing you intend to track.
import asyncio
import json
import os
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import urlparse
from playwright.async_api import async_playwright
URL = os.environ["PRODUCT_URL"]
OUT_DIR = Path(os.environ.get("CAPTURE_DIR", "captures"))
async def main():
OUT_DIR.mkdir(parents=True, exist_ok=True)
captured_at = datetime.now(timezone.utc)
stamp = captured_at.strftime("%Y%m%dT%H%M%SZ")
host = urlparse(URL).netloc.replace(":", "_")
stem = f"{stamp}_{host}"
image_path = OUT_DIR / f"{stem}.png"
metadata_path = OUT_DIR / f"{stem}.json"
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page(
viewport={"width": 1440, "height": 1000},
device_scale_factor=1,
)
response = await page.goto(URL, wait_until="domcontentloaded", timeout=60000)
# Give client-rendered content a short opportunity to appear.
await page.wait_for_timeout(2000)
await page.screenshot(path=str(image_path), full_page=True)
title = await page.title()
final_url = page.url
status = response.status if response else None
await browser.close()
metadata = {
"captured_at_utc": captured_at.isoformat(),
"requested_url": URL,
"final_url": final_url,
"page_title": title,
"http_status": status,
"product_variant": os.environ.get("PRODUCT_VARIANT", ""),
"currency": os.environ.get("CURRENCY", ""),
"delivery_location": os.environ.get("DELIVERY_LOCATION", ""),
"availability": os.environ.get("AVAILABILITY", ""),
"image_file": image_path.name,
}
metadata_path.write_text(json.dumps(metadata, ensure_ascii=False, indent=2) + "\n")
print(f"saved {image_path} and {metadata_path}; status={status}")
if __name__ == "__main__":
asyncio.run(main())
Run it once manually before scheduling:
PRODUCT_URL='https://shop.example/product' \
PRODUCT_VARIANT='blue, 128 GB' \
CURRENCY='INR' \
DELIVERY_LOCATION='your chosen delivery area' \
AVAILABILITY='in stock' \
python capture_product.py
Replace the example URL and context with the listing and conditions you actually track. The page may render a different price if location, cookies, account state, or selected variant differs. The sample deliberately does not attempt to bypass bot checks, logins, or other access restrictions.
Schedule it on a Linux host with cron
Create a directory for the script and captures, then edit your user crontab with crontab -e. This example runs daily at 09:00 in the machine’s configured timezone; confirm that timezone or use UTC consistently for scheduling and metadata.
0 9 * * * PRODUCT_URL='https://shop.example/product' PRODUCT_VARIANT='blue, 128 GB' CURRENCY='INR' DELIVERY_LOCATION='your chosen delivery area' AVAILABILITY='in stock' CAPTURE_DIR='/home/you/price-captures' /usr/bin/python3 /home/you/capture_product.py >> /home/you/price-captures/cron.log 2>&1
Use absolute paths and verify the Python executable and installed Playwright browser are available to the cron environment. To run at a different interval, change the schedule fields and consider how much history and traffic the resulting frequency creates. On Windows, use Task Scheduler; on macOS, use a launch agent or another scheduler. In each case, configure the working directory, environment variables, runtime account, and log output explicitly.
Capture only a price element
If the page has a stable selector, Playwright can capture just that element. After navigation and any required page readiness wait, replace the full-page screenshot call with:
price = page.locator("[data-testid='price']")
await price.wait_for(state="visible", timeout=15000)
await price.screenshot(path=str(image_path))
[data-testid='price'] is an example selector, not a selector known to exist on any retailer page. Inspect the page and use a selector that matches the actual price element. If the site changes its markup, the selector can stop matching; log that failure and review it instead of silently treating a missing element as a price result.
5. Keep comparisons meaningful
Use a predictable naming convention and retain each image with its metadata sidecar. The timestamp should be unambiguous, preferably UTC in the filename or metadata. Keep the requested URL and final URL because redirects can change the page you captured. Where possible, record the selected variant, currency, delivery area, and availability at every run.
For an initial manual review, compare the displayed product identity, variant, and price between consecutive captures. If the screenshot changed, inspect whether the difference is actually price, stock status, delivery location, seller, promotion, or a page-state change. Treat a detected visual change as a prompt to investigate, not as definitive evidence of a like-for-like price movement.
Frequency is a trade-off. More frequent runs can narrow the window in which a change may go unseen, but they create more browser work, storage, and checks. Choose a cadence based on how quickly the price matters to you and the retailer’s access terms. Avoid overlapping runs: if one browser job can take longer than the interval, use a lock or configure the scheduler not to start another instance while one is active.
6. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| Screenshot shows a blank or incomplete page | Client-side content has not rendered, a resource failed, or the page is waiting on an interaction | Inspect the page manually; wait for a meaningful selector instead of relying only on a fixed delay. Check logs and the final URL. |
| Price selector times out | The selector is wrong, the page structure changed, or the selected product is unavailable | Inspect the current DOM and selector. Save a diagnostic screenshot or page HTML for review. Do not treat a missing selector as zero price. |
| Capture contains a CAPTCHA, bot check, login, or access error | The site did not serve the expected product page or requires a permitted access method | Stop and review the retailer’s current rules and available access methods. Do not make bypassing the check part of the workflow. |
| Many alerts occur without a price change | Whole-page changes, rotating content, banners, or availability updates are triggering comparison | Monitor a smaller region or price-focused text/condition where supported; review each alert against product and location context. |
| Scheduled job works interactively but not under cron | Different PATH, working directory, environment, Python install, or browser dependencies | Use absolute paths, set environment variables in the schedule, redirect logs, and run the command as the same account used by the scheduler. |
| Runs are missing | Host was off, scheduler failed, browser crashed, or prior run still occupied the job | Check scheduler logs and host availability; add failure notifications or an external heartbeat if needed, and prevent overlapping runs. |
| Price changed between screenshots but no alert arrived | The change occurred between scheduled checks or the alert condition excluded it | Review frequency and condition configuration. A monitor only checks at its scheduled times. |
7. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. A GET request takes a URL and returns an image or PDF. For a recurring price record, put the call in your scheduler and store each response with your own timestamp and product context. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://shop.example/product -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://shop.example/product"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://shop.example/product' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
Store the API key as an environment secret rather than committing it to source control. The response identifies page verdict and billing status in headers. Cookie banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
8. Reliability and cost notes
A managed monitor can keep checking while your computer is off, but its check frequency, storage, alerting, and geographic options depend on its current service and plan. A local browser job depends on the host, scheduler, browser installation, network, and storage remaining healthy. Neither route guarantees a successful capture of every page on every run.
For self-hosting, account for browser runtime and maintenance, image storage, logs, and notification delivery. Set a retention policy so daily screenshots do not fill the disk indefinitely. For a managed service, compare the current plan limits and history against the number of URLs and chosen frequency. For ScreenshotNeo, the stated plans are Free: 1,000 shots/month; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; and Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan.
9. FAQ
Does a screenshot prove a price changed?
No. It proves what the captured page displayed at that time. Verify that the product, variant, currency, seller, delivery area, and availability match before treating two displayed values as comparable.
Should I capture the whole page or just the price?
Capture the price region for lower visual noise when a stable selector or area selection is available. Keep a full-page capture when surrounding product and availability context is necessary to interpret the value.
Will a daily schedule catch every price change?
No. It samples the page at scheduled times. A change that starts and ends between checks can be missed.
Can I use this workflow for every Indian ecommerce site?
Do not assume that. Check the current access terms and behavior for each retailer, and review what the monitor actually captured before relying on its history.


