← Back to the databaseMethod

How this was built

Sources, the exact query, what counts as a refusal and the four things this database cannot tell you.

Where the data comes from

Two FDA sources, both public:

Every word of charge language on this site is quoted verbatim from that file. Nothing was paraphrased or shortened. The charges are what FDA writes on the Notice of FDA Action.

The query

The endpoint caps a response at 5,000 rows, so the fetcher walks the record month by month from January 2002 to the present, paging within each month until a short page comes back, and de-duplicating on ShipmentID. That produced 525,457 refusals dated January 1, 2002 through August 2026. The script stops only after eighteen consecutive empty months and exits non-zero if it fetches nothing at all, so a silent failure cannot be published as an empty database.

What a refusal is, and is not

A refusal is FDA's final decision that a detained shipment appears to violate the Food, Drug, and Cosmetic Act. The shipment must be exported or destroyed under Customs supervision within 90 days. It is an administrative finding about the appearance of a violation. It is not a court judgment, not a finding of fact about the firm and not proof that anyone was harmed. Firms may contest refusals, and a refusal can follow a paperwork failure as easily as a filthy one.

One shipment can carry several charges, so charge counts sum to more than the number of shipments. The unit of a charge count is charge-on-a-shipment, not shipment.

Counting rule for shipments

Each row returned by FDA is one line on a refused entry, identified by a ShipmentID like 1FX-5639990-0/20002/1. A single physical container can therefore appear as several rows when it holds several refused product lines. This site counts rows, which is how FDA's own dashboard counts them. Read "525,457 shipments refused" as "525,457 refused entry lines."

Charge codes without published text

279 distinct charge codes appear in the refusal record. 22 of them are not present in FDA's published crosswalk, and those are shown here as bare code numbers labelled "no published text." They are a small share of all charge hits. If FDA updates the crosswalk, re-running the build will fill them in.

Why only recent refusals are searchable line by line

The full 525,457-record history is used for every count, chart and ranking on the site. Shipping all of it as a browsable file would mean a download in the tens of megabytes, so the line-by-line browser covers refusals since September 2025 — 39,386 of them. Country, firm, charge and year figures are computed across the entire quarter-century, not the recent slice.

What this cannot tell you

Rebuilding it

Two scripts in this repository: fetch_fda.py pages the API month by month and writes one JSON object per line; build_fda.py joins the charge crosswalk, aggregates and writes the files in data/. Set FDA_USER and FDA_KEY in the environment. FDA updates the underlying report monthly.

Built with AI assistance. The fetching, aggregation and this page were produced with Claude. Figures are computed from FDA's API rather than transcribed, but check FDA's dashboard before publishing any number from here.

← Back to the database