# Meijer Scraper: Store Prices, mPerks Coupons & Weekly Deals (`vant47/meijer-scraper`) Actor

Get Meijer products with the price at your store: sale price, mPerks digital coupons, weekly ad deals with dates, BOGO, unit price, aisle, stock, UPC and size. Search, categories or product links by ZIP or store. Groceries, household and general merchandise. About $0.004 per product. No login.

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

## Pricing

from $3.20 / 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

## Meijer Scraper: Store Prices, mPerks Coupons & Weekly Deals

For US grocery price analysts, brands and comparison services monitoring Meijer products at a particular store. Get current and regular prices, mPerks coupon conditions and dates, promotions, unit prices, barcodes, aisles and stock. About **$0.004 per delivered product**, or **$0.08 for 20 products**, plus a **$0.00005 start charge per GB**, minimum one. No retailer login or retailer API key is required.

### Understand the prices

`price` is the current public price per sold unit at `storeId`. `regularPrice` is the same store's base price. mPerks coupons stay separate in `offers`; their discounts are never silently subtracted from the shelf price. Preserve clipping requirements, quantities, redemption dates and terms when comparing baskets.

Keep item price and unit price separate. A real 3 November 2026 Alpine observation returned bananas at **$0.28 per item** and **$0.55 per LB**, with a source average of **0.5 pricing units per sold item**. The Actor does not invent a price per fluid ounce when the site supplies only an EA price.

A dollar-off coupon is not a verified numeric member checkout price. `memberPrice` remains null when that price is unavailable. `memberProgram` identifies mPerks where the product has an associated flag or offer. Prices exclude checkout taxes and service fees; supplied deposits remain separate.

### What you get

One row represents one product at one store. Common retail fields follow the readable verdict, matching the Safeway and Albertsons family schema. Unknown values remain null.

| Fields | Meaning |
| --- | --- |
| `verdict` | Product, price, sale/coupon signal, stock and store summary. |
| `retailer`, `country`, `currency` | Meijer, US and USD. |
| `storeId`, `storeName`, `location` | Verified store and requested ZIP; ZIP is null for exact/default stores. |
| `productId`, `sku` | Public URL product number and separate internal product ID. |
| `gtin` | Checksum-valid barcode in the source image filename, when available. Short produce PLUs keep gtin null. |
| `title`, `brand`, `size` | Supplied product name, brand and package size, retaining source unit codes. |
| `price`, `regularPrice`, `onSale` | Current/base prices per sold unit and source sale flag. |
| `promoText`, `promoType` | Savings/promotion text and readable classification. |
| `promoStart`, `promoEnd` | Supplied promotion dates; unknown start dates remain null. |
| `memberPrice`, `memberProgram` | Numeric member price if supported, and membership label. |
| `unitPrice`, `unitOfMeasure` | Source price per pricing unit, such as EA or LB. |
| `inStock`, `stockLevel` | Known availability and quantity if supplied; shelf counts are never inferred. |
| `rating`, `reviewCount` | Aggregate review values if supported; currently null. |
| `category`, `url`, `imageUrl` | Catalog taxonomy, product page and image. |
| `scrapedAt` | UTC observation timestamp. |

| Additional fields | Meaning |
| --- | --- |
| `aisle`, `upc`, `department`, `sellByWeight` | Store item-location code, original identifier, top department and source weight-selling flag. |
| `mPerksOffer`, `digitalCouponText` | Matching coupon titles and descriptions. |
| `digitalCouponAvailable`, `mPerksOfferIds` | Source coupon flag and explicitly linked identifiers. |
| `offers` | Offer IDs, text, dates, terms, clipping requirement and supplied discount conditions. |
| `promotions`, `weeklyAd`, `isDeal` | Store promotions, weekly-ad collection membership and combined current-deal flag. |
| `soldByUnit`, `averageWeight`, `regularUnitPrice` | Sold unit, average pricing units per item and base unit price. |
| `depositValue`, `clearancePrice`, `buyQuantity`, `priceText` | Supplied deposit, clearance price, quantity and display text. |
| `storeAddress`, `storeTimezone`, `requestedLocations` | Public store metadata and ZIP selections resolving to that store. |
| `promoTimezone`, `details` | Timezone for local source dates and optional ingredients/description/nutrition. |
| `sourceUrl`, `discoveryUrl` | Public price-service and store-filtered catalog requests. |

The **overview** view puts title, price, regular price, promotion, member price, unit price, stock and store together. The **deals** view emphasizes promotions; **details** exposes the full fields. The free `DEALS` JSON output contains only `isDeal: true` rows, splitting very large exports into linked parts.

Every run saves a `SUMMARY` key-value record: products, stores, deals, source outcomes, free failures, unavailable products, duplicates, charged products and spending-limit status. Explanatory dataset rows use `recordType: "NOTE"`; products use `recordType: "PRODUCT"`. Notes and summaries have no Product charge.

### Start in three steps

1. Enter ZIP codes or exact store IDs.
2. Enter searches, category/deals links or known public product numbers.
3. Set the cap, run, inspect SUMMARY and export JSON, CSV or Excel.

The form prefill searches milk near 49512 and requests 20 products. Its final private test on 3 November 2026 returned **20 unique products in 15.5 seconds**, with **20 matching charges and zero free failures**. Source response times and retries vary.

### Inputs

| Input | Example and behavior |
| --- | --- |
| `searchTerms` | `["milk", "coffee"]`, searched at every selected store. |
| `startUrls` | Meijer category, collection, weekly-ad, search or product links. |
| `productIds` | `["4125010200", "81326702000"]`, public numbers from URL endings. |
| `locations` | `["49512", "48104"]`, nearest supercenter per ZIP; ZIP+4 accepted. |
| `storeIds` | `["20", "50"]`, exact stores taking precedence over ZIPs. |
| `maxItemsPerSearch` | New products per source/store; default 20, maximum 1,000. |
| `maxItems` | Global product/store cap; default 20, maximum 10,000. |
| `dealsOnly` | Keep sales, published promotions, active matching coupons and weekly-ad selections. |
| `includeDetails` | Add supplied ingredients, description and nutrition without another event fee. |
| `proxyConfiguration` | Automatic datacenter discovery/coupon calls and US residential browser prices; custom proxies supported. |

Empty storeIds and locations use the site's observed default, Alpine store 20, which is verified before reading prices. Exact IDs make monitoring repeatable. ZIPs resolving to one store are deduplicated. URL store parameters do not override your selection. Full printed barcodes are not always the same format as Meijer's public product numbers.

Two terms at two ZIPs, capped at 80 observations, cost about $0.32 at base pricing:

```json
{
  "searchTerms": ["milk", "coffee"],
  "locations": ["49512", "48104"],
  "maxItemsPerSearch": 20,
  "maxItems": 80
}
```

Category monitoring:

```json
{
  "startUrls": ["https://www.meijer.com/shopping/departments/grocery/snacks"],
  "storeIds": ["20"],
  "maxItemsPerSearch": 100,
  "maxItems": 100
}
```

A known basket at two stores:

```json
{
  "productIds": ["4125010200", "81326702000", "4011"],
  "storeIds": ["20", "50"],
  "maxItems": 6,
  "includeDetails": true
}
```

Use `https://www.meijer.com/shopping/weekly-ad` for the weekly-ad collection. Supported older `.html` links are normalized. Categories must map unambiguously to the current hierarchy; unsupported selections produce free notes. Pagination uses a stable page size while new matches remain. Search products require a source token match; semantic-only recommendations for unmatched terms are excluded without a Product charge. A cap does not guarantee that a narrow query carries that many products.

### Real output example

Selected fields from a 3 November 2026 ZIP 49512 observation:

```json
{
  "retailer": "Meijer",
  "storeId": "50",
  "storeName": "Cascade",
  "location": "49512",
  "productId": "4125010200",
  "sku": "504293",
  "gtin": "0041250102007",
  "title": "Meijer Whole Milk, Gallon",
  "price": 3.28,
  "regularPrice": 3.28,
  "unitPrice": 3.28,
  "unitOfMeasure": "EA",
  "inStock": true,
  "aisle": "C-1-27-3"
}
```

The same product at Alpine store 20 was $3.34, aisle B-19-7-4. Select the same store on the retailer site before comparing a page with an exported row.

### Pricing and spending limits

One Product charge covers one distinct product at one store per run. A product at two stores is two observations. Overlapping inputs at the same store are delivered and charged once. Optional details have no additional Product fee.

| Products | Base | Bronze | Silver | Gold |
| --- | --- | --- | --- | --- |
| 20 | $0.08 | $0.076 | $0.072 | $0.064 |
| 100 | $0.40 | $0.38 | $0.36 | $0.32 |
| 1,000 | $4.00 | $3.80 | $3.60 | $3.20 |

Base price is $0.004 per product; Bronze $0.0038, Silver $0.0036 and Gold $0.0032. Add $0.00005 per GB at startup, minimum one charge. Default runs use 1 GB. There is no default dataset-item fee. Failed requests, empty results, duplicates, notes and summaries have no Product charge.

Apify's maximum total charge controls larger runs. The Actor checks capacity before further work and delivery, stops cleanly and records spendingLimitReached. Set both row and money caps for schedules; the money cap includes startup.

### Monitor prices every day

Save a task with stable store IDs and a basket or categories. In Apify Console, create a schedule, select the task and timezone, then send completed datasets to your database through a webhook or integration.

Join snapshots using `retailer + storeId + productId` and scrapedAt. Keep barcodes as text, and shelf prices, unit prices and coupon conditions in separate columns. Each scheduled run collects fresh observations and charges for delivered products again. Save those snapshots to build history; historical backfill is unavailable.

Check SUMMARY before accepting a snapshot as complete. Keep freeFailures visible as coverage gaps. Make, Zapier, n8n, Sheets and BI tools can consume the dataset and summary. Combine common fields with sibling US grocery Actors, retaining retailer-specific conditions.

### API and automation

Use your own Apify token:

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

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("vant47/meijer-scraper").call(
    run_input={"searchTerms": ["milk"], "storeIds": ["20"], "maxItems": 20}
)
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
summary = client.key_value_store(run["defaultKeyValueStoreId"]).get_record("SUMMARY")
```

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

### Use with AI agents (MCP)

Connect to `https://mcp.apify.com`. Ask for Meijer prices, mPerks coupons, weekly deals, UPCs and stock by ZIP or exact store. Supply searchTerms or productIds and a cap. Ask the agent to inspect SUMMARY, preserve nulls and retain coupon conditions.

### Reliability and limits

Two private cloud runs each delivered 1,100 unique observations across three stores, with exactly 1,100 Product charges and zero failed sources. They covered milk/coffee/bread and cereal/snacks/juice at Alpine 20, Cascade 50 and Petoskey 257. Separate 1,200-product runs also passed.

A real reboot after the second product save, before its charge, recovered to 10 unique products and exactly 10 charges. Saved pages, the dataset ledger and acknowledged charge receipts survive restarts. Delivery and charging are serial; recovery checks authoritative counts and stops rather than guessing when billing evidence is ambiguous.

Prices and stock must match the requested store and product. Refusal pages, including HTTP 200 HTML errors, are rejected. Requests are paced and retries use fresh anonymous sessions. Public browser data calls use a small origin page, with fuller home-page warming on retry. No retailer accounts, account cookies, CAPTCHA solving or paid unblockers are used.

The public catalog can briefly lag changes; every delivered price is checked against the store product response. Missing dates, ratings and quantities remain null. Sentinel non-promotion dates are omitted. Storefront navigation or source outages can still prevent complete coverage; free notes expose failures.

Public coupons can be available for advance clipping. Future coupon dates remain in offers, but a future coupon alone does not qualify as a current deal. Personalized offers, account clipping state, reward balances, image-only flyer panels and checkout eligibility are outside coverage. Marketplace shipping offers are excluded from store-price output.

### FAQ

**Can I choose exact stores?** Yes. Use storeIds, or ZIPs for nearest-supercenter selection.

**Do coupons lower price automatically?** No. Their conditions remain separate; a coupon amount is not a numeric member price.

**What does unitPrice mean?** The supplied price for unitOfMeasure, such as EA or LB, without invented package normalization.

**Does includeDetails cost extra?** No additional Product fee; unavailable details remain null.

**What happens with bad input?** Parseable invalid selections produce free notes and SUMMARY. Schema-invalid input can be rejected before startup, without a Product charge.

**Can interrupted runs resume?** Yes. Saved observations prevent completed product/store rows and charges from repeating.

# Actor input Schema

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

Find products such as milk, chicken or coffee at each selected Meijer store. Leave empty for URL or product-ID monitoring.

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

Meijer category, collection, weekly-ad, search or product links. Both current and older .html links are accepted. Your store selection controls prices.

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

Meijer public product numbers from product URL endings, for example 4125010200. These are the site UPC identifiers, which may omit barcode zeros or the check digit.

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

US ZIP codes, such as 49512, 48104 or 60614. Selects the nearest Meijer supercenter in the retailer lookup. Empty uses the website default store.

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

Exact Meijer store numbers such as 20, 50 or 257. These take precedence over ZIPs. Each store is verified before prices are read.

## `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.004 per product: 20 products cost about $0.08 plus the small start charge.

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

Keep sales, published product promotions, active mPerks offers or weekly-ad selections. Coupon discounts remain separate from the current price.

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

Slower optional product metadata such as ingredients and nutrition. No extra product fee. Missing details remain null; store prices are always verified independently.

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

Automatic routing: default datacenter HTTP discovery and coupon calls, with US residential browser transport for verified prices. Custom proxy settings are supported.

## Actor input object example

```json
{
  "searchTerms": [
    "milk"
  ],
  "locations": [
    "49512"
  ],
  "maxItemsPerSearch": 20,
  "maxItems": 20,
  "dealsOnly": false,
  "includeDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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": [
        "49512"
    ],
    "maxItemsPerSearch": 20,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("vant47/meijer-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": ["49512"],
    "maxItemsPerSearch": 20,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("vant47/meijer-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": [
    "49512"
  ],
  "maxItemsPerSearch": 20,
  "maxItems": 20
}' |
apify call vant47/meijer-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vant47/meijer-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/ZaZOsaelM28FTdzAO/builds/e4ZhnaW4dxq2sacu8/openapi.json
