The client was a patient-access platform. Their product did one thing: help a patient with a prescription in hand find the cheapest place to fill it, nearby, today. Simple promise. Brutal execution problem.
Because the retail pharmacy market in the United States has a property that almost no other consumer market has — the price of the identical product, at two pharmacies four miles apart, can differ by 400%. Not 4%. Four hundred. The same 30-day supply of the same generic, same strength, same manufacturer, can be $12 at one counter and $58 at another in the next ZIP code. And neither pharmacy is doing anything wrong. That is simply how cash pricing works when it sits downstream of PBM contracts, wholesaler agreements, discount-card programs and store-level discretion.
Add a second variable — availability — and it gets worse. A cheap price at a pharmacy that is out of stock is not a price. It is a wasted trip for a patient who may already be unwell, uninsured, or without a car.
The client's engineering team could build the app. What they could not build, and could not buy off the shelf, was the underlying truth: what does this drug actually cost, and is it actually in stock, at every pharmacy in this ZIP code, right now?
That is the problem Actowiz Solutions was brought in to solve. This is how it was built — the data model, the ZIP-level collection design, the matching layer, the sample data, the compliance boundaries that mattered more here than in any commercial project, and what the numbers looked like ninety days in.
Anyone who has built retail price intelligence assumes the pharmacy version is the same job with different SKUs. It is not. Five things break the standard playbook.
The program was designed around six entities.
| Entity | Key Fields | Why It Exists |
|---|---|---|
| Drug | NDC, generic name, brand name, strength, dosage form, route, manufacturer, therapeutic class, generic/brand flag | The canonical product identity |
| Package | Package size, unit count, days-supply basis, quantity dispensed | Price is meaningless without quantity |
| Pharmacy location | Location ID, chain/independent flag, banner, street address, ZIP, county, lat/long, hours, 24-hour flag | The unit of geography that matters |
| Price observation | Price type (cash / discount-card / membership), price, price per unit, price per day-supply, capture timestamp | The measurement |
| Availability observation | In stock / limited / out of stock / special order, last-updated signal, backorder flag, substitute offered | The other half of the answer |
| Access context | Distance from ZIP centroid, drive time, delivery available, pharmacy desert flag | Whether the patient can actually get there |
Two fields in that model carried disproportionate weight.
Price per day-supply. Not price. A $28 bottle of 90 tablets and a $14 bottle of 30 tablets are not a $14 difference — they are the same price per day. Every price observation was normalized to price per unit and price per 30-day supply before it was allowed anywhere near a comparison. Skipping this normalization is the single most common way pharmacy price comparisons produce confidently wrong answers.
Price type. Every price carried an explicit type label. A cash price and a discount-card price were never allowed to appear in the same column without that label attached. Blending them silently would have produced a dataset that looked cheaper than reality for some pharmacies and more expensive for others — exactly the kind of error that erodes patient trust the first time someone shows up at the counter and the number doesn't match.
The core design decision was that ZIP code is the unit of collection, not the unit of aggregation.
Most price programs collect nationally and then slice by geography. That produces geographic averages with large gaps — fine for a market report, useless for a patient standing in a specific ZIP with a specific prescription.
The client's grid was built the other way round:
That last point matters. Price and availability captured at different times produce a record that is internally inconsistent — a Tuesday price paired with a Thursday stock status. Every observation in this system carried both, from the same capture, with the same timestamp.
Collection was rendering-aware, rate-limited, and restricted strictly to publicly displayed pricing and availability information — the same information any member of the public can see when they look up a drug price on a pharmacy's public site or a public price-transparency tool. No authenticated sessions. No patient data. No insurance-specific pricing that would require impersonating a member. That boundary was not negotiable, and it is discussed in full below.
A single normalized ZIP-level observation:
{
"capture_ts": "2026-07-13T07:12:03-05:00",
"query_zip": "60614",
"drug": {
"ndc": "00093-1049-01",
"generic_name": "Atorvastatin Calcium",
"brand_reference": "Lipitor",
"strength": "20 mg",
"dosage_form": "tablet",
"route": "oral",
"manufacturer": "Teva",
"therapeutic_class": "HMG-CoA Reductase Inhibitor",
"is_generic": true
},
"package": {
"quantity_dispensed": 30,
"days_supply": 30
},
"pharmacy": {
"location_id": "PH-IL-004417",
"banner": "Regional Chain B",
"type": "chain",
"address_zip": "60618",
"county": "Cook",
"lat": 41.9463,
"lng": -87.7031,
"distance_from_query_zip_mi": 2.4,
"drive_time_min": 9,
"open_24h": false,
"delivery_available": true
},
"prices": [
{
"price_type": "cash",
"price_usd": 41.99,
"price_per_unit_usd": 1.40,
"price_per_30d_usd": 41.99
},
{
"price_type": "discount_card",
"price_usd": 9.60,
"price_per_unit_usd": 0.32,
"price_per_30d_usd": 9.60,
"program": "public discount program"
}
],
"availability": {
"status": "in_stock",
"signal_freshness_hours": 3,
"backorder_flag": false,
"substitute_offered": null
},
"derived": {
"cheapest_in_zip_radius_30d_usd": 8.20,
"gap_to_cheapest_pct": 17.1,
"zip_median_30d_usd": 24.50,
"zip_price_spread_pct": 412.0,
"verdict": "NOT_CHEAPEST_BUT_AVAILABLE"
}
}
Look at zip_price_spread_pct: 412%. That is the ratio between the cheapest and most expensive available option for the same drug, same strength, same quantity, within a few miles of one ZIP code. It is not an outlier record. It is the ordinary state of the market, and it is the entire reason the client's product exists.
Note also the two price rows. The cash price is $41.99. The public discount-card price at the same counter is $9.60. Same pharmacy, same drug, same day. A dataset that captured only the first number would have been technically accurate and practically useless.
Aggregate those records and you get the cut the client's app actually renders — every pharmacy within reach of one ZIP, for one prescription:
| Pharmacy | Type | ZIP | Distance | Cash (30d) | Discount (30d) | Availability | Best Price |
|---|---|---|---|---|---|---|---|
| National Chain A | Chain | 60614 | 0.8 mi | $52.40 | $14.20 | In stock | $14.20 |
| Regional Chain B | Chain | 60618 | 2.4 mi | $41.99 | $9.60 | In stock | $9.60 |
| Independent Pharmacy C | Independent | 60614 | 1.1 mi | $38.00 | $12.00 | In stock | $12.00 |
| Grocery Pharmacy D | Chain | 60647 | 3.2 mi | $33.50 | $8.20 | Out of stock | — |
| Big-Box Pharmacy E | Chain | 60622 | 4.1 mi | $29.99 | $8.40 | In stock | $8.40 |
| Independent Pharmacy F | Independent | 60618 | 2.9 mi | $61.00 | $61.00 | Limited | $61.00 |
Three findings a patient could act on immediately, and none of them are visible without the joined price-plus-availability view:
The cheapest listed price is unbuyable. Grocery Pharmacy D at $8.20 is out of stock. A price comparison tool without availability data sends the patient there, and the patient — possibly without a car, possibly missing work — arrives to nothing. The real floor is $8.40 at Big-Box Pharmacy E, 4.1 miles away.
The spread is 7x. $8.40 to $61.00 for the identical prescription within a 4-mile radius. Independent Pharmacy F offers no discount-card price at all, so its cash price is its price.
Distance versus savings is a real trade-off. The closest pharmacy costs $14.20. Driving 3.3 miles further saves $5.80 — a decision only the patient can make, but one they can only make if someone shows them the table.
Pharmacy stock-out monitoring was, on the client's own analysis, the single highest-value component of the program — and the one they had originally scoped as "phase two."
Price data is table stakes. A dozen tools show prices. What almost nobody shows is whether the price is fillable, and that is the thing that determines whether the patient's day ends with medicine in hand.
The availability layer captured:
That last metric turned out to be the finding that changed the client's roadmap. Aggregated across a ZIP and tracked daily, the stock-out rate produced a pharmacy access map — an evidence-based picture of which ZIPs could reliably fill common prescriptions and which could not.
The pattern that emerged was uncomfortable and entirely unsurprising: stock-out rates were consistently higher in lower-income ZIPs, and the ZIPs with the fewest pharmacies within reach were also the ZIPs where the remaining pharmacies were most likely to be out of stock. The places with the least access had the least reliable access.
That is not a pricing insight. It is a health-equity insight, produced as a by-product of a pricing system, and it became the basis of the client's outreach and partnership strategy.
Everything above depends on knowing that the drug listed on Pharmacy A's site and the drug listed on Pharmacy B's site are the same drug. The cascade used:
Tier 1 — NDC match. Where the National Drug Code is exposed, the match is exact. This is the gold standard and it is used wherever available.
Tier 2 — Composition match. Generic name + strength + dosage form + route + quantity. This resolves the very common case where two pharmacies stock the same generic from different manufacturers — clinically equivalent, different NDC, and correctly treated as the same option for comparison purposes, with the manufacturer difference disclosed rather than hidden.
Tier 3 — Brand-to-generic mapping. Linking a brand-name listing to its generic equivalents, so a patient searching a brand name sees the generic options that a pharmacist would offer them anyway.
Tier 4 — Human review queue. Anything below the confidence threshold. In a healthcare context this queue is not optional, and the threshold is set deliberately high. A bad match in retail costs a customer a small annoyance. A bad match here could put a patient in front of the wrong medication.
Every match carried a confidence score, every score travelled with the record, and anything below threshold was never surfaced as a comparison — it was withheld. In this domain, showing nothing is an acceptable outcome. Showing something wrong is not.
This section is not boilerplate. In healthcare it is the architecture.
| Metric | Before | After |
|---|---|---|
| ZIP codes with pharmacy-level price coverage | 40 (manual) | 3,100+ |
| Drugs tracked | ~60 | ~800 (majority of dispensed volume) |
| Price types captured | Cash only | Cash + discount programs, labelled separately |
| Availability data | None | Every observation, same timestamp as price |
| Median savings surfaced per prescription | Not measured | $31 per fill on tracked generics |
| Wasted-trip rate (user-reported, price found but drug unavailable) | 22% | Under 4% |
| Match precision (audited) | n/a | 98.1% |
| Time to detect a ZIP-level stock-out cascade | Never detected | Under 24 hours |
The wasted-trip number is the one the client's product team cared about most, and it is the one that would never have moved without the availability layer. A price comparison tool that gets someone to a closed door has not helped them. It has cost them a morning.
The $31 median saving per fill is what the program was ostensibly built for. The 22% → 4% wasted-trip reduction is what made patients keep using it.
Because ZIP is the geography the patient actually lives in. Within-chain variation between stores is frequently larger than between-chain variation, and state-level averages smooth away exactly the differences that determine what a person pays. A national average price for a generic is a statistic. A ZIP-level price table is a decision.
Because they can differ by 4x at the same counter on the same day, and a patient needs to know which number applies to them. Blending them produces a figure that is wrong for everyone. Every price in the dataset carries an explicit type label.
It is reliable enough to be far better than nothing — which is what the alternative is — but only if freshness is exposed rather than hidden. Every stock signal carries its age. A three-hour-old "in stock" is treated very differently from a three-day-old one, and the patient sees which they are getting.
No. Not at any point, in any form. The system observes publicly displayed prices and availability for products. It never touches PHI, prescription records, insurance member data or personal identifiers, and there is no architectural path by which it could.
Collecting publicly displayed prices and availability for comparison and research is well-established practice, and price transparency in healthcare is actively encouraged by policy. The requirements are strict and were followed throughout: public data only, no patient data, no authenticated or member-specific pricing, non-disruptive rate-limited collection, and clear communication that the output is price information rather than medical advice.
Cross-sectional value — what a drug costs across the pharmacies near one ZIP today — is available from the first collection cycle. The time-series value, including stock-out patterns, shortage propagation and access mapping, needs 60 to 90 days of consistent collection.
The client set out to answer a narrow question: where is this prescription cheapest near me? The data answered it — and then answered several questions nobody had thought to ask.
That the spread for an identical generic within a few miles is routinely several hundred percent. That the cheapest listed price is frequently unbuyable, which makes any price-only tool actively harmful to the people relying on it. And that stock-out rates cluster in exactly the ZIP codes least able to absorb them, turning a pricing dataset into an access map that no facility count would ever have produced.
Actowiz Solutions built and now operates the data layer behind that product — ZIP-level collection, NDC-grade matching, price-type separation, availability captured on every observation, and a compliance perimeter designed for healthcare rather than retrofitted onto it.
If you are building anything that asks a patient to act on a price, the price alone is not enough. It never was.
You can also reach us for all your mobile app scraping, data collection, web scraping , and instant data scraper service requirements!
Our web scraping expertise is relied on by 4,000+ global enterprises including Zomato, Tata Consumer, Subway, and Expedia — helping them turn web data into growth.
Watch how businesses like yours are using Actowiz data to drive growth.
From Zomato to Expedia — see why global leaders trust us with their data.
Backed by automation, data volume, and enterprise-grade scale — we help businesses from startups to Fortune 500s extract competitive insights across the USA, UK, UAE, and beyond.
We partner with agencies, system integrators, and technology platforms to deliver end-to-end solutions across the retail and digital shelf ecosystem.
Wegmans Grocery Product Data Extraction helps retailers track prices, products, availability, and assortment changes to improve grocery market intelligence and decisions.
Track Scrape Ready-to-Cook Cut Veg Product Data from Blinkit TN to monitor prices, availability, SKUs, and trends for smarter retail insights.
Brazil Car Rental Pricing Intelligence Report 2026 reveals rental price trends, market shifts, competitor rates, and opportunities for smarter pricing.
Whether you're a startup or a Fortune 500 — we have the right plan for your data needs.