# Flipkart Products Scraper (`scrapyx/flipkart-products-scraper`) Actor

Product listings from Flipkart search and browse pages: title, price and MRP, rating with its full 5-star histogram, review counts, key specs and images. Cross-page de-duplication and a relevance check on every query.

- **URL**: https://apify.com/scrapyx/flipkart-products-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.05 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Flipkart Products Scraper

Product listings from Flipkart search and browse pages — title, price and
MRP, rating with its **full 5-star histogram**, review counts, key specs and
images.

HTTP only, no browser, no login.

### Input

```json
{
  "mode": "search",
  "keywords": ["laptop", "wireless earbuds"],
  "sortBy": "priceDesc",
  "maxPages": 3,
  "maxItems": 200
}
```

Or point it at listing URLs you already have:

```json
{
  "mode": "urls",
  "listingUrls": ["https://www.flipkart.com/search?q=keyboard"]
}
```

### What you get

| `recordType` | One per | Carries |
| --- | --- | --- |
| `SEARCH_SUMMARY` | keyword / URL | pages fetched, rows fetched vs returned, duplicates dropped, why paging stopped, **and a relevance score for the query** |
| `PRODUCT` | product | id, URL, title, price, MRP, rating + histogram, review count, key specs, images — plus the full raw upstream object |
| `ERROR` | failed input | why |

```jsonc
{
  "recordType": "PRODUCT",
  "productId": "COMH8Z9ABCDEFGHI",
  "productUrl": "https://www.flipkart.com/lenovo-100e-chromebook-...",
  "title": "Lenovo 100e Chromebook Gen 4 MediaTek Kompanio 520 - (4 GB/...)",
  "currency": "INR", "currentPrice": 16500, "strikeOffPrice": 24990,
  "ratingAverage": 4, "ratingCount": 3333, "reviewCount": 307,
  "ratingBreakup": [455, 155, 242, 561, 1920],   // 1★ … 5★
  "imageUrls": ["...", "..."],
  "raw": { "...": "upstream's object, untouched" }
}
```

`ratingBreakup` is the 1★-to-5★ vote distribution — unusual to get from a
listing page rather than a product page, and enough to compute your own
weighted scores or spot review-bombing.

### Known limits — read these before you rely on the output

**Flipkart has no "no results" page, and this is the big one.** An unmatched
query returns `HTTP 200` with ~40 **unrelated** products —
`q=zzzqqqnotarealproduct12345` returned wooden toddler puzzles, magic
copybooks and rose face wipes. It is not even a fixed fallback list: two
different nonsense queries returned two completely different junk sets with
zero overlap. Nothing in the response marks them as junk.

So every query's relevance is **measured and reported**. `titleMatchRate` is
the fraction of returned products matching a query token across title,
subtitle, Flipkart's own category (`vertical`) and key specs, and
`lowRelevanceWarning` flags a run below 20%. Measured separation:

| query | rate |
| --- | --- |
| `headphones`, `mobile`, `watches` | 1.00 |
| `running shoes` | 0.98 |
| `laptop` | 0.92 |
| `shoes` | 0.70 |
| three different nonsense strings | **0.00** |

These rows are never silently dropped — a low score is a fact about your
query that you should see, not a licence for this actor to decide which
products count.

**Pages overlap, so products are de-duplicated.** Page 2 shares ~9 of 24
products with page 1. That is genuine repetition in Flipkart's own paging,
not randomness: page 1 fetched twice returned an identical 24/24 set.
`duplicatesDropped` tells you how many were removed.

**Page size is not fixed.** 24 products on a grid-layout query, 40 on a
carousel-layout query. Flipkart picks the layout per query; it carries no
meaning. Set `maxItems` rather than reasoning from page counts.

**India only, INR only.** flipkart.com serves one market and there is no
locale switch, so `currency` is always `INR`.

**Single product pages are not supported.** `/p/…` is a different layout;
those URLs are refused with an explanation rather than half-parsed.

**MRP is often absent.** `strikeOffPrice` was present on 27 of 30 in
testing — products with no discount simply have no strike-off price. It is
left `null`, never copied from the sale price.

### Technical

Server-rendered React; the payload is a JSON object on
`window.__INITIAL_STATE__` (~354 KB). Products are located structurally
rather than by a fixed path, because slot-group keys are numeric and change
per query.

No WAF observed: 3/3 TLS profiles returned 200. Past the end, paging is
honest — `page=9999` returns 200 with zero products.

`robots.txt` checked: no `ClaudeBot`/`anthropic-ai` group, no blanket
disallow; `/search` verdict ALLOWED.

Full recon trail is in `CRAWLING_METHOD.md`.

# Actor input Schema

## `mode` (type: `string`):

'search' builds Flipkart search URLs from your keywords. 'urls' takes Flipkart search or browse listing URLs you already have. Single product pages (/p/…) are a different layout and are refused with an explanation.

## `keywords` (type: `array`):

Search terms, one per row. Each is paged independently. Note Flipkart never returns a 'no results' page — an unmatched query comes back as HTTP 200 with unrelated products — so every keyword's relevance is measured and reported as 'titleMatchRate'.

## `listingUrls` (type: `array`):

Flipkart search or browse listing URLs. Used by the 'urls' mode.

## `sortBy` (type: `string`):

Result ordering, passed through as Flipkart's own sort value.

## `maxPages` (type: `integer`):

How many listing pages to fetch per keyword or URL. Page size varies with the layout Flipkart picks: 24 products on a grid query, 40 on a carousel query. Paging also stops early on an empty page or one that introduces no new products.

## `maxItems` (type: `integer`):

Optional cap on total product rows across the whole run, shared across every keyword. Counted AFTER de-duplication, so you get the number you asked for.

## `maxConcurrency` (type: `integer`):

How many requests may be in flight at once. Each search page is 550-820 KB, so this trades memory and politeness for wall-clock time.

## `minRequestInterval` (type: `number`):

The honest speed control: the shortest gap between two request starts. No WAF or rate limiting was observed during testing; this is routine pacing.

## `proxyConfiguration` (type: `object`):

Apify Proxy on the shared datacenter pool. This is the default because it is included in your plan at no extra cost and this target works through it. If you start seeing blocks, challenges or empty results, switch the group here to Residential -- it uses real consumer IPs and gets through more, but Apify bills residential traffic per gigabyte, so leave it off unless you need it.

## Actor input object example

```json
{
  "mode": "search",
  "keywords": [
    "laptop"
  ],
  "listingUrls": [],
  "sortBy": "relevance",
  "maxPages": 3,
  "maxConcurrency": 3,
  "minRequestInterval": 0.8,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/flipkart-products-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/flipkart-products-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call scrapyx/flipkart-products-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/flipkart-products-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/27oJIiRVHyXBOaLQk/builds/HTbxr7cuKTZUpqoHx/openapi.json
