# Menards Scraper: Store Prices, Rebates & Pickup Stock (`vant47/menards-scraper`) Actor

Get Menards product prices by selected store: current and regular price, public mail-in rebate amount and conditions, SKU, unit price and pickup stock where shown. Search, categories or product links. About $0.004 per product: 1,000 products cost $4. No login.

- **URL**: https://apify.com/vant47/menards-scraper.md
- **Developed by:** [fortbrand](https://apify.com/vant47) (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 $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

## Menards Scraper: Store Prices, Rebates & Pickup Stock

For retail price analysts, brands, procurement teams and comparison services monitoring what Menards advertises at a selected store. Collect the amount paid now, regular price, sale price, public mail-in rebate amount, future after-rebate value, SKU and pickup quantities where Menards displays them. About **$0.004 per delivered product**: **20 products cost $0.08**, plus a minimum **$0.00005 Actor start charge**. No Menards login or retailer API key is needed.

Search product terms, browse categories or monitor exact item IDs and product links. Select US ZIP codes or exact store IDs.

### Read the price correctly

Menards' mail-in rebate is future in-store merchandise credit. It is not an instant checkout discount. `price` is the advertised amount paid now, before tax and delivery charges. `rebateAmount` is the separately advertised future credit. `priceAfterRebate` is Menards' displayed value after that credit, when supplied.

For example, a first-party observation on 5 November 2026 returned SKU `2303502` with a current and regular price of **$29.97**, an **11% rebate of $3.30**, and a displayed after-rebate value of **$26.67**. A buyer still pays $29.97 at the original purchase. The credit requires the retailer's rebate submission process and is for future eligible in-store purchases.

`onSale` compares current and regular price; a rebate alone does not make it true. `isDeal` includes either a sale or rebate.

### What you get

One row represents one product in one store context. Shared retail field names support comparison with sibling retail Actors; unknown values stay null.

| Field | Meaning |
| --- | --- |
| `verdict` | Readable product, amount paid now, future rebate credit and selected store summary. |
| `retailer`, `country`, `currency` | Menards, US and USD. |
| `storeId`, `storeName`, `location` | Verified store number, name and the ZIP requested. Location is null for exact-store selection. |
| `productId`, `sku`, `gtin` | Menards item ID, source SKU and barcode field. Identifiers are text. |
| `title`, `brand`, `size` | Catalog title and separate brand or package-size fields when the source supplies them. |
| `price`, `regularPrice`, `onSale` | Advertised current price paid now, regular price and sale flag. |
| `promoText`, `promoType` | Displayed price steps and promotion type. |
| `promoStart`, `promoEnd` | Main promotion dates where available through optional rebate detail. |
| `memberPrice`, `memberProgram` | Common family fields; no membership price is inferred from a rebate. |
| `unitPrice`, `unitOfMeasure` | Current price per each when the source uses each; other per-unit values remain null when not supplied. |
| `inStock`, `stockLevel` | Selected-store quantity only when Menards displays it with a stock message. |
| `rating`, `reviewCount` | Common family fields retained as null when absent. |
| `category`, `url`, `imageUrl` | Returned category, canonical product link and supplied product image. |
| `scrapedAt` | UTC observation time. |

Menards fields:

| Field | Meaning |
| --- | --- |
| `rebateAmount`, `rebatePercent` | Explicit advertised rebate amount and percentage label. |
| `rebateValidFrom`, `rebateValidTo` | Available rebate dates; missing start dates remain null. |
| `priceAfterRebate`, `rebateTerms` | Source after-rebate value and an explanation of future in-store credit. |
| `rebateValidToText`, `rebateLimit` | Original end-date wording and quantity limit when returned by optional detail. |
| `modelNumber` | Separate model-number field, null when absent from the catalog route. |
| `priceScope`, `stockScope` | Selected-store online or default online price scope, plus pickup stock scope. |
| `pickupEligible`, `deliveryEligible` | Source fulfillment eligibility, separate from physical quantity. |
| `deliveryMessage`, `stockMessage` | Published availability wording. |
| `priceInCheckout`, `minimumAdvertisedPrice` | Source price-withholding information where supplied. |
| `isDeal`, `categoryId`, `variationCount` | Combined deal flag, source category and variation count. |
| `storeAddress`, `storeDistance` | Public store-resolution evidence and the retailer's ZIP distance. |
| `storeMetadataObservedAt` | Time the store metadata was read. |
| `details`, `sourceUrl` | Optional rebate detail and the first-party request used for the observation. |

The overview view groups prices, promotions, stock and stores. The deals view emphasizes future rebate credit. `DEALS` contains only delivered products with `isDeal: true`; large exports link to smaller parts.

Each run also saves `SUMMARY`: product count, resolved stores, deals found, source outcomes, duplicate exclusions, free failures, charged products and spending-limit status. Explanatory rows have `recordType: "NOTE"` and no product charge. Product rows have `recordType: "PRODUCT"`.

### Start in three steps

1. Enter search terms, category links or full product links.
2. Select ZIP codes or exact store IDs, then set your product limits.
3. Run, review the resolved stores in SUMMARY and export JSON, CSV or Excel.

The form searches deck screws near ZIP `53703` with a 20-product cap. On 5 November 2026, all 33 current inputs passed across five ZIPs. The prefill delivered 20 unique products in 36.1 seconds; two volume runs each delivered 1,100 unique observations with no source failures. Product charges matched delivered rows. Source refusals are retried through fresh anonymous visitor sessions. Check SUMMARY before treating a snapshot as complete.

### Inputs

| Input | Example and behavior |
| --- | --- |
| `searchTerms` | `["deck screws", "drill"]`; each term runs at each selected store. |
| `startUrls` | Public Menards category links or full category-bearing product URLs. |
| `productIds` | `["1444450183111"]`; Menards item IDs from the number after `p-`, rather than SKUs. |
| `locations` | `["53703", "60601"]`; resolve the nearest open Menards store for each ZIP. |
| `storeIds` | `["3034"]`; exact stores, taking precedence over ZIPs. |
| `maxItemsPerSearch` | New product rows per source and store, default 20, maximum 2,000. |
| `maxItems` | Global product/store cap, default 20, maximum 10,000. |
| `dealsOnly` | Keep sale products or products with public mail-in rebate credit. |
| `includeDetails` | Add full titles, explicit selected-store stock messages and public rebate detail, including end-date wording. No extra product fee. |
| `proxyConfiguration` | Automatic default datacenter selection first, then US residential after refusal. Custom proxy settings are optional. |

Empty store selections use the default online context, with `storeId` null. ZIP selection can choose a store outside the requested ZIP; inspect its reported address and distance. Exact store IDs make monitoring repeatable.

Two terms at two locations: up to 80 observations, $0.32 at base pricing:

```json
{
  "searchTerms": ["deck screws", "drill"],
  "locations": ["53703", "60601"],
  "maxItemsPerSearch": 20,
  "maxItems": 80
}
```

A category with rebate detail:

```json
{
  "startUrls": ["https://www.menards.com/main/hardware/fasteners-connectors/screws/deck-screws/c-8929.htm"],
  "storeIds": ["3034"],
  "includeDetails": true,
  "dealsOnly": true,
  "maxItems": 20
}
```

For an exact product, paste its Menards product link or put its numeric item ID in `productIds`. The item ID is the number after `p-` in the link. Exact-product observations combine the public item availability and price-detail calls, including the requested store's explicit stock message when supplied. Overlapping searches and links at the same store are delivered and charged once within a run.

### Price and spending limits

Base price is **$0.004 per Product**. Bronze receives 5% off, Silver 10% off and Gold 20% off. Optional rebate details do not add a second event. Notes, summaries, failed requests, empty results, duplicates and retries have no Product charge. The minimum platform start charge remains separate.

| Delivered 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 |

A product at two stores is two observations. Each scheduled run charges for its fresh observations. Apify's maximum total charge controls the run: the Actor checks capacity before delivering more products and stops cleanly when the next Product would exceed the limit.

### Monitor prices every day

Save a task with stable store IDs and a consistent product basket or category list. In Apify Console, create a schedule, select that task, choose a daily time and timezone, and connect a completed-run webhook to your database or workflow.

Join snapshots by `retailer + storeId + productId`, with `scrapedAt` as the observation time. Retain `price`, `regularPrice`, `rebateAmount` and `priceAfterRebate` as separate columns. Store identifiers as text so spreadsheet software does not convert them to scientific notation or remove leading zeros.

Inspect SUMMARY's source outcomes and freeFailures before accepting an entire snapshot. An unavailable source should appear as a gap in the history; an older price is not substituted. Store the finished datasets in your own warehouse to build price history. This Actor collects current observations rather than historical backfills.

Make, Zapier, n8n and spreadsheet workflows can read the dataset and SUMMARY. Filter with `recordType` and `isDeal`, preserving unknown quantities as null.

### API and automation

Start a run with your Apify token, then read the dataset and SUMMARY:

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

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("vant47/menards-scraper").call(
    run_input={"searchTerms": ["drill"], "locations": ["60601"], "maxItems": 20}
)
products = 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('vant47/menards-scraper').call({
  searchTerms: ['deck screws'], storeIds: ['3034'], maxItems: 20
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

### Use with AI agents (MCP)

Connect to `https://mcp.apify.com`. Request Menards prices, regular prices, rebate credit and displayed pickup stock. Supply ZIPs or stores, terms and a product cap. Ask the agent to inspect SUMMARY, preserve nulls and separate current cash price from future credit.

### Limits

Prices are selected-store online advertisements or the explicitly labeled default online context. They are not an audit of physical shelf labels or a personalized checkout total. Taxes, delivery charges, account-specific offers and eligibility decisions are outside the observation.

Pickup eligibility does not prove a product is on the shelf. Menards can offer pickup for an item without displaying a local quantity. A zero quantity without a displayed stock message is treated as a placeholder and stays null. Source inventory can change after observation and can include display units.

Catalog titles can be abbreviated. The current catalog route does not supply separate GTINs, model numbers, ratings, full specifications or consistently separate brand and size fields, so absent values remain null. `includeDetails` adds full titles, explicit store stock messages and public rebate details rather than a complete specification export. Rebate start dates and some end dates may also be absent.

Broad department pages can contain navigation rather than purchasable listings. The Actor follows their public linked categories until it reaches products and your limit. A source with no usable product listing produces a free source outcome. Product variations are counted as returned catalog entries, not expanded into every possible configuration.

Image-only sale flyer panels are outside this export; deal rows come from live product listings.

Only public signed-out data is read. No account cookies, login, CAPTCHA solving or outside unblocking service is used. Site changes, refusals or outages can leave a source incomplete; those failures are visible in SUMMARY and have no Product charge. Saved page snapshots and a serial dataset/charge ledger support restart recovery.

### FAQ

**Does price include the 11% rebate?** No. Price is paid now. The rebate and the source after-rebate value have their own columns.

**Does includeDetails cost extra?** No extra Product event. It requests full titles, public stock messages and rebate detail, and adds source work.

**Why is stock null when pickup is available?** Pickup eligibility and a displayed local quantity are different source signals. The Actor preserves both.

**Why is a model number or barcode null?** The catalog route did not provide it. A SKU, title fragment or model-family identifier is not substituted for a verified model or barcode.

**What happens with bad input?** Parseable invalid selections become free note rows and SUMMARY information. Apify can reject schema-invalid input before a run starts; no Product charge is added for that rejection.

**Is this affiliated with Menards?** No. It is an independent tool for reading public retail price observations.

# Actor input Schema

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

Products such as deck screws, drill or insulation. Each term runs at every selected store.

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

Optional public Menards category or full product URLs. Run store selections take precedence over URL tracking parameters.

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

Optional numeric item IDs from the p- part of Menards product URLs. Full product links provide category context.

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

Resolve the nearest Menards store for each ZIP and report its address and distance. Empty means the online default context.

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

Exact Menards store numbers, such as 3034. Verified before prices are delivered. Overrides ZIP selection.

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

New unique product rows per search, category or store. Overlap is delivered and charged once.

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

Global product/store observation cap. At base pricing 20 products cost $0.08 plus the small start charge.

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

Keep sale-priced products or products with public mail-in rebates. Rebates do not reduce price paid now.

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

Add full product titles, explicit selected-store stock messages, rebate end-date wording and quantity limits where supplied. No extra Product fee.

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

Account default datacenter proxy first, US residential after refusal. Custom proxy configuration is optional.

## Actor input object example

```json
{
  "searchTerms": [
    "deck screws"
  ],
  "locations": [
    "53703"
  ],
  "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": [
        "deck screws"
    ],
    "locations": [
        "53703"
    ],
    "maxItemsPerSearch": 20,
    "maxItems": 20
};

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

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

```

## MCP server setup

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