Article type: How-to guide (one task: check recent EU and US recalls for your keywords)

Prerequisites: Python 3 with requests. No API key is needed for Safety Gate, CPSC or openFDA. An Apify account only if you use the shortcut in section 4.

Tested on: 31 October 2026 (the run in section 3); the Python snippet was re-run on 1 November 2026

If you sell electronics in both the EU and the US, a recall can show up in three places: EU Safety Gate, the US CPSC and (for food, drugs and devices) the FDA. All three are public and need no key, but each has its own format. Here's how to read each one, then one schema for all three.

1. The three sources

  • CPSC: https://www.saferproducts.gov/RestWebServices/Recall?format=json&RecallDateStart=2026-10-17&ProductName=power%20bank
  • openFDA (food shown; also drug and device): https://api.fda.gov/food/enforcement.json?search=report_date:[20261017+TO+20261031]&limit=100 (With curl, add -g so the square brackets aren't read as a pattern.)
  • EU Safety Gate: the European Commission publishes weekly reports as XML downloads. There's no keyword search, so you fetch the recent weekly reports and filter them yourself.

Things that catch people out:

  • No results is normal. openFDA adds enforcement reports weekly, so the last few days are often empty. Treat a 404 "No matches found" from openFDA as zero rows, not an error.
  • Barcodes don't line up. A 12-digit UPC and the 13-digit EAN with a leading 0 are the same product. Compare digits after stripping leading zeros.
  • Risk wording differs. Safety Gate says "Serious", CPSC mostly doesn't grade, FDA uses Class I/II/III. Keep the original wording next to any scale you map it to.

2. A minimal CPSC check in Python

import requests url = "https://www.saferproducts.gov/RestWebServices/Recall" for kw in ["charger", "power bank"]: r = requests.get(url, params={"format": "json", "RecallDateStart": "2026-10-17", "ProductName": kw}, headers={"User-Agent": "recall-check/1.0 (you@example.com)"}, timeout=30) r.raise_for_status() # saferproducts.gov refuses the default python-requests User-Agent  for rec in r.json(): print(rec["RecallNumber"], rec["RecallDate"][:10], rec["Title"]) 

3. A real run, 31 October 2026

Last 14 days, keywords "charger" and "power bank", at most 3 per source:

Source ID Date Product Brand Risk
EU Safety Gate SR/03027/26 2026-10-30 LED Football (with charger) Coolstuff serious
EU Safety Gate SR/03069/26 2026-10-30 Power Supply vhbw serious
EU Safety Gate SR/03044/26 2026-10-30 Dual USB-C Charger X-start serious
US CPSC 27056 2026-10-29 HAIARA power banks unknown
US FDA (food, drug, device) no matches 18-31 Oct

The FDA row is empty because none of the 71 FDA enforcement reports dated in that window (8 food, 5 drug, 58 device) mentioned a charger or power bank. An empty source is a normal answer, not an error.

4. The shortcut (we built this)

We built an Apify Actor, Product Recall API, that reads all three feeds into one schema (riskLevel plus the source's own wording), matches barcodes across UPC/EAN, gives a free no_matches row per empty source, and has a monitor mode that returns only recalls you haven't had before. It's independent and not affiliated with the European Commission, CPSC or FDA.

{ "publishedWithinDays": 14, "keywords": ["charger", "power bank"], "maxResultsPerSource": 3 } 

Pay per event: base price $0.002 per recall row returned, plus $0.00005 per run per GB of memory for the Actor start (one event at the default 256 MB) and $0.01 per monitor run that returns new recalls. Higher Apify plans pay less. Status rows are free.

Product Recall API on Apify

Your Evenings