Skip to main content
Thirdwatchthirdwatch
E-commerce & products

Monitor AJIO Brand Catalog Changes Daily for Indian Fashion

Track AJIO new launches, out-of-stock SKUs, MRP edits and brand drops at scale with Thirdwatch. Python recipes for daily diffs and Slack alerts to ops.

May 12, 2026 · 5 min read · 1,104 words
See the scraper →

Thirdwatch's AJIO Scraper returns dedupable, sku-stamped product rows that make AJIO catalog monitoring straightforward — daily snapshots, set differences, MRP edit detection, and stockout vs delisting separation. Built for India fashion ops teams tracking new launches and OOS, brand teams monitoring AJIO private-label drops, and analysts watching for unauthorised resellers or counterfeit listings appearing in the catalog.

Why monitor AJIO catalog changes

AJIO's catalog moves daily. According to the India Brand Equity Foundation 2024 fashion report, Indian online fashion brands launch on average 2 to 4 new SKUs per week per category, and AJIO's Reliance-backed private-label brands (AJIO Own, Netplay, Teamspirit, Performax) operate at the higher end of that range. End-of-season-sale windows compress months of churn into days — SKUs appear, sell out, get re-listed at a new MRP within a single week.

For brand ops, marketplace ops, and competitive intelligence teams, that churn is operational signal. The job-to-be-done is structured. A brand ops team tracking 8 competitor brands wants a daily Slack digest of new launches. A marketplace ops team flagging unauthorised resellers needs to detect when an unknown seller's SKU appears under their brand. An analyst watching Reliance's private-label strategy wants the launch-velocity curve per house brand. A dropshipper looking for trending high-discount categories tracks discount_percent moves across whole verticals. All reduce to daily snapshots, sku-keyed dedup, and set-difference logic.

How does this compare to the alternatives?

Approach Reliability Setup time Maintenance
Manual catalog browsing Low — cannot scale to a brand-wide watch Continuous analyst time Continuous
AJIO seller dashboard (own SKUs only) Limited to your own listings Days Per-account login
Thirdwatch AJIO Scraper + diff pipeline Production-tested, full public catalog Half a day Thirdwatch maintains the actor

The AJIO seller dashboard only exposes your own listings, not competitors'. There is no public competitor-catalog feed. The AJIO Scraper actor gives you the full public catalog at pay-per-result, suitable for daily competitor-brand monitoring.

How to monitor AJIO catalog changes in 5 steps

Step 1: How do I authenticate against Apify?

export APIFY_TOKEN="apify_api_xxxxxxxxxxxxxxxx"

Step 2: How do I snapshot a brand's full catalog daily?

Run the actor with the brand name as the query and maxResults set high enough to capture the full visible catalog.

import os, json, datetime, pathlib
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

BRANDS = ["AJIO Own", "Netplay", "Teamspirit", "Performax",
          "Levi's", "Allen Solly", "Biba", "HRX"]

run = client.actor("thirdwatch/ajio-scraper").call(run_input={
    "queries": BRANDS,
    "sortBy": "newest",
    "maxResults": 1000,
})

records = list(client.dataset(run["defaultDatasetId"]).iterate_items())
today = datetime.date.today().isoformat()
pathlib.Path("snapshots").mkdir(exist_ok=True)
pathlib.Path(f"snapshots/ajio-{today}.json").write_text(json.dumps(records))
print(f"{today}: {len(records)} SKUs across {len(BRANDS)} brands")

Sort by newest so the most recent launches appear first within each brand's slice — useful when AJIO truncates very large brand catalogs.

Step 3: How do I diff today's snapshot against yesterday?

Use sku as the natural key. SKUs in today but not yesterday are new launches; SKUs in yesterday but not today are stockouts or delistings.

import pandas as pd, glob

paths = sorted(glob.glob("snapshots/ajio-*.json"))
yest_path, today_path = paths[-2], paths[-1]

yest = pd.DataFrame(json.loads(pathlib.Path(yest_path).read_text()))
today = pd.DataFrame(json.loads(pathlib.Path(today_path).read_text()))

yest_skus = set(yest.sku.astype(str))
today_skus = set(today.sku.astype(str))

new_launches = today[today.sku.astype(str).isin(today_skus - yest_skus)]
dropped = yest[yest.sku.astype(str).isin(yest_skus - today_skus)]

print(f"New launches: {len(new_launches)}")
print(f"Dropped / OOS: {len(dropped)}")
print(new_launches[["brand", "product_name", "price", "discount_percent",
                    "category", "url"]].head(20))

For most brands a daily diff returns 5 to 40 new launches and a similar number of drops — comfortably digestible as a Slack digest.

Step 4: How do I detect MRP edits and discount moves on retained SKUs?

Inner-join yesterday and today on sku, then compare original_price and discount_percent.

retained = today.merge(yest, on="sku", suffixes=("_today", "_yest"))

mrp_edits = retained[
    retained.original_price_today.notna()
    & retained.original_price_yest.notna()
    & (retained.original_price_today != retained.original_price_yest)
]

discount_starts = retained[
    (retained.discount_percent_yest.fillna(0) < 30)
    & (retained.discount_percent_today.fillna(0) >= 30)
]

print(f"MRP edits: {len(mrp_edits)}")
print(f"Discount started (crossed 30%): {len(discount_starts)}")

MRP edits without a discount change typically signal a permanent price reposition — useful for brand ops to flag. Discounts crossing the 30% threshold are the canonical "sale started" signal worth Slack-alerting brand managers.

Step 5: How do I separate stockout from delisting?

For SKUs that disappeared today, attempt a direct URL fetch with httpx (or any HTTP client) and check the response status.

import httpx

def classify_drop(url: str) -> str:
    try:
        r = httpx.get(url, follow_redirects=True, timeout=10.0)
        if r.status_code == 404:
            return "delisted"
        if "currently unavailable" in r.text.lower() or "out of stock" in r.text.lower():
            return "out_of_stock"
        return "still_live_but_unlisted"
    except Exception:
        return "fetch_error"

dropped["status"] = dropped.url.apply(classify_drop)
print(dropped.status.value_counts())

delisted is the operationally interesting bucket — a SKU permanently leaving the catalog often signals brand-relationship change, regulatory issue, or stock burn. out_of_stock is normal churn.

Sample output

A daily-diff digest record looks like this — flat rows ready for Slack or a BI tool.

[
  {
    "event": "new_launch",
    "date": "2026-05-12",
    "sku": "470121983",
    "brand": "Netplay",
    "product_name": "Slim Fit Solid Casual Shirt",
    "price": 899,
    "original_price": 1799,
    "discount_percent": 50,
    "category": "Men > Topwear > Casual Shirts",
    "url": "https://www.ajio.com/p/470121983"
  },
  {
    "event": "dropped",
    "date": "2026-05-12",
    "sku": "468023411",
    "brand": "AJIO Own",
    "product_name": "Round Neck Printed Tshirt",
    "last_seen_price": 449,
    "url": "https://www.ajio.com/p/468023411",
    "status": "out_of_stock"
  },
  {
    "event": "discount_started",
    "date": "2026-05-12",
    "sku": "469712238",
    "brand": "Levi's",
    "product_name": "511 Slim Fit Mid Rise Stretchable Jeans",
    "discount_yest": 20,
    "discount_today": 45,
    "price_today": 2199,
    "url": "https://www.ajio.com/p/469712238"
  }
]

event is the natural facet for routing into different Slack channels (#launches, #stockouts, #sale-watch). sku is the stable join key for time-series analytics in your BI layer.

Common pitfalls

Three things go wrong in production AJIO catalog monitors. Pagination truncation — AJIO caps listing depth around 4,000–5,000 results per query; for very large brand catalogs (AJIO Own across all categories) you'll need to shard your queries by sub-category to capture the full tail. False-positive drops — a SKU can fall off the listing API for a single day due to AJIO's internal indexing without being out of stock. Use a 2-day rolling window (drop only counts if absent 2 days in a row) to suppress that noise. Brand-name normalisation — AJIO writes "Levi's" with an apostrophe, "AJIO Own" with a capital JIO; lower-case and strip non-alphanumerics before joining brand-keyed snapshots.

Thirdwatch's actor handles AJIO's anti-bot defences and proxy rotation transparently. A 5,000-SKU brand snapshot completes in well under ten minutes — small enough to run multiple snapshots per day during sale events without infrastructure overhead.

Related use cases

Frequently asked questions

What kinds of catalog changes can I track?

Four event types matter operationally: new SKUs appearing (new launches), SKUs disappearing (out-of-stock or delisted), MRP edits (original_price changes), and discount_percent moves (sale window starts and ends). The actor returns a stable sku field per product, so day-over-day set differences cleanly separate new from dropped from edited SKUs.

How do I detect new launches reliably?

Sort by newest, snapshot a brand's full catalog daily, and compute the set difference of sku between today and yesterday. SKUs in today but not yesterday are new launches. Use sortBy newest in the input plus a high maxResults to ensure you capture the launch wave before AJIO paginates past it.

How do I avoid noise from AJIO's catalog reshuffling?

AJIO occasionally re-indexes its category taxonomy — the same SKU can appear under Indian Wear on Monday and Ethnic Wear on Tuesday. Pin downstream comparisons on sku and brand, not on category. Use planning_category (AJIO's internal stable code) for time-series stability if you need to slice by category.

What cadence should I use for catalog monitoring?

Daily is the right baseline. AJIO refreshes its catalog overnight India time, so an early-morning IST snapshot captures yesterday's launches and yesterday's stockouts. During End of Season Sale or Big Bold Sale windows, increase to every 4 to 6 hours to catch flash launches and rapid stockout cycles.

How do I detect an out-of-stock SKU vs a deletion?

AJIO doesn't explicitly mark SKUs as out-of-stock in the listing API — they simply disappear from the search/category browse. To distinguish temporary stockout from permanent delisting, attempt a single product URL fetch on disappearance and check whether the URL still resolves. If it 404s, it's a true delisting; if it loads but is not in the listing, it's stocked out.

Can I monitor a single brand across all categories?

Yes. Run the actor with queries set to the brand name (e.g. AJIO Own, Netplay, Levi's) and category set to all. Set maxResults to 1000 to catch the full brand catalog in a single run. Subsequent days' runs against the same input produce comparable snapshots for set-difference logic.

Related

Try it yourself

100 free credits, no credit card.

About 30 real searches. Add the MCP to Claude or Cursor in two minutes.