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

Search official Canada product recalls and safety alerts from open.canada.ca. Filter by keyword, category and date range. Returns recall details, hazards, affected products and what to do.

- **URL**: https://apify.com/darknezz/canada-recalls-safety-alerts.md
- **Developed by:** [Oaida Adrian](https://apify.com/darknezz) (community)
- **Categories:** Business, Automation, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 recall extracteds

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/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

## Canada Product Recalls & Safety Alerts

Scrape **Canada's official product recall and safety alert database** — Health Canada's `recalls-rappels.canada.ca` (open.canada.ca) — and get structured JSON recall records: consumer products, vehicles, food, drugs and health products. Filter by keyword, category and last-updated date.

Built for compliance teams, importers, retailers and safety monitors who need a reliable, always-current feed of Canadian recall activity — no API keys, no login, no proxy budget.

### Why this Actor

- **One source, one job** — reads the Government of Canada recall database directly; no third-party aggregators, no licensing ambiguity.
- **No API key, no login, no proxy** — the site is fully public; the Actor just needs a browser User-Agent (the site 418s plain script clients).
- **Structured, reference-shaped output** — every recall is one JSON row with 17 fields matching the community `dromb/canada-recalls-safety-alerts` schema, so existing consumers can switch with zero changes.
- **Filters built in** — keyword full-text search plus post-filters on category and last-updated date.
- **Cheap and fast** — pay only per recall extracted, plus Apify's standard platform events.

### How it works

The Actor runs a full-text search against the site's Drupal search index (`/en/search?search_api_fulltext=<keyword>`), pages through the results, visits each recall page (`/en/alert-recall/<slug>`), and parses the structured Drupal fields into clean records. Archived recalls are excluded (matching the reference actor's behaviour), so every row is an active recall.

### Input

```json
{
  "keyword": "battery",
  "category": "Electronics",
  "dateFrom": "2026-06-01",
  "maxItems": 50
}
```

| Field | Type | Description |
|---|---|---|
| `keyword` | string | Full-text search term (e.g. `battery`, `croissant`, `vehicle`). Empty = browse the latest recalls. |
| `category` | string | Category filter — case-insensitive partial match against the recall category (e.g. `Electronics`, `Household items`, `Vehicles`). |
| `dateFrom` | string | Only include recalls last updated on or after this date (`YYYY-MM-DD`). |
| `maxItems` | integer | Maximum recall records to extract (default 50, max 500). |

All fields are optional — `{}` returns the most recent active recalls.

### Output (one item per recall)

```json
{
  "recallId": 82426,
  "title": "Portable Clip-On Rechargeable Mini Fan recalled due to fire hazard",
  "dateUpdated": "2026-08-12",
  "recallClass": null,
  "category": "Household items",
  "summary": "Fire hazard",
  "affectedProducts": "Portable Clip-On Rechargeable Mini Fan",
  "companies": "Consumer product safety",
  "hazard": null,
  "issue": "Fire hazard",
  "whatToDo": "Consumers should immediately stop using the recalled product and return it to CTG Brands Inc. for a refund.For more information, consumers can contact CTG Brands Inc. by telephone at 1-888-781-8882, 8:30 a.m. to 5:00 p.m. EST, Monday to Friday, or visit the company website...",
  "archived": false,
  "status": "active",
  "language": "en",
  "sourceUrl": "https://recalls-rappels.canada.ca/en/alert-recall/portable-clip-rechargeable-mini-fan-recalled-due-fire-hazard",
  "dataSource": "open.canada.ca",
  "rawSourceType": "recall_record"
}
```

Field notes (matching the reference actor): `category` strips the top-level taxonomy prefix (`Consumer products - Electronics` → `Electronics`); `summary`/`issue` mirror the short issue label (last `-` segment); `whatToDo` is the long-form consumer guidance (`null` when the page has none); `recallClass` is `Type I/II/III` for health-product recalls, `Class 1/2/3` for food recalls, else `null`; `companies` is the issuing organization from publisher metadata (`Consumer product safety`, `CFIA`, `TC`); `archived` is always `false` / `status` always `active` because the search surface excludes archived recalls.

### Use cases

- 🛡️ **Compliance monitoring** — weekly cron on a product category (electronics, toys, food) and alert on new recalls via Telegram or webhook.
- 🏭 **Importer / retailer screening** — check a product line against active recalls before ordering or listing.
- 📊 **Safety trend analysis** — pull all recalls in a category over a window and analyse hazard mix, issuing agency and product types.
- 🗄️ **Data enrichment** — join recall IDs against internal product SKUs for a live exposure report.

### Run it from the API

Trigger the Actor and get results in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/darknezz~canada-recalls-safety-alerts/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keyword":"battery","category":"Electronics","dateFrom":"2026-06-01"}'
```

**Python (Apify SDK):**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("darknezz~canada-recalls-safety-alerts").call(
    run_input={"keyword": "battery", "category": "Electronics", "dateFrom": "2026-06-01"},
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["recallId"], item["title"])
```

**Scheduling:** attach an Apify Schedule (daily or weekly) to keep a category watchlist topped up — the `dateFrom` filter plus a stored last-run date gives you an incremental feed of new recalls only.

### Limitations

- **HTML scraping** — the site has no public JSON API, so parsing is tied to the Drupal markup. The parser targets stable field machine-names; a site redesign would need a rebuild.
- **English only** — records are extracted from the `/en/` surface; French (`/fr/`) records are not covered.
- **Archived recalls excluded** — matching the reference actor; historical/archived records are not returned.
- **Politeness** — detail fetches are paced; very large result sets (500+ items) take proportionally longer.

### Pricing

Pay per event: a small fee for each recall extracted, plus Apify's standard platform events (actor start + dataset item). No subscription — you pay only for what you run.

### FAQ

**Do I need an API key or government login?** No — the recall database is fully public.

**Why do I get nothing for some keyword/category combos?** The category filter is a post-filter on the parsed category. If the search finds no recalls whose category matches, the dataset is empty — broaden the keyword or drop the category.

**How fresh is the data?** The site is updated continuously; `dateUpdated` is the page's last-modified date, so `dateFrom` gives you an incremental window.

**Can I get archived recalls?** No — the search surface excludes them, and the Actor follows that (as does the reference actor).

**Is scraping this legal?** The data is Canadian government open information published for public consumption; you are responsible for how you use it.

# Actor input Schema

## `keyword` (type: `string`):

Full-text search term (e.g. battery, croissant, vehicle). Leave empty to browse the latest recalls.

## `category` (type: `string`):

Product category filter (e.g. Electronics, Household items, Vehicles). Case-insensitive partial match against the recall category.

## `dateFrom` (type: `string`):

Only include recalls last updated on or after this date (YYYY-MM-DD).

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

Maximum number of recall records to extract.

## Actor input object example

```json
{
  "keyword": "battery",
  "category": "Electronics",
  "dateFrom": "2026-06-01",
  "maxItems": 50
}
```

# Actor output Schema

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

No description

## `recallId` (type: `string`):

No description

## `title` (type: `string`):

No description

## `dateUpdated` (type: `string`):

No description

## `recallClass` (type: `string`):

No description

## `category` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `affectedProducts` (type: `string`):

No description

## `companies` (type: `string`):

No description

## `hazard` (type: `string`):

No description

## `issue` (type: `string`):

No description

## `whatToDo` (type: `string`):

No description

## `archived` (type: `string`):

No description

## `status` (type: `string`):

No description

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

No description

## `sourceUrl` (type: `string`):

No description

## `dataSource` (type: `string`):

No description

## `rawSourceType` (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 = {
    "keyword": "battery",
    "category": "Electronics",
    "dateFrom": "2026-06-01"
};

// Run the Actor and wait for it to finish
const run = await client.actor("darknezz/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 = {
    "keyword": "battery",
    "category": "Electronics",
    "dateFrom": "2026-06-01",
}

# Run the Actor and wait for it to finish
run = client.actor("darknezz/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 '{
  "keyword": "battery",
  "category": "Electronics",
  "dateFrom": "2026-06-01"
}' |
apify call darknezz/canada-recalls-safety-alerts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,darknezz/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/5rKHdQtqHf5e2E30D/builds/uupl7KeJsYXMdJCEH/openapi.json
