# Instacart Product Scraper (`w3crawler/instacart-product-scraper`) Actor

Extract bounded public Instacart product data with explicit source-access diagnostics.

- **URL**: https://apify.com/w3crawler/instacart-product-scraper.md
- **Developed by:** [w3crawler](https://apify.com/w3crawler) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 products

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Product Scraper

#### Target and scope

This Actor extracts bounded, source-backed product data from official public Instacart search pages or public store-specific product pages. It uses Product JSON-LD, server-rendered product state, and a bounded product-card fallback. It does not log in, use private APIs, solve CAPTCHAs, use stealth, or bypass access controls.

The public page may expose no products to an unauthenticated request, even when a browser shows a login modal or an interactive catalog. Those outcomes become minimal diagnostic rows and an `OUTPUT` summary. The Actor never fabricates a product, price, retailer, rating, or image.

#### Use cases

- Take a small public catalog snapshot for a store and query.
- Compare publicly exposed prices, units, availability, promotions, and product media.
- Inspect a bounded list of official product URLs with `retailerSlug` context.
- Run a scheduled public-data monitor that can distinguish usable data from access barriers.

#### Cost

Apify platform compute, storage, and any explicitly enabled proxy traffic are billed according to your Apify plan. This Actor has no separate service fee. Keep `maxItems`, `maxBytes`, retries, and proxy use bounded to control run time and spend.

### How to use

1. Enter a product `query` and official Instacart `storeSlug`, provide an official `searchUrl`, or supply bounded `productUrls`.
2. Set `maxItems` and the request controls appropriate for a small public request.
3. Run the Actor and inspect the default dataset plus the `OUTPUT` key-value record.

`productUrls` takes precedence over `searchUrl`. In detail mode the Actor makes one bounded request per accepted product URL until `maxItems` normal records are collected. In search mode it makes one bounded search-page request; it does not invent pagination for an infinite-scroll surface. Product IDs are deduplicated by public SKU/product ID/GTIN/MPN and then canonical product URL. Diagnostics do not consume `maxItems`.

### Input

The input schema is the source of truth. All limits below are enforced by the schema and bounded again by the runtime.

| Field                | Type and default            | Bounds and behavior                                                                                                                                                                                                               |
| -------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `query`              | string, `organic milk`      | Product keyword; maximum 200 characters. Used when `searchUrl` and `productUrls` are absent.                                                                                                                                      |
| `storeSlug`          | string, `sprouts`           | Public slug matching `[A-Za-z0-9][A-Za-z0-9-]{0,80}`.                                                                                                                                                                             |
| `searchUrl`          | string, empty               | Optional official HTTPS Instacart search URL; maximum 2,000 characters. Takes precedence over `query`/`storeSlug`.                                                                                                                |
| `productUrls`        | array, empty                | Objects with required `url`; official HTTPS Instacart `/products/` URLs; maximum 2,000 characters per URL. Takes precedence over `searchUrl`. Include `retailerSlug` when the public detail page supports store-specific context. |
| `maxItems`           | integer, `30`               | Normal product rows, from 1 through 100.                                                                                                                                                                                          |
| `timeoutMs`          | integer, `30000`            | Per-request timeout, from 5,000 through 120,000 ms.                                                                                                                                                                               |
| `maxBytes`           | integer, `2000000`          | Maximum retained response size, from 100,000 through 5,000,000 bytes.                                                                                                                                                             |
| `requestDelayMs`     | integer, `0`                | Delay before retries or redirects, from 0 through 10,000 ms.                                                                                                                                                                      |
| `maxRequestRetries`  | integer, `1`                | Retries only timeouts, transport failures, and HTTP 5xx responses; from 0 through 2. Access barriers are not bypassed.                                                                                                            |
| `userAgent`          | string, transparent default | Optional user-agent without control characters; maximum 300 characters.                                                                                                                                                           |
| `proxyConfiguration` | object, direct              | Optional `{ "useApifyProxy": true, "apifyProxyGroups": [], "apifyProxyCountry": "US" }`. At most five non-empty groups; country is an optional two-letter code. Proxy use is explicit and does not bypass access controls.        |

#### Runnable search input

```json
{
  "query": "organic milk",
  "storeSlug": "sprouts",
  "maxItems": 10,
  "maxRequestRetries": 0,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

#### Runnable search-URL input

```json
{
  "searchUrl": "https://www.instacart.com/store/sprouts/search?query=coffee",
  "maxItems": 10,
  "timeoutMs": 30000,
  "maxRequestRetries": 1
}
```

#### Runnable multi-product input

```json
{
  "productUrls": [
    {
      "url": "https://www.instacart.com/products/18602684-green-seedless-grapes-per-lb?retailerSlug=kents-market"
    },
    {
      "url": "https://www.instacart.com/products/220058-topcare-ibuprofen-200-mg-tablets-100-ct?retailerSlug=kents-market"
    }
  ],
  "maxItems": 2,
  "timeoutMs": 30000,
  "maxRequestRetries": 1,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

### Output

The default dataset contains only source-backed `instacart-product` rows. Access diagnostics and run summaries are stored in the `OUTPUT` key-value-store entry and logs. If a run saves products before a later request or output problem, the Actor run succeeds and reports `dataStatus: PARTIAL`. A clean empty result succeeds with `dataStatus: NO_RESULTS`. If a real failure occurs before any product is saved, the Actor run reports `status: FAILED` and `dataStatus: FAILED`; diagnostics are never added to the dataset.

#### Normal product record

```json
{
  "recordType": "instacart-product",
  "recordId": "product_0123456789abcdef0123",
  "source": "Instacart",
  "url": "https://www.instacart.com/store/sprouts/search?query=organic%20milk",
  "sourceUrl": "https://www.instacart.com/store/sprouts/search?query=organic%20milk",
  "extractionMethod": "json-ld",
  "productId": "MILK-001",
  "productName": "Organic Whole Milk",
  "productUrl": "https://www.instacart.com/store/sprouts/products/organic-whole-milk",
  "description": "Organic whole milk from Fresh Farms.",
  "category": "Dairy & Eggs",
  "price": 6.49,
  "priceText": "$6.49",
  "currency": "USD",
  "originalPrice": 8.99,
  "unit": "64 fl oz",
  "imageUrl": "https://www.instacart.com/assets/milk.jpg",
  "imageUrls": ["https://www.instacart.com/assets/milk.jpg"],
  "brand": "Fresh Farms",
  "availability": "in-stock",
  "promotionText": "11% off",
  "isOnSale": true,
  "badges": ["Organic", "Non-GMO"],
  "rating": 4.6,
  "reviewCount": 22,
  "sellerName": "Sprouts Farmers Market",
  "searchQuery": "organic milk",
  "storeSlug": "sprouts",
  "scrapedAt": "2026-09-08T00:00:00.000Z"
}
```

#### Card fallback record

When Product JSON-LD is absent, a qualifying public product card can still produce a normal row. Fields not exposed by that card are omitted; they are never guessed.

```json
{
  "recordType": "instacart-product",
  "recordId": "product_card_7e3b",
  "source": "Instacart",
  "url": "https://www.instacart.com/store/sprouts/search?query=coffee",
  "sourceUrl": "https://www.instacart.com/store/sprouts/search?query=coffee",
  "productName": "Organic Coffee",
  "productUrl": "https://www.instacart.com/store/sprouts/products/organic-coffee",
  "price": 7.99,
  "priceText": "$7.99",
  "originalPrice": 8.99,
  "availability": "Many in stock",
  "badges": ["Organic", "Fair Trade"],
  "imageUrl": "https://cdn.example.test/coffee.jpg",
  "cardPosition": 1,
  "scrapedAt": "2026-09-08T00:00:00.000Z"
}
```

#### `OUTPUT` summary

```json
{
  "status": "SUCCEEDED",
  "runStatus": "SUCCEEDED",
  "dataStatus": "PARTIAL",
  "source": "Instacart",
  "actor": "instacart-product-scraper",
  "sourceMode": "product-detail",
  "targetCount": 2,
  "itemCount": 1,
  "productCount": 1,
  "diagnosticCount": 1,
  "blockedCount": 0,
  "dataAvailable": true,
  "productPagesRequested": 2,
  "productPagesSucceeded": 1,
  "productPagesFailed": 1,
  "optionalFailureCount": 0,
  "sourceTransport": "apify_proxy",
  "fixture": false,
  "requestCount": 2,
  "generatedBy": "OpenAI Codex with GPT-6",
  "completedAt": "2026-09-08T00:00:00.000Z"
}
```

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

### Advanced options and troubleshooting

Start with one store, a small `maxItems`, and no retries. Use `productUrls` when store-specific detail state is required. A larger `maxBytes` retains more server-rendered or structured content but uses more memory. Missing price, rating, review, image, or retailer fields are expected when the public response does not expose them.

- `LOGIN_REDIRECT` or `BLOCKED`: the source required an unauthenticated client to stop; no bypass was attempted.
- `NO_PUBLIC_PRODUCTS`: the bounded response was usable but contained no qualifying public Product JSON-LD, detail state, or product card.
- `HTTP_ERROR`, `TIMEOUT`, or `REQUEST_FAILED`: inspect the URL, timeout, retry count, and run logs.
- `INVALID_INPUT` or `INVALID_PROXY`: correct the input shape; unsupported fields are reported rather than silently used.

### API, support, and Issues

Use the Apify API or Console dataset endpoint to read normal rows and the default key-value store `OUTPUT` record. When reporting an issue, include the Actor version, run ID, input mode, error code, and a short description. Do not include private customer information or credentials.

### Privacy, legal, and non-affiliation

This Actor is not affiliated with, sponsored by, or endorsed by Instacart. It is intended for public, source-backed data only. Follow Instacart's terms, robots guidance, rate limits, privacy rules, and applicable law. Do not use it to log in, collect private customer information, evade security controls, or infer data that the public source did not expose.

# Changelog

This Actor's version history is a separate document: https://apify.com/w3crawler/instacart-product-scraper/changelog.md

# Actor input Schema

## `query` (type: `string`):

Product keyword, such as organic milk or coffee.

## `storeSlug` (type: `string`):

Public Instacart store slug, for example sprouts.

## `searchUrl` (type: `string`):

Optional official Instacart search URL override. When present, it takes precedence over query/storeSlug unless productUrls is supplied.

## `productUrls` (type: `array`):

Optional official HTTPS Instacart product detail URLs. When supplied, the Actor extracts each bounded store-specific page's public product, price, unit, availability, and retailer state; productUrls takes precedence over searchUrl.

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

Maximum normal product records emitted; diagnostics do not consume this limit.

## `timeoutMs` (type: `integer`):

Maximum time allowed for each public request.

## `maxBytes` (type: `integer`):

Maximum response size retained from the public page.

## `requestDelayMs` (type: `integer`):

Bounded respectful delay before a retry or redirect; the first request is immediate.

## `maxRequestRetries` (type: `integer`):

Retries timeouts, transport failures, and HTTP 5xx responses only; access blocks are not bypassed.

## `userAgent` (type: `string`):

Optional transparent user-agent string.

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

Optional Apify Proxy configuration. Direct access is the default; proxy use does not bypass access controls.

## Actor input object example

```json
{
  "query": "organic milk",
  "storeSlug": "sprouts",
  "searchUrl": "",
  "productUrls": [],
  "maxItems": 30,
  "timeoutMs": 30000,
  "maxBytes": 2000000,
  "requestDelayMs": 0,
  "maxRequestRetries": 1,
  "userAgent": "Mozilla/5.0 (compatible; ApifyActor/1.0; +https://apify.com/)",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `runSummary` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("w3crawler/instacart-product-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("w3crawler/instacart-product-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 w3crawler/instacart-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,w3crawler/instacart-product-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/sfQQhKETmNSmpCSb8/builds/5ww8eRe54cy9VSDxQ/openapi.json
