Given a prescription drug (name, optional dosage/form/quantity) and a US ZIP, return GoodRx's per-pharmacy consumer price comparison as structured JSON — coupon price, list price, savings %, Gold-tier price, store name + address + distance, the printable coupon's Bin/PCN/Group/Member-ID, and drug monograph metadata. Honors the full filter surface (form, dosage, quantity, radius, pharmacy chain, sort, pickup vs. mail-order). Read-only.
Works with
AI-first code editor with Composer
Before installing skills in Cursor, ensure your development environment meets these requirements:
node --versioncompare-drug-pricesExecute the skills CLI command in your project's root directory to begin installation:
Fetches compare-drug-prices from goodrx.com/compare-drug-prices-c8d87y and configures it for Cursor.
The CLI shows a list of agents. Use arrow keys and space to select Cursor:
Confirm successful installation by checking the skill directory location:
Restart Cursor to activate compare-drug-prices. Access via /compare-drug-prices in your agent's command palette.
We perform automated surface-level scans (Gen AI Scanner, Socket, Snyk) during installation. These checks detect common vulnerabilities but do not guarantee complete security. Always review skill source code and verify the publisher's reputation before production use.
Skills execute code in your environment. Always review source, verify the publisher, and test in isolation before production.
Submit your Claude Code skill and start earning
Automate repetitive workflows and reduce manual effort
Example
Generate reports, summarize documents, draft communications
Save 3-5 hours per week on routine tasks
Learn new skills, understand complex topics, get expert guidance
Example
Explain concepts, provide examples, suggest learning resources
Accelerate learning and skill development by 2x
Enhance output quality through reviews, suggestions, and refinements
Example
Review drafts, suggest improvements, catch errors
Improve work quality by 30-40% with less effort
0
total installs
0
this week
0
upvotes
Run in your terminal
0
installs
0
this week
—
stars
| name | compare-drug-prices |
| title | GoodRx Drug Price Comparison |
| description | >- Given a prescription drug (name, optional dosage/form/quantity) and a US ZIP, return GoodRx's per-pharmacy consumer price comparison as structured JSON — coupon price, list price, savings %, Gold-tier price, store name + address + distance, the printable coupon's Bin/PCN/Group/Member-ID, and drug monograph metadata. Honors the full filter surface (form, dosage, quantity, radius, pharmacy chain, sort, pickup vs. mail-order). Read-only. |
| website | goodrx.com |
| category | healthcare |
| tags | - healthcare - pharmacy - prescription - price-comparison - perimeterx - read-only |
| source | 'browserbase: agent-runtime 2026-05-18' |
| updated | '2026-05-18' |
| recommended_method | browser |
| alternative_methods | [] |
| verified | true |
| proxies | true |
Given a prescription drug (name or full GoodRx URL, plus optional dosage / form / quantity) and a US location (ZIP, defaulting to the session's geo-IP), return GoodRx's consumer pharmacy price comparison as structured JSON: per-pharmacy list price, GoodRx coupon price, savings percent, Gold-tier price when surfaced, the printable coupon reference, store-name + address + distance, and the drug's monograph metadata (canonical slug, active ingredient, strengths, forms, drug class, FDA status). Read-only — never click "Get Free Coupon" submit, "Sign Up for Gold", "Send to Pharmacy", "Sign In", or any control that triggers an email/SMS/insurance/transfer flow.
<drug> at pharmacies near <ZIP>?""Adderall" → Adderall XR vs. Adderall IR; "insulin glargine" → Lantus, Toujeo, Basaglar, Semglee) via the in-page autocomplete before pricing.The optimal path is scripted browsing through a Browserbase remote session with stealth + residential proxy. There is no public consumer API — api.goodrx.com exists but is partner-only and returns 401 {"error":{"type":"authentication_error","detail":"missing api key","code":"unauthorized"}} to unauthenticated requests. The page itself is a Next.js + React Server Components app served behind Fastly Varnish; the prices are embedded in the streamed RSC payload on initial load and then reactively updated when filter controls change.
SID=$(browse cloud sessions create --keep-alive --verified --proxies | node -e 'let s="";process.stdin.on("data",c=>s+=c);process.stdin.on("end",()=>console.log(JSON.parse(s).id))')
export BROWSE_SESSION="$SID"
Both --verified (stealth fingerprint) and --proxies (US residential IP) are required. GoodRx fronts every response with the PerimeterX (HUMAN Security) bot stack — confirmed by the _pxhd cookie set on every response and CSP connect-src whitelisting *.perimeterx.net *.pxchk.net *.px-cdn.net *.px-cloud.net *.px-client.net. A bare (non-stealth, non-proxy) session reliably gets soft-blocked: the page loads but pricing tiles fail to hydrate, replaced by a "Checking your browser…" interstitial. Geo-IP location ranges that obviously aren't residential (datacenter ASNs, IPv6 cloud blocks) get hard-403'd at the Fastly edge before reaching the app.
The proxy IP's geo also seeds the default ZIP — GoodRx fills location from the request IP (X-Location-State response header reports the state Fastly detected), so for the few skills that intentionally want geo-IP defaults, picking a proxy in the target state is faster than typing the ZIP in.
The canonical URL form is https://www.goodrx.com/{drug-slug} — for example /lipitor, /atorvastatin, /adderall-xr, /albuterol, /insulin-glargine-pen. Slug rules:
Adderall XR → adderall-xr, Insulin Glargine Pen → insulin-glargine-pen)./lipitor (brand); if they said "atorvastatin" → use /atorvastatin (generic). Don't normalize between them — the user-facing pricing card differs.https://www.goodrx.com/, click the search input (top-of-page), type the term, wait ~400 ms for the autocomplete dropdown, and read the first ≤ 5 suggestions (each is an anchor with href="/<slug>"). Pick the suggestion whose visible label exactly matches the user's input. If two top suggestions both match (e.g. Adderall vs. Adderall XR), return success: false, reason: "ambiguous_name", candidates: [...] — do not silently pick one. The autocomplete API itself is not exposed as a JSON endpoint; /auto-complete?term=…, /api/autocomplete?q=…, /ajax/search?term=…, /mobile-api/* all return 404 from anonymous clients. Only the in-page typeahead works.browse open "https://www.goodrx.com/{slug}?form={form}&dosage={dosage}&quantity={qty}&label_override={slug}" --remote
GoodRx accepts these as URL params and pre-applies the selection (the values then appear in the form/dosage/quantity dropdowns on the right rail):
| URL param | UI control | Notes |
|---|---|---|
form | "Form" dropdown | Slugified — tablet, capsule, extended-release-tablet, oral-solution, suspension, inhaler, injection-pen, vial, cream, ointment, patch, transdermal-patch |
dosage | "Dosage" dropdown | Slugified mg/mcg/ml — 10mg, 20mg, 1mg-ml, 100mcg, 0-5mg. No space, no slash. |
quantity | "Quantity" stepper | Integer — 30, 60, 90, 1 (for inhaler / pen) |
label_override | (none — for analytics, no UI effect) | Set equal to the slug; mirrors how the site's own links seed it |
sort_type | "Sort by" dropdown | lowest_price (default), distance, pharmacy_name |
deliveryType | "Pickup / Mail order" tabs | pickup (default), mail_order |
prices_first=1 | layout hint | Skip drug-info hero and scroll prices into view immediately |
insurance | insurance hint flag | Triggers the insurance-coverage interstitial — leave unset for cash/coupon pricing |
radius | Radius dropdown | Integer miles: 5, 10, 15, 25 (also accepts 1, 50, 100) |
pharmacy / pharmacy_id | Pharmacy filter pill | Numeric internal pharmacy id; not stable across releases — discover by clicking the chain in the UI rather than hardcoding |
zip / location | ZIP entry | 5-digit US ZIP. If absent, the page pulls the ZIP from session cookies (set on first /change-location call) or falls back to geo-IP |
Source of this list: The robots.txt at https://www.goodrx.com/robots.txt explicitly disallows crawler-indexing of /*?sponsorship*, /*?prices_first*, /*?insurance*, /*?sort_type*, /*?deliveryType*, /*?offerId*, /*?*client=* — implicitly confirming each as a real URL-param. The form, dosage, quantity, radius, pharmacy*, zip/location params are not in robots but are the canonical UI-form names (visible in the form <select name="…"> attributes when you snapshot the page).
The ZIP control is in the top-right "Set your location" widget. The simplest path:
browse open "https://www.goodrx.com/change-location?zip={ZIP}" --remote
# Then re-open the drug URL — the location cookie now sticks for the session
browse open "https://www.goodrx.com/{slug}?…" --remote
/change-location is disallowed in robots.txt — that means "don't index", not "don't fetch", and the endpoint does exist and does set the cookie. Do not POST to /clear-location or /reset-location (also disallowed) unless you actually need to clear state — they wipe the location cookie and cause the next page load to fall back to geo-IP.
browse snapshot --remote > /tmp/snap.json
browse get markdown body --remote > /tmp/page.md
The pricing-tile section is rendered as a vertically-stacked list of cards under the heading "{Drug name} Coupons & Discounts" or the price-comparison heading "Prices and Coupons for {N} {form} of {drug}". Each card has, in order:
"{NN.N} mi · {Store name} · {Street}, {City}, {ST} {ZIP}". The "Store" sublink is a hyperlink to the store-detail page on GoodRx.$4.00). This is the headline price.~~$24.32 retail~~. Compute savings: 1 - coupon/list.$3.00 with Gold. Not all pharmacies; varies by drug./coupon/{slug}?…&pharmacy={pharmacy_id}&dosage=…&quantity=… and renders a printable card containing the public Bin/PCN/Group/Member-ID — these four fields are the coupon. The page also exposes a "Print" CTA which calls window.print() — also read-only.<a href="/{slug}?…&pharmacy={pharmacy_id}…">View {chain} prices</a> on each card. Capture the full href as the pharmacy's GoodRx URL.The "About {drug}" / "How {drug} works" section is below the price tiles. Look for these labelled rows in the right-rail / sidebar:
<h1>.<select> options) give the complete enumerations.<a href="/{slug}/what-is"> or <a href="/{slug}/side-effects">.If the user asked for a specific subset (e.g. "only Costco and Walmart"), click the "Filter pharmacies" button at the top of the prices list. The modal contains chain checkboxes. Multi-select then submit. The resulting URL has &pharmacy_ids={comma-separated-ids} — capture the IDs from the URL for later direct use, but do not hardcode them across runs; GoodRx renumbers pharmacy IDs occasionally.
Do not click these (each triggers a mutation/transactional flow):
/price-alert — disallowed in robots)_pxhd cookie set on every response, and CSP connect-src listing *.perimeterx.net *.pxchk.net *.px-cdn.net *.px-cloud.net *.px-client.net. The task brief speculates Datadome/Akamai — this is wrong on the public consumer surface. Stealth fingerprint + residential proxy is still the right answer; the which-vendor note matters mostly for debugging unexpected blocks ("Checking your browser…" → PerimeterX captcha challenge, not Akamai).api.goodrx.com/v1/drugs/{slug} is real but partner-only. Verified 2026-05-18 with browse cloud fetch: returns 401 {"error":{"type":"authentication_error","detail":"missing api key","code":"unauthorized"}} to anonymous clients. The auth scheme is an Authorization: Bearer token issued under a partner / B2B agreement (per their public partner-API docs). Do not waste time trying to mint a token, sniff one from the consumer page, or replay browser auth headers — the consumer site uses a different (cookie-based) auth path and the bearer token is not present in client-side bundles.browse cloud fetch https://www.goodrx.com/{slug} returns 502 The response body exceeded the maximum allowed size of 1MB. Drug pages routinely run 2-5 MB rendered. Do not try to scrape via Fetch — use a full browser session. (/robots.txt and /coupon/{slug} are small enough to fetch directly; the canonical drug page is not.)X-Location-State response header tells you which state Fastly's geolocator pinned the request to. A --proxies session may land in any US state; if you need a specific state for accurate pharmacy results, set the ZIP explicitly via /change-location?zip=… instead of trusting the IP.connect.usw2.browserbase.com host is unreachable from some restricted sandboxes — if browse open errors with ENOTFOUND connect.usw2.browserbase.com, your sandbox network policy is blocking the session-WebSocket path even though api.browserbase.com is allowed. The skill in that case can only be exercised end-to-end from a non-restricted environment (a developer machine or a Vercel sandbox with broader egress). Skill author 2026-05-18 hit this and could only validate the reconnaissance layer (CSP, robots.txt, partner-API auth shape, URL-param surface from robots disallow list); the price-tile selectors in the workflow above are inferred from prior GoodRx skill builds + the public DOM, not freshly re-verified./lipitor and /atorvastatin cross-link, the headline price card differs: /lipitor shows the brand price prominently and the generic in a "Save more with the generic" rail; /atorvastatin shows the generic price prominently and the brand in a "Looking for the brand?" rail. Always pick the slug that matches what the user typed.extended-release-tablet, oral-solution, injection-pen, transdermal-patch. "ER tablet" → extended-release-tablet (not er-tablet). When in doubt, snapshot the page and read the <select name="form"> <option value="…"> values verbatim.mg/ml becomes mg-ml, decimals become hyphens. E.g. 0.5mg → 0-5mg, 1mg/ml → 1mg-ml, 100mcg/actuation → 100mcg-actuation. Spaces, slashes, and dots all become hyphens.label_override={slug} is GoodRx's own analytics-correlation param — harmless but mirrors how their own pharmacy deep-links set it. Including it makes your traffic look more like a normal click-through.quantity=1000 silently clamps to the cap; the returned prices are for the clamped quantity, not the requested one. Always read back the quantity from the rendered page rather than trusting the request.deliveryType=pickup then deliveryType=mail_order, or click the tab once and re-snapshot. Capture each tab as a distinct sub-list in your output.costplusdrugs.com/{slug-like-path} (not GoodRx-internal). Capture the URL but don't follow it — Cost Plus is a separate skill.Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch. The page is Next.js with React Server Components. If you send a request with RSC: 1 header (only possible via a browser session driving an XHR, not via browse cloud fetch which can't set custom headers), you'll get back the RSC streaming payload — much smaller than the full HTML but harder to parse. Stick with the rendered HTML / accessibility tree unless you're optimizing for cost on a high-volume run.grx_unique_id (visitor id), optimizelyEndUserId (A/B test bucket), grx_visit_start (epoch), grx_sa=false (signed-in flag — false for anon), fastly_unique_id, _pxhd (PerimeterX device fingerprint). The session-state cookie that matters for pricing is the one /change-location?zip=… sets — without it, every page-load falls back to geo-IP./static, /discount-card-sign-up, /ajax, /clear-location, /change-location, /reset-location (state mutations)/price-alert (form submit)/coupon (printable-coupon endpoint; takes per-pharmacy params)/doctors/price-guide, /browse (provider tools)/my-rx (signed-in only)/widget, /iframe, /mobile-api, /webview (partner embeds — all 404 from anon)/auth0/* (auth flow)/good-data/* (internal data API — 404 from anon)/transfer/drug/*, /send-ahead/drug/* (prescription transfer flows — explicitly avoid)/compounded-drugs/* (separate compounded-drug surface; not standard pricing)https://www.goodrx.com/{slug} will sometimes render a "Set your location" gate before showing prices. Submit a ZIP via /change-location?zip=… first, then re-load — no gate.{
"query": {
"drug_input": "atorvastatin 20mg, 30 tablets",
"resolved_slug": "atorvastatin",
"form": "tablet",
"dosage": "20mg",
"quantity": 30,
"zip": "94110",
"radius_miles": 10,
"delivery_type": "pickup",
"sort": "lowest_price",
"pharmacy_filter": null,
"generic_vs_brand_preference": "generic"
},
"drug": {
"canonical_name": "Atorvastatin (Generic Lipitor)",
"slug": "atorvastatin",
"classification": "generic",
"brand_counterpart_slug": "lipitor",
"active_ingredients": ["atorvastatin calcium"],
"available_strengths": ["10mg", "20mg", "40mg", "80mg"],
"available_forms": ["tablet"],
"drug_class": "Statins / HMG-CoA reductase inhibitors",
"typical_use": "Lowers LDL cholesterol; reduces risk of cardiovascular events.",
"fda_approval": { "approved": true, "year": 1996 },
"safety_link": "https://www.goodrx.com/atorvastatin/what-is",
"prices_updated_at": "2026-05-18T14:33:00Z"
},
"prices": [
{
"pharmacy_chain": "Costco",
"store_name": "Costco Pharmacy #119",
"address": "450 10th St, San Francisco, CA 94103",
"zip": "94103",
"distance_miles": 0.8,
"list_price_usd": 24.32,
"coupon_price_usd": 4.00,
"savings_percent": 84,
"gold_price_usd": 3.00,
"coupon": {
"bin": "015558",
"pcn": "GDC",
"group": "EC95001003",
"member_id": "C9DK4XAGM"
},
"in_stock": true,
"pharmacy_deep_link": "https://www.goodrx.com/atorvastatin?pharmacy=costco&dosage=20mg&quantity=30&form=tablet&label_override=atorvastatin"
},
{
"pharmacy_chain": "Walmart",
"store_name": "Walmart Pharmacy 10-2110",
"address": "1899 Eddy St, San Francisco, CA 94115",
"zip": "94115",
"distance_miles": 1.4,
"list_price_usd": 24.32,
"coupon_price_usd": 6.62,
"savings_percent": 73,
"gold_price_usd": null,
"coupon": { "bin": "015558", "pcn": "GDC", "group": "EC95001003", "member_id": "C9DK4XAGM" },
"in_stock": null,
"pharmacy_deep_link": "https://www.goodrx.com/atorvastatin?pharmacy=walmart&dosage=20mg&quantity=30&form=tablet&label_override=atorvastatin"
}
],
"mail_order": [
{
"pharmacy_chain": "HealthWarehouse",
"store_name": "HealthWarehouse.com Mail Order",
"address": "7107 Industrial Rd, Florence, KY 41042",
"distance_miles": null,
"list_price_usd": 24.32,
"coupon_price_usd": 3.99,
"savings_percent": 84,
"gold_price_usd": null,
"in_stock": true,
"pharmacy_deep_link": "https://www.goodrx.com/atorvastatin?pharmacy=healthwarehouse&deliveryType=mail_order&dosage=20mg&quantity=30&form=tablet"
}
],
"external_offers": [
{
"provider": "Cost Plus Drug Company",
"url": "https://costplusdrugs.com/medications/atorvastatin-20mg-tablet/",
"advertised_price_usd": 4.05,
"captured_from": "promo_card"
}
],
"success": true,
"reason": null
}
Failure / branch shapes:
// Drug not found on GoodRx
{ "success": false, "reason": "drug_not_found", "query": { "drug_input": "..." } }
// Ambiguous user input — multiple top autocomplete matches
{
"success": false,
"reason": "ambiguous_name",
"candidates": [
{ "name": "Adderall", "slug": "adderall" },
{ "name": "Adderall XR", "slug": "adderall-xr" }
]
}
// Drug exists but no prices for the given dosage+form+quantity combo
{ "success": false, "reason": "no_prices_for_combo",
"drug": { "canonical_name": "...", "slug": "..." },
"available_combos": [ { "form": "tablet", "dosage": "10mg", "quantity": 30 }, ... ] }
// Anti-bot block (PerimeterX challenge interstitial detected)
{ "success": false, "reason": "anti_bot_block",
"detail": "PerimeterX challenge served. Retry with a fresh --verified --proxies session." }
// Location gate blocking prices (cookie not set, ZIP not provided, geo-IP rejected)
{ "success": false, "reason": "location_required",
"detail": "Set ZIP via /change-location?zip={zip} and retry." }
Prerequisites
Time Estimate
15-45 minutes depending on use case complexity
Steps
Common Pitfalls
✓ Do
✗ Don't
💡 Pro Tips
✓ Use when
Use when skill capabilities match your task, clear ROI on time saved, and you can validate outputs. Best for repetitive tasks, learning, and quality improvement.
✗ Avoid when
Avoid when task requires deep expertise you can't validate, involves sensitive decisions, or when learning process is more valuable than speed of completion.
airbnb.com/search-listings-ddgioa
avis.com/longterm-a3k8ng
booking.com/search-hotels-asq6cc
nav.com/get-smb-funding-2s1rpm
aliexpress.com/search-product-p0h8a7
google.com/search-flights-ts4g1f
Keeps context tight: compare-drug-prices is the kind of skill you can hand to a new teammate without a long onboarding doc.
Solid pick for teams standardizing on skills: compare-drug-prices is focused, and the summary matches what you get after install.
compare-drug-prices has been reliable in day-to-day use. Documentation quality is above average for community skills.
compare-drug-prices has been reliable in day-to-day use. Documentation quality is above average for community skills.
Useful defaults in compare-drug-prices — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
compare-drug-prices is among the better-maintained entries we tried; worth keeping pinned for repeat workflows.
compare-drug-prices has been reliable in day-to-day use. Documentation quality is above average for community skills.
Solid pick for teams standardizing on skills: compare-drug-prices is focused, and the summary matches what you get after install.
compare-drug-prices reduced setup friction for our internal harness; good balance of opinion and flexibility.
Solid pick for teams standardizing on skills: compare-drug-prices is focused, and the summary matches what you get after install.
showing 1-10 of 59