# Canada Recalls & Safety Alerts (`loonieledger/canada-recalls-safety-alerts`) Actor

Search and monitor official Government of Canada recalls and safety alerts (food, consumer products, vehicles, medical devices, drugs and health products) from the open data feed, with keyword, agency, category and date filters.

- **URL**: https://apify.com/loonieledger/canada-recalls-safety-alerts.md
- **Developed by:** [Keegan Carpentier](https://apify.com/loonieledger) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 results

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

## Canada Recalls & Safety Alerts Scraper (Health Canada, CFIA, Transport Canada)

Get every Government of Canada **recall and safety alert** as clean JSON, CSV or Excel. That covers food (CFIA), consumer products, drugs and health products, medical devices, and vehicles (Transport Canada). Filter by keyword, agency, category, recall class and date. You can also schedule it as a **"new recalls only"** monitor that feeds Slack, email, Google Sheets or your own app.

- ✅ Official open data. No scraping of web pages, no login, no API key
- ✅ English **or French** feed (the French feed also accepts the English agency and class names)
- ✅ `onlyNew` monitoring mode: scheduled runs return only notices that are new or updated since the last run
- ✅ The "What you should do" advice is split into clean step lists
- ✅ Pay only for the results you get. `maxItems` and Apify's "max cost per run" both cap your spend

### Who it's for

- **Retailers, grocers, importers and e-commerce sellers** who check their catalogue against new Canadian recalls every day
- **Food-safety, QA and compliance teams** who need an audit trail of CFIA Class 1 allergen and pathogen recalls
- **Fleet managers, dealers and auto shops** who watch Transport Canada vehicle recalls
- **Journalists, researchers and app builders** who need a structured recall history (the feed holds about 34,000 notices, with last-updated dates going back to the 1990s; about 14,000 of them are marked archived)

### Input

| Field | What it does | Default |
|---|---|---|
| `language` | `en` or `fr` feed | `en` |
| `keywords` | Keep notices whose title, product, issue or category contains **any** of these words | `["peanut","salmonella"]` (prefill) |
| `organizations` | Issuing program, e.g. `CFIA`, `Consumer product safety`, `TC`, `Medical devices`, `Drugs and health products`, `Marketed health products` | all |
| `categories` | Category contains any of these words, e.g. `Food`, `Toys`, `SUV`, `Household` | all |
| `recallClasses` | e.g. `Class 1` (most serious food/health risk) or `Type I` | all |
| `updatedWithinDays` / `updatedSince` | Date window on the notice's *last updated* date | 30 days |
| `includeArchived` | Include notices marked archived | off |
| `onlyNew` | Remember what was already returned and give only new or updated notices | off |
| `maxItems` | Hard cap on results (and on cost) | 500 |

Example: a daily allergen watch

```json
{ "organizations": ["CFIA"], "keywords": ["undeclared", "allergen", "milk", "peanut"],
  "recallClasses": ["Class 1"], "updatedWithinDays": 7, "onlyNew": true, "maxItems": 200 }
```

### Output

Each row is one notice. Here is a real record from a live test on 29 Sep 2026 (the long text is shortened):

```json
{
  "recallId": "82689",
  "title": "Smarter Snacks brand Vegan Protein Puff Chili & Lime Flavored contains undeclared milk",
  "url": "https://recalls-rappels.canada.ca/en/alert-recall/smarter-snacks-brand-vegan-protein-puff-chili-lime-flavored-contains-undeclared-milk",
  "organization": "CFIA",
  "product": "Vegan Protein Puff Chili & Lime Flavored",
  "issue": "Milk",
  "category": "Candy, confectionary, snacks and sweeteners",
  "recallClass": "",
  "whatYouShouldDoSteps": ["Check to see if you have affected products",
    "Do not consume affected products to which you are allergic or sensitive as they may cause a serious or life-threatening reaction",
    "Do not serve, use, sell or distribute affected products", "…"],
  "lastUpdated": "2026-09-28",
  "archived": false,
  "language": "en",
  "licence": "Open Government Licence – Canada",
  "attribution": "Contains information licensed under the Open Government Licence – Canada."
}
```

The full field list is in `.actor/dataset_schema.json`, and more real rows are in `sample_output.json`. The dataset's **Overview** table view shows the date, program, category, class, title, issue and link.

### Scheduling a recall monitor

1. Save your input as a **Task** with `onlyNew: true`.
2. Add a daily **Schedule**. The source file is regenerated once a day at about 02:18 UTC, so a run any time after 03:00 UTC picks up that day's changes.
3. Add a webhook or integration (Slack, email, Google Sheets, Zapier or Make) on *Run succeeded*.

The first run returns everything that matches. After that, a run returns only notices it hasn't returned before, plus any notice whose *last updated* date changed. Your state is kept in a named key-value store (`canada-recalls-state`). Delete that store to start over.

### Pricing

**Pay per result.** You're charged once for each notice written to the dataset. Runs that find nothing new cost only Apify's standard start event. Set `maxItems` or a maximum cost per run and the Actor stops cleanly when it reaches the limit.

### Data source, licence and privacy

- Source: *Recalls and safety alerts* open dataset, Government of Canada: https://open.canada.ca/data/en/dataset/d38de914-c94c-429b-8ab1-8776c31643e3 (feed files on recalls-rappels.canada.ca, about 34,000 notices, updated daily).
- Licence: **Open Government Licence – Canada** (https://open.canada.ca/en/open-government-licence-canada). Commercial use is allowed with attribution. Every row carries the required statement: *"Contains information licensed under the Open Government Licence – Canada."*
- The feed has notice-level product information only. It contains **no personal information**.
- This Actor is **unofficial**. It is not affiliated with or endorsed by the Government of Canada, Health Canada, CFIA or Transport Canada. The official notice (`url`) is always the source of truth. Don't use this Actor as your only safety control.

### Limits and notes

- `recallClass` is empty for many older and Transport Canada notices, because the source leaves it blank.
- Category names in the French feed are in French (for example *Aliments* or *Jouets et jeux*). Filter with French words when `language` is `fr`.
- Some edge servers of the Government of Canada CDN keep serving a copy of the daily file that's a day or two old. The Actor adds an hourly cache key so it always reads the current file, and it logs the file's `Last-Modified` time on every run.

# Actor input Schema

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

Language of the feed to read (English or French).

## `keywords` (type: `array`):

Return only recalls whose title, product, issue or category contains ANY of these words (case-insensitive). Leave empty for all.

## `organizations` (type: `array`):

Filter by the 'Organization' field of the feed, e.g. CFIA (food), Consumer product safety, TC (Transport Canada vehicles), Medical devices, Drugs and health products, Marketed health products. Leave empty for all. English names also work with the French feed.

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

Keep notices whose category contains any of these words (case-insensitive), e.g. Food, Toys, Car, SUV, Household. The French feed uses French category names (e.g. Aliments, Jouets). Leave empty for all.

## `recallClasses` (type: `array`):

Keep only these recall classes, e.g. 'Class 1' (food/health risk levels) or 'Type I' (Health Canada). 'Classe 1' also works. Leave empty for all.

## `updatedWithinDays` (type: `integer`):

Only return recalls whose 'Last updated' date is within this many days. 0 = no date limit.

## `updatedSince` (type: `string`):

Optional absolute start date. Overrides 'Updated within the last N days' when set.

## `includeArchived` (type: `boolean`):

The feed marks older notices as archived. Off = current notices only.

## `onlyNew` (type: `boolean`):

Remembers recall IDs + last-updated dates between runs (in a named key-value store) and only returns new or updated notices. Ideal for scheduled daily alerts.

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

Stop after this many results. Controls cost.

## Actor input object example

```json
{
  "language": "en",
  "keywords": [
    "peanut",
    "salmonella"
  ],
  "updatedWithinDays": 30,
  "includeArchived": false,
  "onlyNew": false,
  "maxItems": 500
}
```

# Actor output Schema

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

Recalls and safety alerts written to the default dataset

# 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 = {
    "keywords": [
        "peanut",
        "salmonella"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("loonieledger/canada-recalls-safety-alerts").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 = { "keywords": [
        "peanut",
        "salmonella",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("loonieledger/canada-recalls-safety-alerts").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 '{
  "keywords": [
    "peanut",
    "salmonella"
  ]
}' |
apify call loonieledger/canada-recalls-safety-alerts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,loonieledger/canada-recalls-safety-alerts"
        }
    }
}
```

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/gudo24Dwb4gWP0GhT/builds/5TsbvVwuLmJZBxGV7/openapi.json
