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.
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
Time estimate: 15-45 minutes depending on use case complexity
Prerequisites
Submit your Claude Code skill and start earning
browse install goodrx.com/compare-drug-prices-c8d87yCompatible with
Supported agents
| 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." }
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:
browse install goodrx.com/compare-drug-prices-c8d87yFetches 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:
.cursor/skills/compare-drug-prices
Restart Cursor to activate compare-drug-prices. Access via /compare-drug-pricesin your agent's command palette.
Learn more:View source on GitHubSkills CLI docsAbout CursorWhat are agent skills?
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.
compare-plans
healthcare.gov/compare-plans-ruai96 · healthcare · tag: healthcare
provider-search
findadoc.healthplan.org/provider-search-ykncm6 · healthcare · tag: healthcare
find-california-business
bizfileonline.sos.ca.gov/find-california-business-izbvm2 · government · tag: read-only
compare-credit-cards
nerdwallet.com/compare-credit-cards-0a4ihq · credit-cards · tag: read-only
get-company-reviews
glassdoor.com/get-company-reviews-qknrhf · employer-reviews · tag: read-only
recipe-discovery-generator
recipebee.app/recipe-discovery-generator-cdqfi0 · food-and-cooking · tag: read-only
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