# Walgreens Scraper (`crawlerbros/walgreens-scraper`) Actor

Scrape Walgreens.com's product catalog. Search by keyword, browse any category/department page, or fetch specific products by product ID/URL. Get price, member price, brand, UPC/GTIN, stock & shipping status, images, description and category breadcrumb.

- **URL**: https://apify.com/crawlerbros/walgreens-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, E-commerce, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Walgreens Scraper

Scrape [Walgreens.com](https://www.walgreens.com)'s product catalog — pharmacy, health, beauty, grocery, and household items. Search by keyword, browse any category/department page, or fetch specific products by ID or URL. Get price, member (myWalgreens) price, brand, UPC/GTIN, stock & shipping status, images, description, and category breadcrumb. No login, no cookies required.

### What this actor does

- **Three modes:** `search` (keyword), `byCategoryUrl` (browse any department/category page), `byProductIds` (exact lookup)
- **Rich product data:** price, member price, unit price, UPC, GTIN, brand, images, description, category breadcrumb, FSA/EBT eligibility, stock & shipping availability
- **Filters:** price range, in-stock only, exact brand, minimum customer rating, on-sale/clearance only
- **Store-aware:** pass a `storeId` to get that store's local pricing/availability (defaults to a representative US store)
- **Empty fields are omitted** — no null/placeholder values in the output

### Output per product

- `productId`, `title`, `brand`, `url` — canonical Walgreens product page
- `imageUrl`, `imageUrls` — full photo gallery
- `regularPrice`, `memberPrice` (myWalgreens member price, when it differs from regular), `unitPrice`, `unitPriceSize`
- `rebateText` — sitewide promo/rebate banner copy
- `promotions` — BOGO / mix-and-match style offers, e.g. "Buy 1, Get 1 FREE"
- `rating` (0-5, Bazaarvoice-sourced), `reviewCount`
- `sizeCount`, `availableOptions` — other sizes/variants of this product
- `upc`, `gtin` — barcode identifiers
- `inStock`, `shipAvailable`, `pickupAvailable` — authoritative availability flags
- `shipAvailableMessage` — a Walgreens API status label; note it is frequently `"Out of stock online"` even when `shipAvailable`/`addToCartEnable` are `true` — treat `inStock`/`shipAvailable` as authoritative, not this message string
- `ageRestricted`, `isAlcohol`, `isGiftCard` — purchase-restriction flags
- `tier1Category`, `tier2Category`, `tier3Category`, `brandUrl`
- `isFsaEligible`, `isEbtEligible` — payment-eligibility flags
- `webExclusive`, `isWalgreensBrand`
- `onClearance`, `isNewLowerPrice`, `isNewItem` — merchandising badges
- `retailUnitQty`, `couponAvailable`
- `productAttributes` — certifications/features like "Gluten Free", "Vegan"
- `productType` — fine-grained product type, more granular than `tier3Category`
- `hasIngredients`, `ingredients` — flat list of ingredient names (supplement/OTC-drug products that publish an ingredients panel)
- `nutritionFacts` — list of `{name, amountPerServing}` from the Supplement/Nutrition Facts panel (e.g. Calories, Vitamin C, Sodium), on the same products that publish `ingredients`
- `servingSize`, `servingsPerContainer`
- `warningText` — product warning/caution copy
- `shippingWeightLbs`, `shippingRestrictedStates` — US state codes this item cannot ship to
- `description`
- `recordType`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byCategoryUrl` / `byProductIds` |
| `searchQuery` | string | `vitamin c` | Keyword search (mode=search) |
| `categoryUrl` | string | – | Category/department page URL (mode=byCategoryUrl) |
| `productIds` | array | – | Product IDs or product page URLs (mode=byProductIds) |
| `storeId` | integer | `15196` | Walgreens store ID for local pricing (default: a representative US store) |
| `minPrice` / `maxPrice` | integer | – | Regular-price bounds in USD |
| `inStockOnly` | boolean | `false` | Only in-stock (online) products |
| `brand` | string | – | Exact brand match, case-insensitive |
| `minRating` | number | – | Only products with an average customer rating at or above this (0-5); unreviewed products are kept |
| `onSaleOnly` | boolean | `false` | Only products currently on clearance or at a new lower price |
| `maxItems` | integer | `30` | Cap on emitted records (1-200) |

#### Example: keyword search at a specific store

```json
{
  "mode": "search",
  "searchQuery": "vitamin c",
  "storeId": 15196,
  "maxItems": 30
}
```

#### Example: browse a category page

```json
{
  "mode": "byCategoryUrl",
  "categoryUrl": "https://www.walgreens.com/store/c/vitamin-c/ID=361635-tier3",
  "maxItems": 50
}
```

Use a leaf category page (one that lists individual products, e.g. `.../ID=xxxxx-tier3`) rather than a top-level department landing page (`.../ID=xxxxx-tier1`), which lists subcategories instead of products — click through to the specific product-listing page on walgreens.com and copy that URL.

#### Example: exact product lookup by ID/URL

```json
{
  "mode": "byProductIds",
  "productIds": ["300405068", "prod3511"]
}
```

#### Example: on-sale, highly-rated products in a price range

```json
{
  "mode": "search",
  "searchQuery": "sunscreen",
  "minPrice": 5,
  "maxPrice": 25,
  "minRating": 4,
  "onSaleOnly": true,
  "maxItems": 40
}
```

### Use cases

- **Price monitoring** — track regular price, member price, and clearance status for pharmacy/health/beauty SKUs over time
- **Assortment & catalog research** — browse category pages to see everything Walgreens stocks in a department
- **Competitive retail analysis** — compare pricing and promotions against other drugstore/grocery chains
- **Ingredient & nutrition auditing** — pull `ingredients`/`nutritionFacts` for supplement and OTC products
- **Local availability checks** — pass `storeId` to check in-stock/pickup status for a specific store
- **Deal & coupon feeds** — filter `onSaleOnly` to build a live clearance/markdown feed

### FAQ

**Do I need a Walgreens account or cookies?**
No. Prices and product data are read from Walgreens' own public product API anonymously, exactly like a signed-out visitor's browser does.

**Why does `search` sometimes take longer than the other modes?**
Walgreens gates its keyword search-results and category-listing pages behind a short client-side verification step. This actor tries a plain HTTP fetch first for `search` and `byCategoryUrl`; if that's blocked, it falls back to loading the page in a real headless browser once (a few seconds) to clear the challenge, then reads product data from the same fast JSON API all three modes use. `byProductIds` never needs the browser step and is fastest.

**What's `memberPrice`?**
Walgreens shows a lower "myWalgreens member" price alongside the regular price on many products; it's included when it differs from `regularPrice`.

**Does the output include ratings/reviews?**
Yes — `rating` (0-5) and `reviewCount` come straight from Walgreens' own product-page review widget when the product has published reviews; new/low-traffic products without reviews simply omit both fields rather than showing `0`.

**What's the difference between `rebateText` and `promotions`?**
`rebateText` is Walgreens' sitewide promo banner (e.g. a percent-off promo code). `promotions` lists product-specific mix-and-match/BOGO offers (e.g. "Buy 1, Get 1 FREE") that apply to that item specifically.

**Can I get products from a specific store's inventory?**
Yes — set `storeId` to your target Walgreens store's numeric ID. Pricing and stock messages reflect that store; the default value is a representative store used when you don't need store-specific data.

**What happens if my `searchQuery` doesn't match any product?**
For most unmatched keywords, Walgreens' search returns zero products and the actor reports 0 records with a clear status message. For some nonsense or partial-word keywords, Walgreens' own search engine does fuzzy/substring matching and can surface loosely related products (e.g. a query containing "zzz" matching a brand named "Always ZZZ") instead of returning zero results — this is upstream search behavior, not something the actor filters or fabricates; every record returned is a real, live Walgreens product.

### Limitations

- `search` clicks through Walgreens' own results pagination (beyond the first page) to gather more product IDs when `maxItems` calls for it, but for broad/popular keywords the site's own deeper result pages increasingly re-surface products already seen on earlier pages — so the actor may return fewer unique records than `maxItems` once it has exhausted what Walgreens' search UI actually offers as distinct results, rather than an error. Use a narrower `searchQuery` (or `brand`/`minPrice`/`maxPrice`) to reach a larger unique count.
- For very broad single-word keywords with `maxItems` set near the 200 maximum, Walgreens' own ad/lazy-image-heavy results grid can also hit a headless-browser rendering limit a few pages in (typically after 80-90 unique products); the actor detects this cleanly and returns the records already gathered rather than erroring, timing out, or fabricating filler — re-run with a narrower `searchQuery` if you need the full requested count.
- `byCategoryUrl` reads whatever product tiles Walgreens renders on the category page (including recommendation carousels); very large categories may not be fully covered in a single run — use a narrower subcategory URL, or `byProductIds` for exact coverage of a known product list.
- Coupon *content* (the `couponsearch` endpoint with actual coupon codes/terms) requires a signed-in session and is out of scope; `couponAvailable` (whether a coupon exists at all) and `rebateText` reflect publicly shown savings signals only.
- Per-store aisle location and pharmacy-specific (prescription) data are not exposed by the public product API and are out of scope.
- The `url` field on each product record is the correct, live walgreens.com product page — it opens normally in a browser. Walgreens' Akamai bot protection stalls or blocks direct HEAD/GET requests to product and category pages from non-browser clients (e.g. `curl`), independent of this actor; the actor itself reaches the same data through Walgreens' public product API rather than by rendering those pages.

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

## `searchQuery` (type: `string`):

Free-text keyword search, e.g. `vitamin c`, `ibuprofen`, `sunscreen`.

## `categoryUrl` (type: `string`):

Full or relative Walgreens *product-listing* category URL (ends `-tier2...`/`-tier3`), e.g. `https://www.walgreens.com/store/c/vitamin-c/ID=361635-tier3`. Copy this from a specific category page on walgreens.com — not a top-level department page (`-tier1`), which lists subcategories rather than products.

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

Walgreens product IDs (e.g. `300405068`, `prod3511`) or full product page URLs.

## `storeId` (type: `integer`):

Walgreens store ID used for local price/availability lookups. Leave as default for a representative US store; change if you need a specific store's pricing.

## `minPrice` (type: `integer`):

Drop products priced below this.

## `maxPrice` (type: `integer`):

Drop products priced above this.

## `inStockOnly` (type: `boolean`):

Only emit products currently in stock (online).

## `brand` (type: `string`):

Exact brand name to keep, e.g. `Nature Made`, `Walgreens`. Case-insensitive.

## `minRating` (type: `number`):

Only emit products with at least this average customer rating (0-5). Products without any reviews yet are kept.

## `onSaleOnly` (type: `boolean`):

Only emit products Walgreens is currently marking as on clearance or at a new lower price.

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "vitamin c",
  "productIds": [],
  "storeId": 15196,
  "inStockOnly": false,
  "onSaleOnly": false,
  "maxItems": 30
}
```

# Actor output Schema

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

Dataset containing all scraped Walgreens products.

# 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 = {
    "mode": "search",
    "searchQuery": "vitamin c",
    "productIds": [],
    "storeId": 15196,
    "inStockOnly": false,
    "onSaleOnly": false,
    "maxItems": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/walgreens-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 = {
    "mode": "search",
    "searchQuery": "vitamin c",
    "productIds": [],
    "storeId": 15196,
    "inStockOnly": False,
    "onSaleOnly": False,
    "maxItems": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/walgreens-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "search",
  "searchQuery": "vitamin c",
  "productIds": [],
  "storeId": 15196,
  "inStockOnly": false,
  "onSaleOnly": false,
  "maxItems": 30
}' |
apify call crawlerbros/walgreens-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlerbros/walgreens-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9JSc3KfFoPg0X5aB4/builds/qGx3UdvLJLAvTBGqf/openapi.json
