# Instacart Scraper: Store Prices, Deals & Stock by ZIP (`moggedhq/instacart-price-scraper`) Actor

Get Instacart products for any store, for example Costco, Sprouts or Publix, at your ZIP: Instacart price, sale and coupon deals with dates, unit price, stock, size, brand and UPC where shown. Search, categories or product links. Compare one product across stores. About $0.005 per product. No login.

- **URL**: https://apify.com/moggedhq/instacart-price-scraper.md
- **Developed by:** [mogged](https://apify.com/moggedhq) (community)
- **Categories:** E-commerce, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 products

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

## Instacart Scraper: Store Prices, Deals & Stock by ZIP

For grocery price analysts, brands and comparison services monitoring the price a shopper sees at a particular Instacart store. About **$0.005 per delivered product**, or **$0.10 for 20 products**, plus the minimum **$0.00005 Actor start charge**. No Instacart login, account cookies or retailer API key is required.

Collect US and Canadian Instacart delivery prices from searches, product IDs, product links, store collections and deals pages. Select retailers such as Costco, Safeway, Sprouts, Publix, ALDI, Walmart or Loblaws and supply ZIP or postal codes. Every row identifies the retailer, Instacart shop, physical retailer location and requested postal zone. Availability depends on which stores serve that location.

### What you get

The output uses the same core field names as the grocery price scraper family. A readable verdict comes first. One product at one store is one price observation; repeated matches within that run are delivered and charged once.

| Field | Meaning |
| --- | --- |
| `verdict` | Product, current price, store and relevant sale or stock signal. |
| `retailer`, `country`, `currency` | Store banner, US or CA, and USD or CAD. |
| `storeId`, `storeName`, `location` | Instacart shop ID, retailer name and requested ZIP or postal code. |
| `productId`, `sku`, `gtin` | Instacart product ID, published external SKU and barcode when supplied. Missing identifiers stay null. |
| `title`, `brand`, `size` | Source product name, brand and package label. |
| `price`, `regularPrice`, `onSale` | Current displayed price, published struck-through price and sale comparison. |
| `promoText`, `promoType` | Published offer wording and a plain classification. |
| `promoStart`, `promoEnd` | Published promotion dates. Start dates are commonly unavailable. |
| `memberPrice`, `memberProgram` | Explicit loyalty price and program label, when shown publicly. |
| `unitPrice`, `unitOfMeasure` | Published numeric unit price and its unit, including `each`, `fl oz` or `100g`. |
| `inStock`, `stockLevel` | Source availability and numeric quantity if supplied. Numeric shelf quantity normally remains null. |
| `rating`, `reviewCount` | Supplied product review aggregates. |
| `category`, `url`, `imageUrl`, `scrapedAt` | Category, public product link, image and UTC observation time. |

Instacart extras include `instacartRetailer`, `retailerSlug`, `shopId`, `retailerId`, `retailerLocationId`, `postalCode`, `zoneId`, `serviceType`, `storeAddress`, `inStockLikelihood`, `stockLabel`, `priceString`, `unitPriceString`, `offers`, `isDeal`, `priceRequiresMembership`, `requestedLocations`, `sourceType` and `sourceUrl`. Optional `details` contains public product detail data. Optional `availableRetailers` checks the product at other selected shops.

The overview dataset view shows title, current and regular price, promotion, member price, unit price, stock and store. The deals view emphasizes offer fields. The details view exposes the common schema and retailer extras for export. Free explanatory rows have `recordType: "NOTE"`; delivered products have `recordType: "PRODUCT"`.

### Understand the price and the offer

**These are Instacart prices. They can differ from the retailer's in-store prices.** Taxes, delivery fees, tips, account-specific offers and checkout eligibility are outside the advertised product price.

`price` is the displayed product price at the resolved shop and postal zone. `regularPrice` retains an explicit source comparison price; it is not invented by repeating the current price. Weighted products can show estimated package prices, so keep `soldBy`, `isEstimatedPrice` and the source unit-price text.

Coupons and spend or quantity offers remain separate. A “Spend $25, save $5” offer does not subtract $5 from each product. Each `offers` entry preserves its source label, clipping state where supplied, expiry text, quantity limits, minimum purchase and written conditions. No coupon is clipped and no cart is changed.

A private cloud deals test on 3 November 2026 returned five products with five product charges. One Ferrero Rocher item showed $16.78, a $21.28 regular price, “$4.50 off; limit 5” and an expiry of `2026-11-16T03:00:00-05:00`, with the condition “or while supplies last.” A Colgate offer also included a separate spend promotion. Conditions remain separate from checkout totals.

When a row has multiple offers, `promoEnd` is the earliest published expiry and `promoEndConditions` keeps each original expiry statement. Use the individual offers to reason about eligibility. A missing start date, barcode, member price, rating or stock quantity remains null. UPC coverage is sparse; this Actor does not derive barcodes from product IDs or package pictures.

### Start in three steps

1. Enter retailer slugs and US ZIPs or full Canadian postal codes.
2. Add search terms, collection links or exact product IDs and set the product limits.
3. Run, check SUMMARY for source coverage, then export JSON, CSV or Excel.

The prefill searches milk at Costco for ZIP 10001 with a 20-product cap. A private cloud run delivered 20 unique products with 20 accepted charges and no source failures in 33.8 seconds. A Toronto test delivered ten Costco products in 30.2 seconds. Two larger cloud runs delivered 1,100 products across three stores and 1,091 across four stores, with matching product charges, no duplicates and no source failures.

### Inputs

| Input | Example and behavior |
| --- | --- |
| `searchTerms` | `["milk", "coffee"]`, searched at each selected shop. |
| `startUrls` | HTTPS collection, product, search, flyer or store links. A store link browses its departments. |
| `productIds` | `["31895"]`, the number at the start of a public product URL. |
| `locations` | `["10001", "94105", "M5V 3L9"]`. Empty uses the site's visitor default location. |
| `storeIds` | Exact Instacart shop IDs, verified within the selected postal zone. Pair these with locations for recurring work. |
| `retailers` | Store slugs such as `costco`, `safeway`, `sprouts`, `publix` or `loblaws`. Defaults to Costco when no store links or IDs are supplied. |
| `maxItemsPerSearch` | New observations per source and store; default 20, maximum 1,000. |
| `maxItems` | Global product/store cap; default 20, maximum 10,000. |
| `dealsOnly` | Keep source sales, promotions and explicit member prices. |
| `includeDetails` | Add public product metadata through extra requests, with no additional product fee. |
| `availableRetailers` | Check whether the product is carried by other selected shops at the same postal code. Adds requests. |
| `proxyConfiguration` | Optional custom proxy settings. Default datacenter routing precedes country-matched residential retries. |

Canadian `costco` and `walmart` selections resolve to `costco-canada` and `walmart-canada`; exact Canadian slugs are also accepted. Canadian coordinates use the postal-area centre, while the full postal code selects the delivery zone. US coordinates use the ZIP centre. Store discovery does not promise street-address delivery eligibility.

A two-country comparison:

```json
{
  "retailers": ["costco", "walmart"],
  "searchTerms": ["milk", "coffee"],
  "locations": ["10001", "M5V 3L9"],
  "maxItemsPerSearch": 10,
  "maxItems": 80
}
```

A category example:

```json
{
  "startUrls": ["https://www.instacart.com/store/costco/collections/produce"],
  "locations": ["94105"],
  "maxItemsPerSearch": 100,
  "maxItems": 100
}
```

For exact monitoring, use `productIds: ["31895"]`, `retailers: ["costco"]` and `locations: ["10001", "94105"]`. A product not carried at a selected shop is excluded free. Product URLs do not override the run's postal selection. Verify the website's selected ZIP before manually comparing a page.

### Real output example

Selected fields from the 3 November 2026 ZIP 10001 cloud run:

```json
{
  "retailer": "Costco",
  "country": "US",
  "currency": "USD",
  "storeId": "968",
  "retailerLocationId": "284",
  "location": "10001",
  "productId": "22165660",
  "title": "Kirkland Signature Organic A2 Whole Milk, Half Gallon, 3-count",
  "price": 18.03,
  "regularPrice": null,
  "unitPrice": 0.09,
  "unitOfMeasure": "fl oz",
  "inStock": true
}
```

### Pricing and spending limits

A product at two stores is two observations. Overlapping searches and URLs at one shop produce one observation. Notes, summaries, duplicates, failed requests, unavailable products and empty results have no product charge. There is no default dataset-row fee or separate detail event.

| Products | Base | Bronze | Silver | Gold |
| --- | --- | --- | --- | --- |
| 20 | $0.10 | $0.095 | $0.09 | $0.08 |
| 100 | $0.50 | $0.475 | $0.45 | $0.40 |
| 1,000 | $5.00 | $4.75 | $4.50 | $4.00 |

Add the minimum $0.00005 start charge. Base price is $0.005 per product, Bronze $0.00475, Silver $0.0045 and Gold $0.004. Apify's maximum total charge controls spending. The Actor checks capacity before more product delivery, stops cleanly at the limit and records the decision in SUMMARY.

### Monitor prices every day

Save a task with stable product IDs, retailer slugs, postal codes and shop IDs. In Apify Console, create a schedule, select that task, choose the recurring schedule and timezone, then connect the completed-run webhook to your database or workflow.

Join observations using `country + storeId + productId`, with `scrapedAt` as the timestamp. Keep current price, regular price, loyalty price and coupon conditions separate. Every scheduled run fetches a fresh observation and charges for products delivered in that run. Historical backfill is unavailable.

SUMMARY includes products, resolved stores, deals found, duplicates, source outcomes, free failures and spending-limit status. Inspect `freeFailures` and `outcomes` before accepting a run as a complete snapshot. A run can deliver useful partial coverage while clearly identifying a failed source. Missing stores and refused requests are distinguished.

### API and automation

Start a run with your own Apify token, then fetch its dataset and SUMMARY:

```bash
curl -X POST \
  'https://api.apify.com/v2/acts/moggedhq~instacart-price-scraper/runs' \
  -H 'Authorization: Bearer YOUR_APIFY_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"searchTerms":["milk"],"retailers":["costco"],"locations":["10001"],"maxItems":20}'
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("moggedhq/instacart-price-scraper").call(
    run_input={"searchTerms": ["coffee"], "locations": ["M5V 3L9"], "maxItems": 20}
)
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('moggedhq/instacart-price-scraper').call({
  searchTerms: ['milk'], retailers: ['costco'], locations: ['10001'], maxItems: 20
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Filter `recordType` when importing the dataset into Make, Zapier, n8n, Sheets or webhooks.

### Use with AI agents (MCP)

Connect your agent to `https://mcp.apify.com`. Ask for Instacart grocery prices at specific retailers and ZIPs, regular prices, unit prices, stock and offer expiry dates. Supply a product cap. Ask the agent to inspect SUMMARY, preserve nulls and distinguish coupon conditions from current price. Use exact product IDs for a repeated basket, then compare snapshots in your own database.

### Reliability and limits

Requests are sequential within each run, paced two seconds apart. Retries use fresh anonymous visitor sessions. Default datacenter routing comes first; residential retries match the country. The scraper never imports account cookies, logs in, solves a CAPTCHA or uses a paid unblocking service.

The site's own public data calls provide prices. Product item IDs must match the selected physical retailer location before delivery. Saved source snapshots, dataset rows and acknowledged charge receipts survive a reboot. Delivery and charging are serial; recovery reconciles saved rows against authoritative charge counts. Ambiguous billing evidence stops further charges.

Search reads one public result batch per term and store. Collections return at most 1,000 IDs each; exhaustive catalog coverage is not promised. The per-source cap is a ceiling. Store links browse departments; overlap remains free. Unavailable retailers, historical prices and personalized offers are excluded.

Optional availability comparisons report only selected stores at the same postal code. `productCarried: null` means that check was unavailable. The public source's stock labels are likelihood signals rather than audited shelf quantities. Details and barcodes can remain null.

Postal coordinates come from Zippopotam.us, with source postal data credited to GeoNames under CC BY 4.0. Instacart's public postal autocomplete is a fallback. Product prices and stock come from Instacart, not from the coordinate provider.

### FAQ

**Are these the prices inside Costco or another physical store?** They are Instacart's displayed delivery prices for the resolved shop. A retailer may use different prices in store.

**Can I choose a physical branch?** Supply its Instacart shop ID with the postal location. Rows also identify the physical `retailerLocationId` and public address.

**Are coupons applied?** No. Published offer labels, dates, limits and clipping conditions are collected separately. Checkout eligibility depends on the shopper and basket.

**Why are UPC, start date or member price null?** The public source did not publish a verified value for that product. IDs and prices are never used to manufacture a barcode or promotion date.

**What happens with bad input?** Parseable invalid input produces free explanatory notes and SUMMARY. Apify can reject schema-invalid input before a run starts; neither path adds a product charge.

**Does this give me all stores in North America?** It supports public Instacart stores serving the requested postal locations. Coverage must be checked in each run's resolved stores and source outcomes.

This independent Actor has no affiliation with Instacart or the retailers named here.

# Actor input Schema

## `searchTerms` (type: `array`):

Search terms to run at each selected store. The source may return fewer matches than your cap.

## `startUrls` (type: `array`):

HTTPS Instacart collection, deals, store, search or product links. Store links browse departments. The run locations determine the price context.

## `productIds` (type: `array`):

Instacart product IDs, the number at the start of a /products/ URL. Each is priced at each selected shop; unavailable cells are free.

## `locations` (type: `array`):

US ZIPs or full Canadian postal codes, for example 10001, 60614 or M5V 3L9. Empty uses the site visitor default location. Canadian store discovery uses the postal-area centre.

## `storeIds` (type: `array`):

Exact Instacart shop IDs, for example 968 for a Costco delivery shop serving 10001. IDs must be present in the selected postal zone. Returned rows also include retailerLocationId.

## `maxItemsPerSearch` (type: `integer`):

Maximum new product rows from each term, category or deals source at one store. Duplicates are free.

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

Global limit across all products and stores. About $0.005 per product: 20 products cost about $0.10 plus the small start charge.

## `dealsOnly` (type: `boolean`):

Keep source sale prices, published promotions and member prices. Coupon conditions remain separate from the displayed price.

## `includeDetails` (type: `boolean`):

Add slower public ingredient, nutrition and product detail fields. No additional event charge. UPC is null when it is not published.

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

Default datacenter pool first; country-matched residential retries only when needed. Custom proxy settings replace this routing. No account cookies or logins.

## `retailers` (type: `array`):

Instacart store slugs, for example costco, sprouts, publix, safeway or real-canadian-superstore. Empty with store links uses those stores. Empty otherwise defaults to Costco. Only stores serving the selected location are returned.

## `availableRetailers` (type: `boolean`):

Check whether this product is carried by each selected store at the same postal code. Adds public product requests. A refused check remains null; it is never guessed.

## Actor input object example

```json
{
  "searchTerms": [
    "milk"
  ],
  "locations": [
    "10001"
  ],
  "maxItemsPerSearch": 20,
  "maxItems": 20,
  "dealsOnly": false,
  "includeDetails": false,
  "retailers": [
    "costco"
  ],
  "availableRetailers": false
}
```

# Actor output Schema

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

No description

## `dealsView` (type: `string`):

No description

## `dealsOnly` (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 = {
    "searchTerms": [
        "milk"
    ],
    "locations": [
        "10001"
    ],
    "maxItemsPerSearch": 20,
    "maxItems": 20,
    "retailers": [
        "costco"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("moggedhq/instacart-price-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 = {
    "searchTerms": ["milk"],
    "locations": ["10001"],
    "maxItemsPerSearch": 20,
    "maxItems": 20,
    "retailers": ["costco"],
}

# Run the Actor and wait for it to finish
run = client.actor("moggedhq/instacart-price-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 '{
  "searchTerms": [
    "milk"
  ],
  "locations": [
    "10001"
  ],
  "maxItemsPerSearch": 20,
  "maxItems": 20,
  "retailers": [
    "costco"
  ]
}' |
apify call moggedhq/instacart-price-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,moggedhq/instacart-price-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/nDcvRGY58wdc2ngpW/builds/BoVefodfeUkU0ppzR/openapi.json
