← All experiments

Medicine prices across online pharmacies in Latin America and the Caribbean

No one compares what pharmacies charge for the same medicine across all 33 countries of the region. I built a reusable extractor that maps pharmacies in all 33 countries and reads the online catalogues of those that publish prices, and an analysis layer that turns the prices into a regional benchmark.

  • Data
  • Health
  • Automation
  • Tools

Updated5 Sep 2026

The problem

Medicines are a large part of what households pay out of pocket for health in Latin America and the Caribbean. I needed to know what a patient is charged at the pharmacy for the same medicine in different countries, and how many days of the lowest wage a standard treatment costs. That price is hard to see at scale.

What was out there

Most official price databases in the region record regulated ceilings or public procurement prices rather than what a private pharmacy charges, and the studies that compared pharmacy prices covered a handful of countries. The WHO and Health Action International survey method gives a standard basket and a way to measure affordability, but its international reference price series is too old for a 2026 benchmark. There is no comparison that covers the whole region at once. So I decided to read the prices that the big chains now publish in their own online catalogues.

What I built

I built two connected tools. The extractor keeps a census of commercial pharmacies in all 33 countries, checks which ones show prices online, and collects prices for a fixed basket of 16 essential medicines, each at one strength and form, wave after wave. Every price is a private retail sticker price, labelled as such; government price observatories are excluded by rule. The analysis layer reads only the extractor's versioned data package and produces the price comparisons, affordability in days of wage, sensitivity tests and a public report. A small local server exposes nine read-only tools for asking questions of the frozen data.

The idea grew out of an earlier scraper for five pharmacy websites in Panama, which taught me the basic problem: pharmacies list medicines under brand names, so every medicine needs a set of search terms, and every result needs checking.

Cover of the September 2026 report, titled Medicine prices in Latin America's online pharmacies: 24-country benchmark, with an illustration of a blister pack, syrup bottle, inhaler and ampoule and four headline figures: 24 countries with a priced study medicine, a 106.1x widest price gap for one medicine, 22.0 days of wage for one antibiotic course and 18 countries ranked on price.
The public September report: sixteen essential medicines priced from the online catalogues of 107 pharmacies.
Table of 17 countries with a medicine price index and rank under three lenses: market exchange rate, equal weight per pharmacy and purchasing power parity. Cells above 100 are shaded orange and below 100 green. Costa Rica ranks first at market rates with 245; Ecuador is last with 13. These are the fixed 17-country comparison, not the headline index.
The fixed 17-country comparison, whose indices differ slightly from the headline ones: the same prices rank differently by lens, and 14 of 17 countries change place between market rates and purchasing power parity.
Range plot for 18 countries showing days of the lowest daily wage needed for a standard treatment course, from the typical medicine (grey dot) to the least affordable one (blue dot). Argentina runs from 2.1 to 22 days for ceftriaxone; Ecuador from 0.1 to 1.5 days.
In most countries the typical course costs under a day of the lowest wage; the problem is the distance to the worst medicine.

Equipment

How I built it

  1. Fixed the basket: the 14 medicines of the WHO and Health Action International global core list, plus paracetamol 500 mg tablets and co-trimoxazole 800/160 mg tablets.
  2. Mapped every country's pharmacy market with background agents, one country at a time, and probed each pharmacy for whether it shows products and prices online. I marked sites with anti-bot walls as blocked and left them alone.
  3. Wrote a small declarative recipe per scrapeable site. One harvester covers VTEX stores; the rest go through backend APIs, rendered pages or structured product data. Codex built and repaired recipes in long goal runs, and a smoke test checks every recipe before each wave.
  4. Checked every scraped row: it must prove it belongs to its medicine, match the basket strength and form, and have a usable pack size before its price is divided per unit.
  5. Exported each wave as CSV files with a checksum manifest, then built the analysis as a separate project that reproduces the extractor's own figures before computing anything new.
  6. Had other models check the numbers: Agy re-fetched sample prices in the first wave, and Codex reviewed the analysis independently. I fixed the defects Codex confirmed, then wrote the report.

Results

  • The census lists 298 commercial pharmacies across 33 countries. A test run on 2026-09-04 checked 138 configured sources: 129 returned prices, 8 were reachable with no parsed items and 1 failed.
  • The frozen September wave holds 16,423 observations of 10,195 distinct products from 131 sources. 22 countries priced at least 8 of the 16 medicines, 8 priced some and 3 priced none.
  • After the matching checks, 3,521 listings from 107 pharmacy sources in 24 countries were usable. Of those, 18 countries priced enough medicines to be ranked.
  • At market exchange rates, Costa Rica has the highest price index (247.6, where 100 is the regional median) and Ecuador the lowest (15.0). Using purchasing power parity instead changes the rank of 14 of 17 comparable countries and puts Argentina first.
  • Leaving out salbutamol, whose packs mix units, the widest gap for one medicine is bisoprolol 5 mg: the most expensive country's median is 106.1 times the cheapest.
  • The least affordable treatment is a ceftriaxone 1 g injection course in Argentina: 22.0 days of the lowest daily wage.
  • The analysis reproduces all 280 of the extractor's reference cells within 0.0027 percent.

The full results are in the September report. The July methodology report on the first two waves is also public.

What I learned

Search results need checking. Pharmacy search endpoints fill the page with unrelated products, so the first wave's 13,448 raw rows came down to 4,472 clean observations once re-run duplicates were removed and every row had to prove its medicine. Without that check the medians would have meant nothing.

A product name does not tell you who the originator is. The July report showed Brazil's branded ceftriaxone at 33 times the generic. Later I removed every originator premium, because originator status is a country-specific regulatory fact that catalogue text cannot establish. The September report compares named products with products sold under the generic name only, within the same country.

The currency lens decides the ranking. Market exchange rates and purchasing power parity give different league tables for the same local prices, so the report shows both. It also shows days of wage, which does not depend on the exchange rate at all.

Lab notes

  1. I froze the third wave at 16,423 observations of 10,195 products from 131 sources, dropped the old international reference prices and any originator premium, and published the September report on GitHub Pages.

  2. I rebuilt the census from scratch, from 161 to 298 pharmacies, and started a separate analysis project that reads only the exported data package. Codex worked through 36 batches of scraper recipes for 179 assigned sources and left 62 working recipes.

  3. I added a relevance filter after finding that pharmacy search boxes pad results with unrelated products, which cut the first wave to 4,472 clean observations. Then I published a preliminary methodology report on the first two waves.

  4. I started the regional version, with a harvester for VTEX (the e-commerce platform behind many of the big chains) and a census of all 33 countries run by one background agent per country. The first wave stored 13,448 raw price rows.

  5. I ran a first scraper in Panama: 116 medicines from Panama's CABAMED essential medicines list, 386 search terms and five pharmacy websites, which returned 1,425 price rows for a Tableau dashboard.

© 2026 Johnattan García-Ruiz Last updated