ScreenshotNeo

BlogHow-to

How to Test an Indian Ecommerce Website’s Pincode Delivery States with Screenshots

Build a repeatable pincode delivery test: check the visible result, capture screenshot evidence, and log enough context to compare runs.

By the ScreenshotNeo team4 October 20269 min read

To test pincode delivery states, keep the product and browser setup consistent, enter each PIN code through the site’s delivery or serviceability control, wait for the result to appear, and capture a screenshot showing both the product and the delivery details. Log the PIN code, timestamp, browser and viewport, exact displayed text, and screenshot filename for every run. Treat each result as a time-stamped observation: serviceability and delivery promises can change.

The control and result vary by merchant. Nykaa Fashion documents a product-page “Select Delivery Location” control that can show standard delivery time and Cash on Delivery (COD) availability; it says serviced PIN codes are frequently updated. Reliance Digital describes checking COD eligibility on a product details page, while FirstCry documents a “Check Delivery Details” tool. A platform’s flow may also show delivery estimates, slots, pickup choices, or refreshed availability during checkout. These examples do not define a universal interface or result vocabulary. Nykaa Fashion help, Reliance Digital delivery information, FirstCry FAQs, Flipkart Commerce Cloud documentation.

What to test and record

Test the same product configuration at each location. Availability and delivery promises can depend on the product, seller, inventory, and fulfillment route, so keep those details fixed where the site allows it.

Record Why it matters
Test ID, product URL or identifier, seller, and variant Lets you identify what the result applied to and repeat the same case.
PIN code and timestamp with timezone Delivery states are location-specific and time-sensitive.
Browser, browser version, operating system, viewport, and device context Helps explain visual differences between captures.
Page stage and control used Distinguishes product-page checks from cart or checkout checks.
Exact visible result Preserves details beyond a simple deliverable/unavailable label.
Screenshot filename Connects the observation to its visual evidence.

Record each outcome dimension the page actually shows: serviceability, delivery estimate or slot, home delivery or pickup, shipping charge, and payment choices such as COD. Do not assume every merchant exposes every field.

Repeatable test procedure

  1. Choose a stable test case. Select a product and variant, note the seller and visible stock state, and save the product URL or identifier.
  2. Select representative PIN codes. Include locations expected to show different serviceability outcomes, plus markets relevant to your users. Verify the result on the site during the run; the research does not establish PIN codes that produce fixed results across merchants or products.
  3. Start each run from the same state. Navigate to the same product and use its delivery-location or serviceability control. If the site only checks after adding an item to cart or during checkout, follow that flow and record the stage.
  4. Enter and submit one PIN code. Use the site’s current control and submit the value. Avoid changing product, variant, seller, or other conditions between location runs.
  5. Wait for the result to update. Capture only after the visible delivery state has settled. Record the exact wording and any timing, pickup, shipping, or payment details shown.
  6. Capture evidence. Take a viewport screenshot that includes product context and the result. Use a full-page screenshot when necessary UI is below the viewport.
  7. Write the evidence ledger entry. Store the metadata and screenshot filename together. Preserve the original image; if you make a redacted copy, retain the original securely and document what was masked.
  8. Repeat and retest when needed. Run the same steps for each PIN code. If a later run differs, save a new timestamped observation instead of overwriting the earlier evidence.

Automate the check with Playwright

Playwright can capture a page screenshot, a full-page screenshot, a clipped region, or masked elements. This example is a reusable harness: supply the product URL and the actual selectors for the site under test. The selector and expected result text are merchant-specific; inspect the current page and adjust them before running. It does not claim that any particular PIN code is serviceable.

Install Playwright and its Chromium browser:

npm init -y
npm install --save-dev playwright
npx playwright install chromium

Save the following as pincode-check.cjs. It opens the same product for each PIN code, fills and submits the delivery control, waits for a result, saves a screenshot, and writes a JSONL evidence ledger. Replace the example selectors with the site’s current selectors. By default, it waits for a non-empty result; pass a site-specific regular expression as RESULT_PATTERN if you need to wait for specific result wording.

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

const productUrl = process.env.PRODUCT_URL;
const codes = (process.env.PIN_CODES || '').split(',').map(x => x.trim()).filter(Boolean);
const inputSelector = process.env.PIN_INPUT || '[name="pincode"]';
const submitSelector = process.env.PIN_SUBMIT || 'button[type="submit"]';
const resultSelector = process.env.RESULT_SELECTOR || '[data-testid="delivery-result"]';
const resultPattern = process.env.RESULT_PATTERN ? new RegExp(process.env.RESULT_PATTERN, 'i') : null;
const outputDir = process.env.OUTPUT_DIR || 'pincode-evidence';

if (!productUrl || codes.length === 0) {
  throw new Error('Set PRODUCT_URL and comma-separated PIN_CODES before running.');
}

(async () => {
  await fs.mkdir(outputDir, { recursive: true });
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } });
  const ledgerPath = path.join(outputDir, 'ledger.jsonl');

  try {
    for (const pin of codes) {
      const page = await context.newPage();
      await page.goto(productUrl, { waitUntil: 'domcontentloaded', timeout: 60000 });
      await page.locator(inputSelector).fill(pin);
      await page.locator(submitSelector).click();
      const result = page.locator(resultSelector);
      await result.waitFor({ state: 'visible', timeout: 30000 });
      await page.waitForFunction(
        ({ selector, pattern }) => {
          const el = document.querySelector(selector);
          const text = el?.innerText?.trim() || '';
          return text.length > 0 && (!pattern || new RegExp(pattern, 'i').test(text));
        },
        { selector: resultSelector, pattern: resultPattern?.source || null },
        { timeout: 30000 }
      );
      const observedText = (await result.innerText()).trim();
      const stamp = new Date().toISOString().replaceAll(':', '-');
      const safePin = pin.replace(/[^0-9A-Za-z_-]/g, '_');
      const filename = `${stamp}-${safePin}.png`;
      await page.screenshot({ path: path.join(outputDir, filename), fullPage: false, animations: 'disabled' });
      const entry = {
        testId: `${stamp}-${safePin}`,
        productUrl,
        pinCode: pin,
        timestamp: new Date().toISOString(),
        browser: 'Chromium via Playwright',
        viewport: { width: 1440, height: 1000 },
        pageStage: 'product page',
        observedText,
        screenshot: filename
      };
      await fs.appendFile(ledgerPath, JSON.stringify(entry) + '\n');
      console.log(JSON.stringify(entry));
      await page.close();
    }
  } finally {
    await context.close();
    await browser.close();
  }
})().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

Run it with your site’s selectors and the PIN codes you want to check:

PRODUCT_URL='https://shop.example/product' \
PIN_CODES='560001,110001' \
PIN_INPUT='input[name="postalCode"]' \
PIN_SUBMIT='button.check-delivery' \
RESULT_SELECTOR='.delivery-message' \
node pincode-check.cjs

The example expects the result element’s text to change from empty to non-empty. If the page initially contains stale text, wait for a site-specific state change or validate the result against a known pattern. For a small relevant region, use Playwright’s clip screenshot option; use mask for elements that should be visually obscured, while keeping an original evidence capture when the test requires it. Playwright documents these options in its Page screenshot API. Visual screenshot assertions are available in Playwright Test screenshot comparisons.

Make screenshots comparable

Keep the browser engine and version, operating system, viewport, device scale, headless mode, and screenshot options consistent when comparing runs. Browser rendering can vary with environment, settings, hardware, power source, and headless mode; Playwright’s screenshot comparison guidance recommends a consistent environment and waits for consecutive screenshots to match before comparison. A screenshot is evidence of the rendered state under that setup, not a universal rendering guarantee.

Use a viewport capture for the product and delivery result when both fit on screen. Use fullPage: true when relevant content is otherwise omitted, but remember that a long page can make the delivery result harder to inspect. For repeatable visual comparisons, first make sure the dynamic delivery result has settled, then compare captures from the same environment. Preserve timestamps in the ledger even when filenames are normalized for image-diff tooling.

Common problems and fixes

Problem Likely cause Fix
Input selector times out The site changed its markup, the control is hidden behind a location dialog, or the page has not loaded it yet. Inspect the live page, open the delivery-location control if needed, and update PIN_INPUT. Wait for the dialog or input to become visible before filling.
Submit click has no effect The button selector is wrong, the control requires Enter, or validation prevented submission. Check the current UI and validation messages. Use the actual button or submit the field with Enter if that matches the site’s flow.
Result wait times out The result selector is wrong, the PIN code is invalid, the page has not responded, or the site reports an error in another element. Inspect the page after submission, capture diagnostic text or a failure screenshot, and update the selector and wait condition. Record an error outcome rather than silently skipping the run.
Old result is recorded for a new PIN code The script waited for existing non-empty text instead of a changed result. Read and save the prior text before submission, then wait until text changes, or wait for a site-specific loading indicator to disappear and validate the updated state.
Screenshot omits the delivery message The message is below the viewport, in a modal, or captured before it becomes visible. Scroll the result into view or use a full-page capture; ensure the modal is open and the result has settled before capture.
Screenshots differ across runs with no apparent site change Browser, OS, viewport, fonts, animation, or dynamic content differs. Pin the environment and viewport, disable animations for capture, and avoid comparing captures taken under different rendering setups.
Checkout result differs from product-page result The site checks availability at different stages or refreshed cart data changes the state. Record the page stage and follow the merchant’s actual flow. Treat each displayed state as a separate observation.

Performance, reliability, and cost

For a short PIN-code list, a sequential run is easier to audit and avoids overlapping actions in a single browser context. Each run loads the product and waits for the site’s response, so total duration depends on the page and its serviceability flow. Set navigation and result timeouts to suit the site; record timeouts and failures as outcomes for investigation instead of treating them as unavailable delivery.

For repeatability, use a stable test product, preserve the exact browser setup, and keep the ledger and screenshot together. Do not infer that a failed load or bot check means a PIN code is unserviceable. This procedure does not guarantee that a retailer’s data is static or that its response will match a later run. No universal PIN-code dataset or delivery-state vocabulary is established by the sources.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo. You can make a single request for a screenshot of a page, but a screenshot API does not itself enter and submit a PIN code in a site’s interactive delivery control; use browser automation for that interaction, then capture the resulting page URL or state as appropriate. See the ScreenshotNeo API documentation.

Example cURL call for a page screenshot:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Cookie banners, newsletter popups, and chat widgets can be removed before the shot. Bot checks, blank pages, and failed loads are never billed, and response headers report the page verdict and billing status. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a 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.

FAQ

Is there one PIN code that proves a site is serviceable?

No. Results depend on the merchant, product, seller, inventory, and time. Verify each expected category against the specific site during the test.

Should I use a full-page screenshot for every run?

No. Use a viewport capture when it contains the product and delivery result. Choose full-page capture only when relevant content would otherwise be missing.

Can I compare screenshots from different machines?

You can inspect them, but visual differences may come from the browser environment. For reliable pixel comparisons, keep the rendering environment consistent.

What if the site checks delivery only at checkout?

Follow that site’s flow and record that the result appeared at checkout. Do not label a product-page state that the site never displayed.