# London Drugs Scraper — Prices, Sales, Stock & UPCs (`yugenox/london-drugs-scraper`) Actor

Scrape londondrugs.com by keyword, category, product link or the whole ~30,000-product catalogue: price, regular vs sale price, % off, online stock, ship/pickup options, ratings, brand, size, category and variants — plus UPC barcodes, part numbers and full descriptions. Canada, CAD. No login.

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

## Pricing

from $1.50 / 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.

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

## London Drugs Scraper — prices, sales, online stock & UPCs

Scrape **londondrugs.com** — the Western Canadian pharmacy, electronics, beauty, photo and home retailer — and get clean, structured product data in CAD: current price, regular vs sale price, % off, online stock count, ship-to-home / in-store pickup, star rating and review count, brand, size, model, category breadcrumb and colour/size variants. Turn on product details for **UPC barcodes**, manufacturer part numbers, full descriptions, every image and sale end dates.

Search by keyword, paste category or product links, or crawl the **whole ~30,000-product catalogue**. No account, no login, no cookies to supply.

**Your Apify account must be able to use residential proxies** (London Drugs refuses datacenter IPs); if it can't, the run stops within a few seconds with 0 results and a status message saying what to change.

### What you can scrape

| Input | Example | What you get |
|---|---|---|
| Search terms | `vitamin c`, `air fryer`, `062600263865` (UPC), `L0581327` (item code) | Every matching product. Brand and department words (`shampoo`, `tylenol`, `lego`) open that department automatically, just like on the site. |
| Category links | `https://www.londondrugs.com/category/air-purifiers/c/53` | The whole category, with any filters/sort in the link kept. |
| Product links | `https://www.londondrugs.com/products/…/p/L0581327` | That product with full product-page details. |
| Whole catalogue | tick **Crawl the whole catalogue** | All ~30,000 products (use **Max results in total** to sample). |

### Data you get

- **Identity:** item code, variant code, UPC/GTIN, name, brand, model, size, department, category path (e.g. `Health & Personal Care > Wellness > Vitamins & Supplements > Vitamins A-K`), product URL, image
- **Pricing (CAD):** current price, regular price, sale price, list price, on-sale flag, % off, $ saved, price range across variants, quantity price tiers, sale end date\*
- **Availability:** available online, **units in stock online**, ship to home, in-store pickup, pickup-only\*, special order\*, max quantity per order
- **Reviews:** average rating, review count
- **Variants:** colour/size options, every variant's item code — or one row per variant with its own price, stock, UPC and model
- **Extras:** specifications (dietary and ingredient flags, flavour, colour…), badges (Proudly Canadian, Vegan, Cruelty-Free…), full description as HTML and plain text\*, all images\*, subscribe-and-save frequencies\*
- **Context:** search term, category the search opened, position in the results, scrape time

\* with **Include product page details**

### How to use it

1. Enter one or more **search terms** and/or paste **londondrugs.com links**.
2. Set **Max results per search term / link** (default 200; 0 = everything) and optionally **Max results in total**.
3. Optional: **Sort by** price or rating, **On sale only**, **Hide unavailable items**.
4. Optional: **Include product page details** (UPC, part number, description, images) and **One row per variant**.
5. Run, then download as JSON, CSV or Excel, or use the **Overview** and **Barcodes & details** table views.

Leave the proxy on its default (Apify residential, Canada).

#### Example input

```json
{
  "searchTerms": ["vitamin c", "wireless earbuds"],
  "startUrls": [{ "url": "https://www.londondrugs.com/category/air-purifiers/c/53" }],
  "maxItemsPerQuery": 200,
  "sort": "price-asc",
  "onlyOnSale": false,
  "includeDetails": false,
  "expandVariants": false
}
```

### Output example

A variant row with product page details (trimmed):

```json
{
  "productCode": "M0009577",
  "sku": "L1248084",
  "upc": "802118131658",
  "name": "Logiix tuneFREQS USB-C In-Ear Headphones",
  "variantOptions": { "Color": "SILVER" },
  "brand": "LOGIIX",
  "model": "LGX13165",
  "url": "https://www.londondrugs.com/products/logiix-tunefreqs-usb-c-in-ear-headphones/p/L1248084",
  "imageUrl": "https://cdn-tp2.mozu.com/28945-m1/cms/files/L1248084/large/L1248084.JPG",
  "price": 24.99,
  "regularPrice": 34.99,
  "salePrice": 24.99,
  "onSale": true,
  "discountPct": 29,
  "savings": 10,
  "currency": "CAD",
  "isAvailable": true,
  "onlineStockLevel": 3,
  "shipToHome": true,
  "inStorePickup": true,
  "categoryPath": "Electronics > Portable Audio > Headphones > Wired Headphones",
  "variantCount": 2,
  "variants": [
    { "sku": "L1248066", "options": { "Color": "Grey" } },
    { "sku": "L1248084", "options": { "Color": "SILVER" } }
  ],
  "rowType": "variant",
  "descriptionText": "Give your favourite music and podcasts sharp, detailed sound quality…",
  "scrapedAt": "2026-09-24T03:30:51.712Z"
}
```

A search result row (no extra options):

```json
{
  "productCode": "L0876917",
  "sku": "L0876917",
  "name": "Hask Tea Tree Oil & Rosemary Shampoo - 355ml",
  "brand": "HASK",
  "price": 11.99,
  "regularPrice": 11.99,
  "onSale": false,
  "isAvailable": true,
  "onlineStockLevel": 59,
  "rating": 4.52,
  "reviewCount": 412,
  "size": "355ml",
  "badges": ["Paraben-Free", "Phthalate-Free", "Product is Vegan", "Sulfate-free"],
  "categoryPath": "Beauty > Hair Care > Shampoo & Conditioner > Shampoo > Natural Shampoo",
  "position": 1,
  "query": "shampoo",
  "resolvedCategory": "/category/shampoo/c/855",
  "rowType": "product"
}
```

### Use cases

- **Price monitoring:** track London Drugs prices and sales daily across a category or the whole catalogue, and get alerted when a product goes on sale.
- **Competitive pricing:** match products by **UPC** against other Canadian retailers (Shoppers, Walmart, Best Buy, Canadian Tire, Loblaw banners) for price-gap analysis.
- **Brand & MAP compliance:** check how your products are priced, discounted and stocked at London Drugs.
- **Stock intelligence:** online stock counts show sell-through and out-of-stocks over time.
- **Assortment research:** see which brands, sizes and variants London Drugs carries in each category.

### FAQ

**How many products can I get?**
Everything London Drugs sells online — about 30,000 products. A search or category returns all of its results (set the per-search limit to 0).

**How fast is it?**
Search and category pages return up to 200 products per page: 1,000 products take about 15–30 seconds, the whole ~30,000-product catalogue about 5 minutes. Product page details and one-row-per-variant add one page per product or variant, which is slower.

**Why do some products show a price range and no stock?**
Products sold in several colours or sizes come back as one row (`rowType: "variantGroup"`) with the lowest and highest price and the list of variants — London Drugs publishes stock per variant, not per product. Turn on **One row per variant** to get each variant's own price, stock, UPC and model.

**Why is `upc` empty on some rows?**
Search and category pages include barcodes only for some items. Turn on **Include product page details** to look it up for every product.

**Why is `rating` empty?**
The product has no reviews yet.

**What do the `specifications` codes like "1" or "2" mean?**
Dietary and ingredient flags are published as codes. The `badges` field lists the ones the product actually displays (e.g. Vegan, Paraben-Free).

**Can I get store-by-store stock?**
Not in this version — stock is the online stock count. Tell us in the Issues tab if you need per-store stock.

**Are duplicates removed?**
Yes. If two search terms return the same product, it is returned once (with the first search term). Product links are always returned.

**Will a full crawl skip products?**
When you take everything a category or search has (per-search limit 0, sort "Recommended"), results are paged in item-code order, which cannot shift between pages, so nothing is skipped or returned twice. The `position` field then follows that order. If londondrugs.com fails to show one product on a results page, the scraper narrows the page down and keeps every other product on it. The run status says how many products, if any, could not be loaded.

**Why is `price` empty on gift cards?**
Variable-amount gift cards have no fixed price on the site (it shows $0). The scraper returns `null` for them rather than 0.

**Can I scrape one colour or size of a product?**
Yes. Paste the product link with the colour or size selected, e.g. `.../p/M0009577?Variant%20Color=SILVER`. You get that variant's own price, stock and UPC.

**Do I need a London Drugs account or cookies?**
No.

**Do I need a proxy?**
Yes: residential proxies. London Drugs refuses datacenter IPs and direct connections, so keep the Proxy input on its default (Apify Proxy, group RESIDENTIAL, country Canada), or paste your own residential proxies. Your Apify account has to be able to use residential proxies. If it can't, the run ends in a few seconds with 0 results and no per-result charge, and the status message says so. Enable residential proxies on your Apify account (Apify Console → Proxy) and run again.

**How much does it cost?**
You pay per product returned. Products from search, category and catalogue pages cost $1.50 per 1,000. Products built from their own product page cost $6.00 per 1,000, because each one needs an extra page load. That applies to every product when **Include product page details** is on, to each colour/size row when **One row per variant** is on, and to pasted product links (or a UPC / item-code search that opens a product page). Each row is charged once, at one of the two prices. There is also a start fee of $0.00005 per run. If a run returns nothing (no results, or the site was unavailable), you pay only the start fee.

**Is it legal to scrape London Drugs?**
This Actor only collects publicly available data: product listings, prices, stock levels and product details that anyone can see on londondrugs.com without an account. Collecting publicly available data is generally legal, but you're responsible for how you use it. You must follow privacy laws such as GDPR, PIPEDA and CCPA, as well as London Drugs' terms. If you're unsure, check with a lawyer. More on this: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it access any private data?**
No. Everything comes from pages London Drugs shows to any visitor without logging in. It never uses a login, never touches private or restricted accounts, and never reaches password-protected areas.

# Actor input Schema

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

What you would type into the londondrugs.com search box: product names, brands, keywords, UPC barcodes or London Drugs item codes (L0581327). Brand and department words (shampoo, tylenol, lego) open that department automatically. Each term is scraped separately.

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

Category pages (e.g. https://www.londondrugs.com/category/air-purifiers/c/53), search result pages, or product pages. Filters and sort order in a category link are kept.

## `crawlWholeCatalog` (type: `boolean`):

Every product on londondrugs.com (about 30,000). Combine with Max results in total to take a sample. Only Max results in total limits this crawl.

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

Stop the whole run after this many rows. 0 = no overall limit.

## `maxItemsPerQuery` (type: `integer`):

Upper limit for each search term or link. 0 = everything it has (a department can hold thousands of products).

## `sort` (type: `string`):

Order of search and category results, as on the website. Useful with a per-search limit, e.g. the 100 cheapest.

## `onlyOnSale` (type: `boolean`):

Keep only products currently priced below their regular price.

## `onlyAvailable` (type: `boolean`):

Drop items London Drugs marks as unavailable online. Products sold in several colours/sizes are kept (their availability is per variant — turn on One row per variant to see it).

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

Open each product page for UPC barcode, manufacturer part number, full description, all images, sale end date, category names, subscribe-and-save frequencies and shipping/pickup flags. One extra page per product, so runs are slower.

## `expandVariants` (type: `boolean`):

Products sold in several colours or sizes normally come back as one row with a price range and the list of variants. Turn this on to get one row per variant with that variant's own price, sale price, online stock, UPC and model number (one extra page per variant).

## `concurrency` (type: `integer`):

How many pages to load at the same time. 5 is a good balance.

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

London Drugs only answers residential connections. Keep Apify residential proxies with country Canada (the default); other settings fall back to it automatically.

## `_noResidential` (type: `boolean`):

Internal (canaries): behave exactly like an account without the RESIDENTIAL proxy group.

## `_noUnblocker` (type: `boolean`):

Internal (canaries): behave exactly like an account without the UNBLOCKER proxy group.

## Actor input object example

```json
{
  "searchTerms": [
    "vitamin c",
    "wireless earbuds"
  ],
  "crawlWholeCatalog": false,
  "maxItems": 50,
  "maxItemsPerQuery": 200,
  "sort": "recommended",
  "onlyOnSale": false,
  "onlyAvailable": false,
  "includeDetails": false,
  "expandVariants": false,
  "concurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "CA"
  },
  "_noResidential": false,
  "_noUnblocker": false
}
```

# Actor output Schema

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

Every scraped product as JSON.

## `productsCsv` (type: `string`):

The same rows as CSV, for a spreadsheet or price tracker.

## `productsTable` (type: `string`):

Image, product, price, discount, stock, rating and link.

# 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": [
        "vitamin c"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "CA"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/london-drugs-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": ["vitamin c"],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "CA",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/london-drugs-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": [
    "vitamin c"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "CA"
  }
}' |
apify call yugenox/london-drugs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yugenox/london-drugs-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/1cQy9sgntNuOFSe63/builds/sVPEHwyjU1TMi7DGr/openapi.json
