# Swiggy Instamart Scraper (`code-for-everyone/swiggy-instamart-scraper`) Actor

\[💰 $1.5 / 1K] Live Swiggy Instamart brand, prices, MRP, discounts, stock, ratings, category, description, image and sponsored flags, pinned to your city and neighbourhood. Search keywords or sweep categories, and flag price and stock changes between runs.

- **URL**: https://apify.com/code-for-everyone/swiggy-instamart-scraper.md
- **Developed by:** [Code for Everyone](https://apify.com/code-for-everyone) (community)
- **Security:** Limited permissions
- **Stats:** 5 total users, 3 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.50 / 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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Swiggy Instamart Scraper do?

**Swiggy Instamart Scraper** collects product data from [Swiggy Instamart](https://instamart.in), India's quick-commerce grocery service. Give it a few search words (like "milk" or "amul butter") or category links, tell it which city and neighbourhood to shop from, and it returns a clean table with **prices, MRP, discounts, ratings, stock status and sponsored (ad) placements**.

What makes it different: **it remembers your last run.** From the second run onward, every row tells you whether its **price or stock status changed** since you last scraped it, and by how much. Tracking works per pack size, so a 1 L bottle changing price never gets confused with the 500 ml one. There is even a separate "Price & Stock Changes" table with only the items that moved, so you never have to scroll through things that stayed the same.

Because it runs on Apify, you also get scheduling, an API, integrations (Google Sheets, Zapier, Make, webhooks), proxy rotation and run monitoring out of the box.

### Why use Swiggy Instamart Scraper?

- **Price monitoring:** watch how prices for your products, or your competitors' products, move day to day.
- **Local price comparison:** Instamart prices and stock depend on the delivery area. Compare one neighbourhood against another.
- **Stock tracking:** find out when a product goes out of stock or comes back.
- **Ad intelligence:** see which brands pay for sponsored placements on a keyword, and which keyword they bid on.
- **Market research:** build a catalogue of brands, pack sizes, ratings and categories for any area.
- **No login needed:** the Actor reads the same public pages any visitor sees. You do not share any account or password.

### Use cases and examples

#### 1. Catch a competitor's price cut the morning it happens

You sell cooking oil and want to know the moment a rival changes price. Run this on a schedule every
morning:

```json
{
    "searchQueries": ["fortune sunflower oil", "saffola gold", "dhara mustard oil"],
    "city": "Bengaluru",
    "area": "Koramangala",
    "maxResults": 50
}
```

Then open only the **Price & Stock Changes** table. On a quiet day it is empty. On the day a rival
drops a 1 L bottle from ₹169 to ₹149, you get one row with `previousPrice: 169`, `price: 149` and
`priceChangePercent: -11.8`. Pipe that table into Slack or email through an Apify integration and
you have a price alert, not a spreadsheet to read.

#### 2. Find out how much the same basket costs across the city

Instamart prices differ by neighbourhood. Run the same keywords once per area, changing only the
`area` field:

```json
{
    "searchQueries": ["amul butter", "milk", "brown bread", "eggs"],
    "city": "Mumbai",
    "area": "Bandra West",
    "maxResults": 30
}
```

Repeat for `Andheri East`, `Powai`, and so on, then stack the datasets and pivot on `skuId` with
`area` as columns. Joining on `skuId` rather than the product name keeps the comparison honest,
because the same tile can hold several pack sizes. The result is a straight answer to "is the same
500 g pack of butter cheaper in Bandra or Powai?", useful for choosing where to launch, where to
price-match, or just for a story about city price gaps.

#### 3. See who is paying to sit above you in search

Every row carries `isAd`, and ad rows carry `adKeyword`, the keyword the advertiser bid on. Scrape a
set of category keywords, then group by `brand` where `isAd` is true:

```json
{
    "searchQueries": ["protein bar", "muesli", "granola", "peanut butter"],
    "city": "Delhi",
    "area": "Hauz Khas",
    "maxResults": 60
}
```

You get a share-of-voice table: which brands buy sponsored slots on which keywords, and how often.
Run it weekly and you can see a competitor's campaign start and stop. Filter `isAd` to false instead
and you get the organic ranking, which is a cleaner read on what is genuinely selling.

#### 4. Watch for stock-outs on your own products

Set your own SKUs as keywords, schedule it a few times a day, and watch
`stockStatusChanged` in the Changes table. A row where `previousInStock: true` and `inStock: false`
means the dark store serving that neighbourhood has run dry, which is a distribution problem you can
act on the same day instead of finding it in next month's sales report.

### How to use Swiggy Instamart Scraper

1. Open the Actor and go to the **Input** tab.
2. Type the **City** and **Area / neighbourhood** you want prices for, for example `Bengaluru` and `Koramangala`.
3. Add one or more **Search keywords**, and/or paste **Category URLs** from Instamart.
4. Choose how many rows you want per keyword or category in **Max results**.
5. Click **Start**. Most runs finish in a few minutes.
6. Open the **Output** tab to see the results, or download them as JSON, CSV, Excel, HTML or XML.
7. **Set up a schedule** (for example once or twice a day) so that price changes are tracked automatically. A single run has nothing to compare with, so scheduling is what unlocks the change-tracking.

### Input

| Field                                  | What to enter                                                                                                                                                                                                                                     |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Search keywords**                    | Words to search for, one per line (for example `milk`, `eggs`).                                                                                                                                                                                   |
| **Category URLs**                      | Links to Instamart category pages, one per line, for example `https://instamart.in/c/fresh-vegetables/st`. A plain name like `Fresh Fruits` or `Atta, rice and dal` works just as well — the Actor looks the category up in the store's own menu. |
| **City**                               | City of the delivery address, for example `Mumbai`.                                                                                                                                                                                               |
| **Area / neighbourhood**               | Neighbourhood of the delivery address, for example `Andheri West`. Prices change from area to area.                                                                                                                                               |
| **Max results per keyword / category** | How many rows to collect for each keyword and each category (separately). One row is one pack size. Default: 100.                                                                                                                                 |
| **Include every pack size**            | On by default. See [Pack sizes](#pack-sizes-and-how-rows-are-counted) below.                                                                                                                                                                      |
| **Only confident matches (search)**    | Off by default. Drops search results that Instamart does not label a confident match, so a misspelled keyword returns no rows. See the FAQ.                                                                                                       |
| **Proxy configuration**                | Pre-set to Indian residential proxies, which gives the best chance of a smooth run.                                                                                                                                                               |
| **Store ID (advanced)**                | Leave empty. Only for users who already know the Instamart store ID of their area.                                                                                                                                                                |

Example input:

```json
{
    "searchQueries": ["milk", "amul butter"],
    "categoryUrls": ["https://instamart.in/c/fresh-vegetables/st"],
    "city": "Bengaluru",
    "area": "Koramangala",
    "maxResults": 100,
    "includeAllVariants": true
}
```

#### Pack sizes and how rows are counted

On Instamart a single product tile can hold several pack sizes (500 ml, 1 L, and so on), and **each
pack size has its own price and its own stock status**. So one pack size is one row, and price
tracking follows each pack size separately. A 1 L bottle going up in price does not make the 500 ml
bottle look like it changed.

Leave **Include every pack size** on to get all of them. Turn it off if you only want the one size
Instamart shows in its listing, which means fewer rows and a lower cost.

### Output

Each product is one row. Here is a shortened example from a second run, where the price went up by 2 rupees:

```json
{
    "productId": "G3UN48UFZ6",
    "skuId": "QMXJB9J45Y",
    "spinId": "QRMK9UXYP9",
    "name": "Thirumala Toned Milk",
    "brand": "Thirumala",
    "quantity": "500 ml",
    "isListingVariant": true,
    "variantCount": 3,
    "price": 27,
    "mrp": 29,
    "savings": 2,
    "discount": "6% OFF",
    "rating": 4.2,
    "ratingCount": 5600,
    "inStock": true,
    "isAd": true,
    "adTitle": "Ad",
    "adKeyword": "milk",
    "category": "Milk",
    "superCategory": "Dairy, Bread and Eggs",
    "productUrl": "https://instamart.in/item/G3UN48UFZ6",
    "spinUrl": "https://instamart.in/p/QRMK9UXYP9",
    "storeId": "1404917",
    "city": "Bengaluru",
    "area": "Koramangala",
    "sourceQuery": "milk",
    "scrapedAt": "2026-10-04T08:30:00.000Z",
    "hasPreviousData": true,
    "priceChanged": true,
    "previousPrice": 25,
    "priceChangeAmount": 2,
    "priceChangePercent": 8,
    "stockStatusChanged": false,
    "previousInStock": true,
    "changed": true
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

The run gives you two tables:

- **All Products:** everything found in this run.
- **Price & Stock Changes:** only products whose price or stock status changed since the previous run. Find it in the **Storage** tab of the run (dataset named `changes`) or on the **Output** tab.

#### Data table

| Field                                                                      | Meaning                                                                                                           |
| -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `productId`                                                                | Stable Instamart product ID for the product tile, the same from run to run                                        |
| `skuId`                                                                    | ID of this specific pack size                                                                                     |
| `spinId`                                                                   | The ID Instamart uses in `/p/` links, handy as a join key                                                         |
| `name`, `brand`, `quantity`                                                | Product name, brand and pack size                                                                                 |
| `isListingVariant`, `variantCount`                                         | Whether this is the pack size shown in the listing, and how many sizes the product has                            |
| `price`, `mrp`, `savings`                                                  | Selling price, maximum retail price and the difference (INR)                                                      |
| `discount`, `discountPercent`                                              | Discount as shown by Instamart, and as a number                                                                   |
| `pricePerUnit`                                                             | Price per unit, when Instamart shows it                                                                           |
| `rating`, `ratingCount`                                                    | Average rating and number of ratings                                                                              |
| `inStock`, `lowStockText`                                                  | Availability in the chosen area, and any "only few left" message                                                  |
| `isAd`, `adTitle`, `adKeyword`, `adAuctionType`                            | Whether it is a sponsored placement, and the keyword it was bought for                                            |
| `searchResultType`                                                         | How confident Instamart is that this answers your keyword, for example `HIGH_CONFIDENCE`. Empty for category rows |
| `category`, `subCategory`, `superCategory`                                 | Instamart categories                                                                                              |
| `image`                                                                    | Product picture                                                                                                   |
| `productUrl`                                                               | `https://instamart.in/item/<productId>`                                                                           |
| `spinUrl`                                                                  | `https://instamart.in/p/<spinId>`                                                                                 |
| `city`, `area`, `storeId`                                                  | The location the data belongs to (`storeId` is the Instamart store serving that area)                             |
| `sourceQuery`, `sourceCategoryUrl`                                         | Which keyword or category produced this row                                                                       |
| `scrapedAt`                                                                | When the row was collected                                                                                        |
| `hasPreviousData`                                                          | `false` the first time a product is seen in this area                                                             |
| `priceChanged`, `previousPrice`, `priceChangeAmount`, `priceChangePercent` | Price change since the last run (positive = price went up)                                                        |
| `stockStatusChanged`, `previousInStock`                                    | Stock change since the last run                                                                                   |
| `changed`                                                                  | `true` if the price or the stock status changed                                                                   |

In the change fields, an empty value (`null`) means "nothing to compare with yet", for example on the first run. `false` means "compared, and nothing changed".

### How much does it cost to scrape Swiggy Instamart?

The Actor is priced at **$3.00 per 1,000 rows** (pay per result), where one row is one pack size. You are charged for rows in the **All Products** table. The extra "Price & Stock Changes" table is free, since those rows are already part of your results.

Examples:

- 5 keywords x 100 rows = up to 500 rows, about **$1.50** per run.
- A daily schedule for 20 keywords x 100 rows = up to 2,000 rows, about **$6.00** per day.

To keep costs predictable, lower **Max results**, use fewer keywords, turn off **Include every pack size**, or set a maximum spending limit on the run. The Actor stops when that limit is reached.

### Tips

- **Schedule it.** Change tracking only works when the Actor runs more than once for the same area. Daily is a good start; use a few times a day if you follow fast-moving prices.
- **Keep your inputs stable.** Price history is stored per city and area. Use the same City and Area text each time to keep comparing against the same history.
- **One area per run.** To compare several neighbourhoods, run the Actor once for each area (or create one saved Task per area).
- **Use focused keywords.** "amul butter 500g" gives you a tighter list than "butter".
- **Max results works per keyword and per category.** Three keywords with Max results 100 can return up to 300 rows.
- **Your history belongs to you.** It is saved in a storage called `swiggy-instamart-price-history` in your own Apify account. Deleting that storage resets change tracking.
- **Join on the IDs, not the name.** Product names change wording; `productId`, `skuId` and `spinId` do not.
- **Category names are enough.** You can paste `Fresh Vegetables` instead of a full link. The Actor reads the store's own menu to find the right section, so it keeps working when Instamart renames or moves sections, and it corrects a link that points at the wrong one.
- **A category not sold in your area is skipped**, and the run carries on with the rest. The full list of categories that area *does* offer is saved as `CATEGORY_CATALOGUE` in the run's key-value store, so you can see what to ask for instead.

### FAQ, disclaimers, and support

**Why are all change fields empty on my first run?**
There is nothing to compare with yet. The first run saves a baseline. From the second run on, the fields fill in.

**Why do I see the same product name on several rows?**
Those are its different pack sizes, and each has its own price. Look at `quantity` and `skuId` to tell them apart, or turn off **Include every pack size**.

**A product appears twice in my results.**
A product is listed once per keyword or category. If it matches two keywords, it appears under each. Within one keyword, duplicates (for example an ad and the regular listing) are removed and the first one is kept.

**I got no results.**
Check that the keyword is spelled correctly and that the area is served by Instamart. If the location cannot be found, the run stops with a clear error message.

**I searched for something that does not exist and still got products.**
That is Instamart's own behaviour: when a keyword matches nothing it answers with loosely related recommendations rather than an empty page. Every row carries a `searchResultType` field showing how confident Instamart is, so you can filter on it afterwards. If you would rather the Actor dropped them for you, turn on **Only confident matches**. It is off by default because the same mechanism also surfaces genuinely related products that many users want to keep. The run log tells you which keywords came back without a confident match.

**A category was skipped.**
That category is not offered in the area you chose. The run continues with your other categories. Open `CATEGORY_CATALOGUE` in the run's key-value store to see the categories that area does have, and use one of those names.

**Is it legal to scrape Swiggy Instamart?**
This Actor only collects publicly visible product information and does not log in or collect personal data. Laws and website terms differ between countries and uses, so make sure your use of the data follows the Swiggy terms of service and applicable laws. This Actor is not affiliated with or endorsed by Swiggy.

**Known limitations**
Instamart can change how its website works at any time, which may temporarily affect the results. Prices and availability are a snapshot of the moment the Actor ran.

**Need help or a custom version?**
Open an issue in the **Issues** tab of this Actor. If you need extra fields, more locations per run or a custom integration, get in touch and we can build it for you.

# Actor input Schema

## `searchQueries` (type: `array`):

Products to search for, one per line (for example: milk, amul butter, eggs).

## `categoryUrls` (type: `array`):

Paste Instamart category page links, one per line, for example https://instamart.in/c/fresh-vegetables/st. A plain category name such as "Fresh Fruits" also works.

## `city` (type: `string`):

City of the delivery address, for example Bengaluru, Mumbai or Delhi.

## `area` (type: `string`):

Neighbourhood of the delivery address, for example Koramangala. Prices and stock change from one area to another.

## `maxResults` (type: `integer`):

Maximum number of rows to collect for EACH keyword and EACH category. One row is one pack size.

## `includeAllVariants` (type: `boolean`):

On by default. Each pack size of a product (500 ml, 1 L, ...) has its own price, so each becomes its own row. Turn this off to get only the pack size Instamart shows in the listing, which gives fewer rows and a lower cost.

## `onlyConfidentMatches` (type: `boolean`):

Off by default. When a keyword matches nothing, Instamart answers with loosely related recommendations instead of an empty page. Turn this on to keep only the products Instamart labels a confident match, so a misspelled keyword returns no rows. Off by default because the labels vary and this can also drop loosely related products you may want. Every row carries a searchResultType field, so you can always filter afterwards instead.

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

Instamart is an Indian service and may block data-center IPs, so an Indian residential proxy is recommended.

## `storeId` (type: `string`):

Leave empty in normal use. If you already know the Instamart store id for your area, enter it to skip the automatic location lookup.

## Actor input object example

```json
{
  "searchQueries": [
    "milk"
  ],
  "categoryUrls": [],
  "city": "Bengaluru",
  "area": "Koramangala",
  "maxResults": 100,
  "includeAllVariants": true,
  "onlyConfidentMatches": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "IN"
  }
}
```

# Actor output Schema

## `products` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "searchQueries": [
        "milk"
    ],
    "categoryUrls": [],
    "city": "Bengaluru",
    "area": "Koramangala",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "IN"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("code-for-everyone/swiggy-instamart-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 = {
    "searchQueries": ["milk"],
    "categoryUrls": [],
    "city": "Bengaluru",
    "area": "Koramangala",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "IN",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("code-for-everyone/swiggy-instamart-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 '{
  "searchQueries": [
    "milk"
  ],
  "categoryUrls": [],
  "city": "Bengaluru",
  "area": "Koramangala",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "IN"
  }
}' |
apify call code-for-everyone/swiggy-instamart-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,code-for-everyone/swiggy-instamart-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/8UP1EtgOLeEuoTabt/builds/VN5GWA5dgwvsMuDUO/openapi.json
