ScreenshotNeo

BlogHow-to

How to Schedule Website Screenshots of Indian Ecommerce Sale Pages

Schedule timestamped captures of Indian ecommerce sale pages with Playwright and cron. Keep comparisons consistent and verify price changes before recording them.

By the ScreenshotNeo team4 October 202611 min read

To schedule recurring screenshots of an Indian ecommerce sale page, use a browser script such as Playwright to capture the page, then run that script from a separate scheduler such as cron. Save each capture with its timestamp and record the browser, viewport, timezone, URL, and relevant delivery context. A screenshot records what the browser rendered at that moment; it does not prove that the product’s underlying price changed.

This guide builds a daily capture for a permitted sale page, explains how to make captures comparable, and shows how to investigate apparent price changes without confusing page movement or rotating content for a verified price change.

1. Choose the page and the evidence you need

Start with the exact URL or URLs you are allowed to access. Decide what the capture needs to show:

  • Full landing page: useful when the promotion’s surrounding context, conditions, or page layout matters.
  • Promotion banner: useful when the sale announcement itself is the evidence.
  • Product and price region: useful for comparing a particular product, variant, and displayed price while excluding unrelated rotating content.

For each target, note the product identity and variant, currency, delivery region if it affects what is displayed, and the timezone you will use for the capture schedule. Keep the exact URL in the run record. A retailer may show different price, availability, delivery, or promotion details for different variants or locations.

2. Install Playwright and create a capture script

Playwright can capture a page, a full page, or a specific element. The screenshot operation does not schedule itself; a separate scheduler will run the script. See the Playwright screenshots documentation for the capture options and PageAssertions documentation for screenshot stability assertions in Playwright Test.

Install the browser runtime

mkdir sale-page-captures
cd sale-page-captures
npm init -y
npm install playwright
npx playwright install chromium

Create a reusable script

Save this as capture-sale-page.js. It uses environment variables for the target URL and output directory. By default it captures the full page. Set SELECTOR to capture a single element instead. The script waits for the page to load, then optionally waits for a selector that represents the price or promotion. It does not attempt to evade bot checks or access restrictions.

const { chromium } = require('playwright');
const fs = require('node:fs/promises');
const path = require('node:path');

function timestampForFilename(date) {
  return date.toISOString().replace(/[:.]/g, '-');
}

async function main() {
  const url = process.env.TARGET_URL;
  if (!url) throw new Error('Set TARGET_URL to a permitted sale-page URL');

  const outDir = process.env.OUT_DIR || './captures';
  const selector = process.env.SELECTOR || '';
  const waitSelector = process.env.WAIT_SELECTOR || '';
  const viewportWidth = Number(process.env.VIEWPORT_WIDTH || 1365);
  const viewportHeight = Number(process.env.VIEWPORT_HEIGHT || 900);
  const timezone = process.env.TIMEZONE || 'Asia/Kolkata';

  await fs.mkdir(outDir, { recursive: true });
  const capturedAt = new Date();
  const file = path.join(outDir, `sale-${timestampForFilename(capturedAt)}.png`);
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({
    viewport: { width: viewportWidth, height: viewportHeight },
    timezoneId: timezone,
    locale: 'en-IN'
  });

  try {
    const page = await context.newPage();
    const response = await page.goto(url, {
      waitUntil: 'domcontentloaded',
      timeout: 60000
    });

    if (response && response.status() >= 400) {
      throw new Error(`Navigation returned HTTP ${response.status()}`);
    }

    if (waitSelector) {
      await page.locator(waitSelector).waitFor({ state: 'visible', timeout: 30000 });
    } else {
      await page.waitForTimeout(2000);
    }

    if (selector) {
      const target = page.locator(selector).first();
      await target.waitFor({ state: 'visible', timeout: 30000 });
      await target.screenshot({ path: file, animations: 'disabled' });
    } else {
      await page.screenshot({ path: file, fullPage: true, animations: 'disabled' });
    }

    const run = {
      capturedAt: capturedAt.toISOString(),
      timezone,
      url,
      viewport: { width: viewportWidth, height: viewportHeight },
      selector: selector || null,
      waitSelector: waitSelector || null,
      httpStatus: response ? response.status() : null,
      file: path.basename(file)
    };
    await fs.writeFile(`${file}.json`, JSON.stringify(run, null, 2) + '\n');
    console.log(`Saved ${file}`);
  } finally {
    await context.close();
    await browser.close();
  }
}

main().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

Run it once manually before scheduling. Example for macOS or Linux:

TARGET_URL='https://shop.example/sale' \
OUT_DIR='./captures' \
TIMEZONE='Asia/Kolkata' \
node capture-sale-page.js

Replace the example URL with a page you are permitted to capture. If the important price content is in a known element, supply its CSS selector. For example, after inspecting the page’s own markup, set WAIT_SELECTOR='.product-price' to wait for that element and SELECTOR='.product-summary' to capture its containing region. Selectors are site-specific; verify them on the actual page.

3. Schedule recurring captures with cron

Cron runs a command on a schedule. The following example runs once a day at 09:00 India Standard Time. Set the machine or container timezone to Asia/Kolkata if you want cron’s schedule itself to use India time; otherwise schedule in the host’s timezone and account for the offset. The TZ variable is not honored by every cron implementation, so check the one on your system.

crontab -e

Add a line like this, replacing the paths and URL with your own values:

CRON_TZ=Asia/Kolkata
0 9 * * * cd /srv/sale-page-captures && TARGET_URL='https://shop.example/sale' OUT_DIR='/srv/sale-page-captures/captures' TIMEZONE='Asia/Kolkata' /usr/bin/node capture-sale-page.js >> /srv/sale-page-captures/capture.log 2>&1

If your cron does not support CRON_TZ, configure the host timezone or convert the desired run time to the host’s timezone. Check the schedule after daylight-saving or host timezone changes where applicable. India does not observe daylight saving time, but the server running cron could be in a different timezone.

Scheduled workflow alternative

A hosted scheduled workflow can run the same script from a repository or runner. Configure the runner’s timezone explicitly if supported, or use a UTC schedule and convert the desired India time. Store secrets and output artifacts according to that provider’s controls and retention settings. These details vary by scheduler, so verify its current documentation, quotas, artifact retention, and timezone behavior.

4. Make screenshots comparable

Visual comparison is useful only when the capture conditions are reasonably stable. Keep these values fixed across runs:

  • Browser runtime and version: avoid changing browser versions in the middle of a comparison series without recording the change.
  • Viewport and capture area: use the same width and height, and keep full-page versus element capture consistent.
  • Capture timing: run at a consistent time and wait for the price or promotion element, rather than capturing while content is still loading.
  • Locale, timezone, and delivery context: record settings that might affect displayed dates, currency, stock, or delivery information.
  • Dynamic content: rotating banners, recommendations, cookie overlays, popups, and layout shifts can create image differences unrelated to the price.

Full-page captures preserve surrounding context but may include unrelated content that changes between runs. Element captures focus on a particular region and reduce noise, but can omit conditions elsewhere on the page. Keep a full-page record too if the surrounding terms or sale context matter.

Playwright Test includes an assertion that waits until consecutive page screenshots yield the same result before comparing against an expectation. That can help with test snapshots, but it is not a guarantee that a recurring scheduled capture is stable or that the price has been verified. See the official API description.

5. Review apparent price changes carefully

A changed screenshot means the rendered appearance changed. Before recording it as a price movement, compare the same product and variant and verify:

  1. The product identity and variant are the same.
  2. The displayed currency is the same.
  3. The delivery location or pin code context is the same where it affects the page.
  4. The item is available in both captures, and the shown price refers to the same offer.
  5. The change is in the numeric price rather than a sale banner, crossed-out list price, coupon message, shipping charge, or unrelated page content.

Preserve the original captures and run metadata. An archive can show what the browser rendered at capture time; it does not establish why the page changed or validate the underlying transaction price.

6. Preserve dated records and handle missed runs

The sample script uses an ISO timestamp in each filename and writes a JSON sidecar containing the URL, capture time, timezone, viewport, selector, HTTP status, and filename. Keep the log next to the archive or in the monitoring system you use. For each run, record whether it succeeded, failed, timed out, or was skipped, so a gap in the archive is not mistaken for no price movement.

Choose a retention period based on your use case, storage capacity, and any site or organizational requirements. Keep screenshots and metadata together, restrict access to the archive where appropriate, and document changes to the script or browser runtime. The research sources do not establish a universal retention period or storage cost; measure your own capture size and storage policy.

7. When to use a managed capture service

Self-hosting gives you control over the script, timing, file naming, and storage, but you maintain the browser runtime, scheduler, logs, and alerts. A managed service can bundle some of those pieces, though current schedules, capture locations, quotas, storage, notifications, price, retention, and data terms must be checked with that provider. Available research does not provide an independent, apples-to-apples price or reliability comparison among managed services.

For India-specific captures, confirm that the capture environment actually receives the regional page content you need. A provider may advertise India capture locations, but availability and behavior should be verified directly. Follow the target site’s terms and access rules. If automation is blocked, do not try to bypass that restriction.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Its one-call API captures a URL; it does not itself provide recurring scheduling, so run this request from cron or your chosen scheduler if you need a recurring archive. See the ScreenshotNeo API documentation for request options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://shop.example/sale -o sale.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://shop.example/sale"},
    timeout=90,
)
open("sale.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://shop.example/sale'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('sale.webp', Buffer.from(await res.arrayBuffer())));

Use the returned image and save it with your own timestamp and run metadata when scheduling repeat captures. ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents and MCP clients. The Free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots.

Sign up for 1,000 free screenshots a month, with no card required.

Troubleshooting

Symptom Likely cause What to check or fix
Executable doesn't exist or browser launch error The Playwright browser binary is not installed in the runtime environment. Run npx playwright install chromium in the same environment that runs the scheduled job. Confirm the cron user uses the expected Node installation and project directory.
Script works interactively but cron produces no file Cron has a different working directory, PATH, environment, or permissions. Use absolute paths for Node, script, and output directory; set required environment variables in the crontab line; redirect stdout and stderr to a log; ensure the cron user can write to the destination.
Screenshot shows a loading state or missing price The script captured before the relevant content appeared, or the selector is wrong. Set WAIT_SELECTOR to a visible price or promotion element, inspect the selector on the current page, and allow a suitable timeout. Avoid relying only on a fixed delay when a meaningful element can be awaited.
Price region is clipped or missing The chosen selector targets a child, hidden element, or wrong variant panel. Check that the selector is visible and points to the full region needed. Compare an element capture with a full-page capture during setup.
Screenshots differ even though the price appears unchanged Rotating banners, popups, consent overlays, recommendations, layout shifts, or browser changes affected the rendered page. Keep browser and viewport stable, wait for the relevant content, use a focused element capture where appropriate, and inspect the images before treating a difference as a price change.
Page returns an error, CAPTCHA, or access block The site rejected the request, the page is unavailable, or the access rules prohibit automation. Record the failed run and follow the site’s access rules. Do not try to bypass a block; use an authorized method or stop capturing that target.
Same URL shows a different price or currency Product variant, delivery region, availability, locale, or offer context changed. Verify product identity, selected variant, currency, delivery context, and availability from both captures before recording a price movement.
Duplicate filenames or overwritten captures A schedule ran more than once within the timestamp precision or used a fixed filename. Use a timestamped filename as in the script, or add a run identifier. Keep the timestamp in metadata in UTC and record the intended local schedule timezone.
Scheduled runs drift from 09:00 India time The host timezone differs from India or cron ignores the timezone setting. Check the cron implementation and host timezone. Configure the machine timezone or convert the job time from India Standard Time to the host’s schedule timezone.

Performance, reliability, and cost

  • Performance: full-page screenshots may require more page rendering and produce larger files than a focused element capture. Use the smallest capture area that preserves the evidence you need, and wait only for relevant content.
  • Reliability: a local scheduled job depends on the host being available, the browser runtime remaining installed, and storage being writable. Log failures and missed runs; a missing image is not evidence that the page stayed unchanged.
  • Cost: the self-hosted workflow uses your chosen compute and storage, whose cost depends on your environment and retention policy. No reviewed source establishes a general price or reliability comparison. For a managed service, verify current plan limits and terms.
  • Access: obey the merchant’s terms and access controls. A technically successful screenshot is not permission to automate a page.

FAQ

Does taking a screenshot confirm the sale price?

No. It records the rendered page at capture time. Verify the same product, variant, currency, region, availability, and price context before describing a change as a price movement.

Does Playwright schedule screenshots every day?

No. Playwright performs the browser capture; cron or another scheduler runs the script repeatedly.

Should I capture the whole page or just the product?

Use a full-page capture when surrounding sale terms matter. Use an element capture to focus on a specific product or price and reduce unrelated visual changes. Keep both if you need the focused comparison and the wider context.

Can I compare screenshots from different capture regions?

For a meaningful visual comparison, use the same browser, viewport, and capture region across the series, and record any changes to those settings.