# Safeway & Albertsons Scraper: Club Prices & Coupons by ZIP (`vant47/safeway-albertsons-scraper`) Actor

Get Safeway, Albertsons, Vons, Jewel-Osco, ACME and Shaw's products with the price at your store: regular price, Club Price, digital coupons and deals, unit price, aisle, stock, UPC and size. Search, categories or product links by ZIP. About $0.004 per product. No login.

- **URL**: https://apify.com/vant47/safeway-albertsons-scraper.md
- **Developed by:** [fortbrand](https://apify.com/vant47) (community)
- **Categories:** E-commerce, Automation
- **Security:** Limited permissions
- **Stats:** 10 total users, 5 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

## Safeway & Albertsons Scraper: Club Prices & Coupons by ZIP

For retail price analysts, brands and comparison services monitoring the price a shopper sees at a particular store. Get regular prices, Club Prices, digital coupon conditions, unit prices, UPCs, aisles and availability. About **$0.004 per delivered product**, or **$0.08 for 20 products**, plus a minimum **$0.00005 Actor start charge**. No retailer login or retailer API key is required.

Choose Safeway, Albertsons, Vons, Jewel-Osco, ACME, Shaw's, Star Market, Tom Thumb, Randalls, Pavilions or Carrs. Each run uses one banner. Every product row identifies its banner and store, so separate runs fit the same comparison table.

### Understand the prices

`price` is the retailer's advertised current product price at `storeId`. A Club Card promotion can make that a membership price. Then `memberPrice` repeats the Club Price, `regularPrice` retains the source base price, and `priceRequiresMembership` is true. Preserve those distinctions when comparing baskets.

Digital coupons remain separate in `offers`. They can require clipping, a minimum quantity or a qualifying second product. Published text, validity dates and conditions are retained. Coupons are not subtracted from the product price, and no personalized checkout total is calculated. An offer without a numeric redemption price keeps a null price.

Prices exclude checkout taxes and service charges. Weighted products can have an estimated product price and a separate price per pound. Keep `sellByWeight`, `averageWeight`, `unitPrice` and `unitOfMeasure` together.

### What you get

The common retail fields appear first, after a readable verdict. Unknown values remain null.

| Field | Meaning |
| --- | --- |
| `verdict` | Readable product, price, membership, availability and store summary. |
| `retailer`, `country`, `currency` | Selected banner, US and USD. |
| `storeId`, `storeName`, `location` | Verified store, supplied name and requested ZIP. Location is null for exact/default stores. |
| `productId`, `sku`, `gtin` | Product identifiers and original UPC, preserving leading zeros. |
| `title`, `brand`, `size` | Supplied product title, explicit brand and package-size label. |
| `price`, `regularPrice`, `onSale` | Advertised price, source base price and sale flag. |
| `promoText`, `promoType` | Main price-promotion text and type. |
| `promoStart`, `promoEnd` | Main price-promotion dates when supplied. |
| `memberPrice`, `memberProgram` | Explicit Club Price and membership label. |
| `unitPrice`, `unitOfMeasure` | Source price per unit and its unit code, such as FL.OZ. |
| `inStock`, `stockLevel` | Online availability and supplied channel quantity. |
| `rating`, `reviewCount` | Supplied aggregate product review values. |
| `category`, `url`, `imageUrl` | Department, product page and product image. |
| `scrapedAt` | UTC observation timestamp. |

Retailer-specific fields add:

| Field | Meaning |
| --- | --- |
| `banner`, `bpn`, `upc` | Banner key, BPN number and original UPC. |
| `aisle`, `aisleId`, `shelf`, `departmentId` | Store aisle location and catalog taxonomy. |
| `sellByWeight`, `averageWeight`, `snapEligible` | Supplied weight-selling and SNAP information. |
| `digitalCouponAvailable`, `digitalCouponText` | Current UPC-linked clippable coupon flag and text. |
| `offers` | Offer IDs, text, dates, clipping requirement, quantities, channel and conditions. |
| `weeklyAd`, `isDeal`, `priceRequiresMembership` | Weekly-ad badge, combined deal flag and Club Price requirement. |
| `regularUnitPrice`, `promoTimezone`, `storeTimezone` | Base unit price and supplied store timezone. |
| `storeAddress`, `storeDistance`, `requestedLocations` | Public location evidence from store lookup. |
| `details`, `sourceUrl` | Optional product metadata and the public store-specific price request. |

The overview view puts title, price, regular price, promotion, member price, unit price, stock and store together. The deals view emphasizes promotions. The free `DEALS` JSON output contains only products with `isDeal: true`; large exports link to smaller JSON parts.

Every run saves `SUMMARY`: selected stores, delivered products, deals found, duplicates, source outcomes, free failures and spending-limit status. Free explanatory rows have `recordType: "NOTE"`; product rows have `recordType: "PRODUCT"`.

### Start in three steps

1. Select a banner and ZIP codes, or exact store IDs.
2. Enter search terms, category/product links or BPN numbers. Set your product limit.
3. Run, inspect the stores and coverage in SUMMARY, then export JSON, CSV or Excel.

The form prefill searches milk near ZIP 94611 with a 20-product cap. Its first private cloud test on 28 October 2026 delivered 20 unique products in 19.6 seconds. Another 20-product test finished in 23.3 seconds. Source retries, store count and optional details affect runtime.

### Inputs and examples

| Input | Example and behavior |
| --- | --- |
| `banner` | `safeway` by default; one supported banner per run. |
| `searchTerms` | `["milk", "coffee"]`, searched at each store. |
| `startUrls` | Plain URL strings for category, deals or product pages of the selected banner. |
| `productIds` | `["960111519"]`, retailer BPN numbers. Use searchTerms for barcode searches. |
| `locations` | `["94611", "20037"]`, nearest store of the banner per ZIP. ZIP+4 is accepted. |
| `storeIds` | `["3132", "923"]`, exact stores, taking precedence over ZIPs. |
| `maxItemsPerSearch` | New rows per source and store; default 20, maximum 1,000. |
| `maxItems` | Global product/store row cap; default 20, maximum 10,000. |
| `dealsOnly` | Keep sales, active UPC-linked offers and weekly-ad badges. |
| `includeDetails` | Slower optional metadata, with no extra product charge. |
| `proxyConfiguration` | Datacenter first, then US residential retries; custom settings are supported. |

Empty locations and storeIds use the website's default store. Explicit store IDs make monitoring repeatable. Store parameters in pasted URLs do not override the run's selection. Product links can open with the retailer website's currently selected store; check that selection when reviewing prices in a browser.

Two terms at two ZIPs can deliver up to 80 observations, about $0.32 at base pricing:

```json
{
  "banner": "safeway",
  "searchTerms": ["milk", "coffee"],
  "locations": ["94611", "20037"],
  "maxItemsPerSearch": 20,
  "maxItems": 80
}
```

A category example:

```json
{
  "startUrls": ["https://www.safeway.com/shop/aisles/dairy-eggs-cheese/milk-cream/milk.html"],
  "storeIds": ["3132"],
  "maxItems": 20
}
```

For exact-product monitoring, use `productIds: ["136010121", "960111519"]`, `storeIds: ["3132", "923"]` and `maxItems: 4`. Search/category pagination continues while the source supplies new products and your limits allow more, with a 50-page safety limit per source. A cap does not guarantee that a store carries that many matches. Deals-only filtering can scan more pages to find qualifying products.

### Real output example

Selected fields from the 28 October 2026 ZIP 94611 prefill:

```json
{
  "retailer": "Safeway",
  "storeId": "654",
  "location": "94611",
  "productId": "136010121",
  "gtin": "0002113007002",
  "title": "Lucerne Milk Whole 1 Gallon - 128 Fl. Oz.",
  "price": 6.49,
  "regularPrice": 6.49,
  "unitPrice": 0.05,
  "unitOfMeasure": "FL.OZ",
  "inStock": true
}
```

### Pricing and spending limits

One product means one distinct product at one store. A product at two stores is two price observations. Overlapping inputs at the same store are delivered and charged once within the run. Notes, summaries, failed requests and empty results have no product charge. There is no additional default dataset-row 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 |

Add the minimum $0.00005 start charge. Base price is $0.004 per product; Bronze is $0.0038, Silver $0.0036 and Gold $0.0032. Optional details have no extra event fee. Apify's maximum total charge controls larger jobs. The Actor checks capacity before requesting and saving more products, stops at the limit and records the decision in SUMMARY.

### Monitor prices every day

Save a task with stable store IDs and products or categories. In Apify Console, create a schedule, select the task, choose a daily time and timezone, then connect the completed-run webhook to your database or workflow.

Join snapshots using `banner + storeId + productId`, with `scrapedAt` as observation time. Keep regular prices, membership prices and coupon conditions in separate columns. Store UPCs as text in spreadsheets. Every scheduled run collects a fresh observation and charges for its delivered products again. Save snapshots in your database to build history; historical backfill is unavailable.

Make, Zapier, n8n and Sheets workflows can read the dataset and SUMMARY. Check freeFailures before accepting a snapshot as complete. Source outages should appear as gaps in your history, rather than substituted old prices.

### API and automation

Use your own Apify token and fetch the completed dataset and SUMMARY:

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

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("vant47/safeway-albertsons-scraper").call(
    run_input={"searchTerms": ["milk"], "storeIds": ["3132"], "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('vant47/safeway-albertsons-scraper').call({
  searchTerms: ['milk'], storeIds: ['3132'], maxItems: 20
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

### Use with AI agents (MCP)

Connect to `https://mcp.apify.com`. Ask for Safeway or Albertsons store prices, Club Prices, UPCs and coupon dates by ZIP. Supply the banner, ZIPs or store IDs, terms and product cap. Ask the agent to inspect SUMMARY, preserve nulls and retain membership and coupon conditions. Exact BPNs are useful for a repeatable monitored basket.

### Reliability and limits

Requests run sequentially, about two seconds apart, with fresh sessions on retry. US datacenter routing precedes US residential routing. The shared public company platform can serve a request through another official company host while its requested banner and store remain explicit. Product store IDs must match before delivery.

Prices, stock and ZIP selection are fetched live. Exact-store address metadata can be reused for seven days. `storeMetadataFromCache` and `storeMetadataObservedAt` identify that reuse. Cached address metadata never supplies prices or stock.

Saved page snapshots and the dataset ledger survive reboots. Delivery and charging are serial. Recovery checks saved rows, charge receipts and authoritative run counts; ambiguous billing evidence stops further charging. Source outages and refusals can still prevent complete output. SUMMARY makes those failures visible and uncharged.

Optional details add product-page requests. Those pages can use the website default store, so only product metadata is taken from them. Price and stock always come from the selected-store response. Details can remain null even when a verified store price is delivered.

Availability is an online signal; quantities are not audited physical shelf counts. Prices and stock can change after collection. Promotion timestamps without offsets retain their source local-time meaning, with a timezone supplied when available. Missing brands, start dates, ratings and quantities remain null.

Weekly-ad badges and UPC-linked offers cover returned products. Image-only flyer panels, personalized account offers, clipped-account state and checkout eligibility are outside coverage. The Actor does not sign in or solve CAPTCHAs.

### FAQ

**Can I choose an exact store?** Yes, use storeIds for stable monitoring or ZIPs for nearest-store selection.

**Do coupons lower price?** Their conditions stay in offers. Explicit Club Card promotions also populate memberPrice.

**Why are fields null?** The public response did not supply a verified value. Field availability varies by product.

**Does includeDetails cost extra?** No extra product fee; it adds slower metadata requests.

**What happens with bad input?** Parseable invalid selections produce a free note and summary. Apify can reject schema-invalid input before a run starts; neither path adds a product charge.

**Can I monitor every banner together?** Run each banner separately, then combine the common product/store fields.

# Actor input Schema

## `banner` (type: `string`):

Choose one banner. Product and store URLs must match this banner.

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

Find products such as milk, chicken or coffee. Each term is searched at every selected store. Leave empty when using only URLs or product IDs.

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

Optional links from the selected banner. Explicit ZIPs or store IDs control the store price; URL loc parameters do not override your selection.

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

Optional retailer BPN product numbers, such as 960111519. These are product numbers, not UPC barcodes.

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

Use US ZIP codes, such as 94611 or 20037. Chooses the nearest store of the selected banner. Empty means the website default store.

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

Optional exact numeric store IDs, such as 3132 or 923. These take precedence over ZIP codes. Each store is verified for the chosen banner.

## `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 products with a Club Price, other sale, active UPC-linked offer or weekly-ad badge. Coupon conditions remain separate from the advertised product 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`):

Default: datacenter first, with US residential only after refused datacenter attempts. You may supply your own proxy configuration.

## Actor input object example

```json
{
  "banner": "safeway",
  "searchTerms": [
    "milk"
  ],
  "locations": [
    "94611"
  ],
  "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 = {
    "banner": "safeway",
    "searchTerms": [
        "milk"
    ],
    "locations": [
        "94611"
    ],
    "maxItemsPerSearch": 20,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("vant47/safeway-albertsons-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 = {
    "banner": "safeway",
    "searchTerms": ["milk"],
    "locations": ["94611"],
    "maxItemsPerSearch": 20,
    "maxItems": 20,
}

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

```

## MCP server setup

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