# Flipp Flyer Deals Scraper — Weekly Flyers & Prices, CA + US (`yugenox/flipp-flyer-deals-scraper`) Actor

Weekly flyer deals from 2,500+ Canadian and US retailers by postal code or ZIP: search every flyer for a product, or pull every item in every flyer near you. Prices, sale text, unit prices ($/kg), multi-buys, discounts, categories, in-store and online deals, and week-over-week price changes.

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

## Pricing

from $1.50 / 1,000 deals

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

## Flipp Flyer Deals Scraper — Weekly Flyers, Prices & Sales (Canada + US)

Get **weekly flyer deals** from Flipp for **2,500+ Canadian and US retailers** by postal code or ZIP. Search every flyer near you for a product, or pull **every item in every flyer**. Grocery, pharmacy, hardware, electronics, pets, home and more: Walmart, Costco, No Frills, Loblaws, Metro, Sobeys, Shoppers Drug Mart, Canadian Tire, Home Depot, Best Buy, Target, CVS, Walgreens, ALDI, Lowe's and hundreds of independents.

- 🔑 **No login, no API key, no cookies.** Enter a postal code and run.
- 🧩 **Complete results, not the first 200.** A Flipp search stops at 200 results. When a search hits that cap, this actor re-runs it store by store automatically. Example: "chicken" in downtown Toronto gives **197 → 715 deals** in about 30 seconds.
- 📰 **Every item in every flyer.** Full-flyer mode reads whole flyers: about **18,000 items from 108 flyers in 12 seconds** for one Vancouver postal code. Add the region presets for a near-national flyer dataset (46 Canadian cities cover about 1,200 flyers).
- 🧮 **Prices you can compare.** Multi-buys ("2 for $5" → $2.50 each), `/lb` and `/100 g` prices converted to **$/kg**, discount % and $ off, and a `priceRank` (1 = cheapest) within each search.
- 🏬 **Three kinds of deals.** Printed flyer deals, **in-store sale prices at the nearest branch** (with address, SKU and product link), and **online deals** (with SKU, rating and reviews).
- 📈 **Week-over-week tracking.** Each row gets `new` / `price_drop` / `price_up` / `unchanged` and the previous price. Deals that ended are listed too. Schedule it weekly for a deal-alert feed.
- ♻️ **Many postal codes, no duplicates.** Neighbouring postal codes share flyers. Each flyer is read once, and each deal appears once (optional).
- 🇫🇷 **English or French** (Quebec and bilingual chains). US ZIP codes work too.

### Three ways to use it

| Mode | You give | You get |
|---|---|---|
| 🔍 **Search** (default) | Postal codes + search terms (`milk`, `chicken breast`, `tv`) | Every matching flyer deal, in-store price and (optionally) online deal near each postal code |
| 📰 **Full flyers** | Postal codes (+ optional stores, categories, keywords) | Every item printed in every flyer near each postal code |
| 🆔 **Specific flyers** | Flyer ids or flipp.com flyer links | Every item in those flyers |

### Quick start

Compare milk and eggs prices across all stores near a Toronto postal code:

```json
{
  "postalCodes": ["M5V 2T6"],
  "searchTerms": ["milk", "eggs"]
}
```

Every grocery and pharmacy flyer deal in two cities, valid today, with full item details:

```json
{
  "mode": "flyers",
  "postalCodes": ["V6B 1A1", "T2P 1J9"],
  "categories": ["Groceries", "Pharmacy"],
  "onlyValidNow": true,
  "includeItemDetails": true
}
```

A weekly price-drop alert for one chain across Canada (schedule it every Thursday):

```json
{
  "mode": "flyers",
  "regionPresets": ["ca-major-cities"],
  "merchants": ["No Frills"],
  "trackChanges": true
}
```

### Output

One row per deal. Here is a real row from a "chicken" search with item details on:

```json
{
  "itemId": "1039620999",
  "itemType": "flyer",
  "name": "Maple Leaf Prime raised without antibiotics boneless skinless chicken breasts 3-piece",
  "brand": "Maple Leaf",
  "merchant": "Walmart",
  "merchantId": 234,
  "flyerId": 8129937,
  "flyerName": "Flyer",
  "flyerCategories": ["Groceries", "General Merchandise"],
  "categoryL1": "Food, Beverages & Tobacco",
  "categoryL2": "Food Items",
  "currentPrice": 6.34,
  "originalPrice": 7.43,
  "currency": "CAD",
  "effectivePrice": 6.34,
  "priceText": "6.34",
  "postPriceText": "lb",
  "saleStory": "Rollback",
  "priceUnit": "lb",
  "pricePerKg": 13.98,
  "multiBuy": null,
  "discountPct": 15,
  "dollarsOff": 1.09,
  "validFrom": "2026-09-17T04:00:00+00:00",
  "validTo": "2026-09-24T03:59:59+00:00",
  "imageUrl": "https://f.wishabi.net/page_items/433472261/1789053555/extra_large.jpg",
  "productUrl": "https://www.walmart.ca/en/ip/3VLCAVLWS55J?...",
  "sku": "3VLCAVLWS55J",
  "description": "#51053321. $16.38/kg, $13.98/kg.",
  "inStoreOnly": false,
  "priceRank": 73,
  "detailsIncluded": true,
  "searchTerm": "chicken",
  "postalCode": "M5V2T6",
  "locale": "en-ca",
  "scrapedAt": "2026-09-24T02:46:06.597Z"
}
```

A multi-buy deal is parsed into a per-item price:

```json
{ "name": "Longo's Chicken Wings, Chicken Tenders or Bites", "merchant": "Longos", "currentPrice": 23, "prePriceText": "2 FOR",
  "multiBuy": { "quantity": 2, "totalPrice": 23, "pricePerItem": 11.5 }, "effectivePrice": 11.5 }
```

#### Fields

| Field | Description |
|---|---|
| `itemId`, `itemType` | Deal id; `flyer` (printed flyer), `store` (in-store price at the nearest branch) or `online` |
| `name`, `brand`, `description`, `sku` | What's on sale. `description` usually has the size and varieties ("2 L, selected varieties") |
| `merchant`, `merchantId` | The retailer. `storeAddress` and `storeId` are filled for in-store prices |
| `flyerId`, `flyerName`, `flyerCategories` | The flyer it came from and its categories (Groceries, Pharmacy, Home & Garden…) |
| `categoryL1`, `categoryL2` | Product category (search mode), e.g. "Food, Beverages & Tobacco" › "Beverages" |
| `currentPrice`, `originalPrice` | Sale price and regular price, as numbers |
| `currency` | `CAD` or `USD` (from the flyer's own locale, so a US flyer read from a Canadian postal code is still USD) |
| `priceText`, `prePriceText`, `postPriceText`, `saleStory` | The flyer's own text: "2/", "Member Price", "/lb", "ea.", "SAVE $3", "Rollback" |
| `effectivePrice` | Price for one item (multi-buys divided out) |
| `priceUnit`, `pricePerKg` | What the price is per (`each`, `lb`, `kg`, `100g`, `pack`), and $/kg for weight-priced items |
| `multiBuy` | `{ quantity, totalPrice, pricePerItem }` for "2 for $5"-style deals |
| `discountPct`, `dollarsOff` | Discount vs the regular price (or as stated by the retailer) |
| `validFrom`, `validTo` | When the deal runs |
| `imageUrl`, `productUrl` | Item image; the retailer's product page (with item details, and for in-store prices) |
| `inStoreOnly`, `disclaimer`, `rating`, `reviewCount` | Extra detail where the retailer provides it |
| `priceRank` | 1 = cheapest in that search (by $/kg for weight-priced items, by item price otherwise) |
| `searchTerm`, `postalCode`, `locale` | Which search and postal code found the deal |
| `changeType`, `previousPrice` | With change tracking on: `new`, `price_drop`, `price_up` or `unchanged`, and last run's price |

`detailsIncluded` tells you whether the row got the item details add-on.

### Input

| Field | Description |
|---|---|
| `mode` | `search` (default), `flyers` or `flyerIds` |
| `postalCodes` | Canadian postal codes (`M5V 2T6`) or US ZIP codes (`10001`). Must be the full code |
| `searchTerms` | Products to search for. In full-flyer modes they filter the items |
| `flyerIds` | Flyer ids or flipp.com flyer links (for `flyerIds` mode) |
| `regionPresets` | `ca-major-cities` (46 cities, every province and territory) and/or `us-major-cities` (50 metros) |
| `maxItems` | Maximum deals for the whole run (empty = no limit) |
| `merchants` | Only these stores, by name or `merchantId` |
| `categories` | Only these flyer or product categories (partial names work) |
| `itemTypes` | Search mode: `flyer`, `store`, `online` (default flyer + store) |
| `onlyValidNow` | Skip deals from flyers that haven't started yet or have ended |
| `sortBy` | Search mode: `relevancy`, `price_low_to_high`, `price_high_to_low` |
| `includeItemDetails` | Add description, SKU, product link, sale and unit text, in-store-only flag and ratings to flyer deals |
| `trackChanges` | Week-over-week changes against the previous run of the same input |
| `completeCoverage` | Search mode: get past the 200-result cap by splitting per store (default on) |
| `dedupeAcrossPostalCodes` | Each deal once across postal codes (default on) |
| `language` | `en` or `fr` (Canada) |
| `maxItemsPerPostalCode`, `maxPostalCodes`, `maxConcurrency`, `proxyConfiguration` | Limits and tuning |

### Use cases

- **Grocery price comparison and "cheapest near me" apps.** Search a basket of products across every store near a postal code, sorted by $/kg or item price.
- **CPG and retail analytics.** Track which brands are promoted, at what discount, by which chains and in which regions, week after week.
- **Deal alerts and newsletters.** Schedule a weekly run with change tracking and send only the new deals and price drops.
- **Competitive pricing.** Watch competitors' flyer prices and promotions by city.
- **Flyer archives and datasets.** Near-national weekly snapshots of every flyer item with categories, prices and validity dates.

### FAQ

**How fresh is the data?** Live at run time. Most retailers publish new flyers weekly, often a day or two before they start. Use `onlyValidNow` to keep only what's valid today.

**Why do I get more than 200 results for a search?** Flipp stops each search at 200 results. When a search hits that cap, the actor re-runs it for each store that has matches and merges the results, so you get the long tail too. Turn `completeCoverage` off for a quick top-200 sample.

**Why are some prices empty?** Some flyer items have no single price ("20% off all toys", "Buy 1 get 1"). `discountPct` or `saleStory` then carries the deal. In full-flyer mode, `includeItemDetails` fills the sale text and units for most items.

**Which postal codes work?** Any full Canadian postal code or US ZIP code. The first three characters alone (e.g. "M5V") are not enough.

**How many postal codes should I use for a whole city or country?** One downtown postal code covers the flyers for most of a metro area. For national coverage, use `regionPresets`: flyers shared between cities are read only once.

**What does "in-store price" mean?** Some chains publish their own current sale prices per store. These rows (`itemType: "store"`) include the store address, SKU and a link to the product page.

**How does change tracking work?** The actor keeps a small snapshot of the last run for each distinct input in your Apify account. Run the same input again, for example on a weekly schedule, and each deal is compared with the last run. The run's `CHANGES` record lists totals and the deals that expired.

**How am I charged?** You pay per deal saved. The optional item details are a small add-on per enriched deal. Deals removed by your filters or as duplicates are not charged.

**Is it legal to scrape Flipp?** This Actor only collects publicly available data: weekly flyer deals, prices, product details and store locations that anyone can see on Flipp 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 Flipp's 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 Flipp 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

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

Search: find a product across every flyer, in-store sale and online deal near each postal code. Full flyers: every item in every flyer near each postal code, optionally narrowed by store, flyer category or keywords. Specific flyers: every item in the flyers you list.

## `postalCodes` (type: `array`):

Full Canadian postal codes (e.g. M5V 2T6) or US ZIP codes (e.g. 10001). Deals are what's available near each one. Flyers shared by several codes are only read (and charged) once.

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

Products to look for, e.g. milk, chicken breast, tv. In Search mode each term is its own search. In Full-flyer mode they filter the flyer items (a row matches when every word of a term starts a word in the item name, brand or description).

## `flyerIds` (type: `array`):

For 'Specific flyers' mode: flyer ids (e.g. 8148102) or flipp.com flyer links. Flyer ids are in the output of any run (flyerId).

## `regionPresets` (type: `array`):

Add one postal code per major city: 46 Canadian cities (every province and territory — about 1,200 distinct flyers) and/or 50 US metros (about 800 flyers). Combine with Full flyers mode for a near-national flyer dataset. Neighbouring cities share most flyers; they are deduplicated.

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

Maximum number of deals across the whole run. Leave empty for no limit (a full flyer sweep of one big-city postal code is ~15,000–30,000 items).

## `merchants` (type: `array`):

Only these retailers, by name (e.g. No Frills, Walmart, Shoppers Drug Mart, Canadian Tire, Target) or Flipp store id (merchantId in the output). Leave empty for all stores.

## `categories` (type: `array`):

Only deals in these categories. Matches the flyer category (Groceries, Pharmacy, Home & Garden, Electronics, General Merchandise, Pets, Sporting Goods, Automotive, Fashion, Baby & Kids, Office, Specialty, Restaurants) and, in Search mode, the product category too (e.g. Beverages, Meat). Partial names work.

## `itemTypes` (type: `array`):

Flyer: deals printed in weekly flyers. In-store: a chain's own sale price at the nearest branch (with store address, SKU and product link). Online: online-store deals (with SKU, rating and reviews). Full-flyer modes always return flyer deals.

## `onlyValidNow` (type: `boolean`):

Skip deals from flyers that haven't started yet (next week's flyers are often published a day or two early) or have ended.

## `sortBy` (type: `string`):

Order of search results. Every row also gets a priceRank (1 = cheapest in that search; $/kg for weight-priced items).

## `includeItemDetails` (type: `boolean`):

Add each flyer item's description (size, varieties), SKU, the retailer's product link, sale text, pre/post price text, in-store-only flag, disclaimer and ratings. In Full-flyer mode this is also what fills the sale text and unit (/lb, ea.) columns. Billed as a separate small add-on per enriched item.

## `trackChanges` (type: `boolean`):

Compare with the previous run of the same input: each row gets changeType (new / price\_drop / price\_up / unchanged) and previousPrice, and the CHANGES record lists deals that expired. Schedule the run weekly (flyers roll over mid-week) for a deal-alert feed.

## `completeCoverage` (type: `boolean`):

Flipp returns at most 200 results per search. When a search hits that cap, it is automatically re-run store by store so you get every matching deal (e.g. 197 → 700+ for "chicken" in Toronto). Turn off for a quick top-200 sample.

## `dedupeAcrossPostalCodes` (type: `boolean`):

The same flyer usually covers many postal codes. On (default): each deal is returned once, tagged with the first postal code it was found for. Off: one row per deal per postal code.

## `language` (type: `string`):

French returns French item names and flyers where the retailer publishes them (Quebec and bilingual chains). US ZIP codes are always English.

## `maxItemsPerPostalCode` (type: `integer`):

Cap for each postal code. Leave empty for no per-postal-code limit.

## `maxPostalCodes` (type: `integer`):

Safety cap on how many postal codes (including region presets) one run covers.

## `maxConcurrency` (type: `integer`):

How many requests run at once. The default is fast and gentle; higher is rarely needed.

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

Apify datacenter proxy works well and is the default. Slow or blocked IPs are rotated automatically, with a residential fallback.

## Actor input object example

```json
{
  "mode": "search",
  "postalCodes": [
    "M5V 2T6"
  ],
  "searchTerms": [
    "milk",
    "chicken"
  ],
  "maxItems": 100,
  "itemTypes": [
    "flyer",
    "store"
  ],
  "onlyValidNow": false,
  "sortBy": "relevancy",
  "includeItemDetails": false,
  "trackChanges": false,
  "completeCoverage": true,
  "dedupeAcrossPostalCodes": true,
  "language": "en",
  "maxPostalCodes": 100,
  "maxConcurrency": 8,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped deals.

## `changes` (type: `string`):

Change summary (only when change tracking is on): new deals, price drops and increases, expired deals.

## `run` (type: `string`):

Status and statistics for this run.

# 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 = {
    "postalCodes": [
        "M5V 2T6"
    ],
    "searchTerms": [
        "milk",
        "chicken"
    ],
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/flipp-flyer-deals-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 = {
    "postalCodes": ["M5V 2T6"],
    "searchTerms": [
        "milk",
        "chicken",
    ],
    "maxItems": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/flipp-flyer-deals-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 '{
  "postalCodes": [
    "M5V 2T6"
  ],
  "searchTerms": [
    "milk",
    "chicken"
  ],
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/flipp-flyer-deals-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yugenox/flipp-flyer-deals-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/58sScnjADg9dhsVve/builds/CbtJo69RswXmbap40/openapi.json
