iHerb API & Scraper
iHerb sells one catalogue into about 30 countries, and the price is not the same in any two of them.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
This API makes the country a first-class parameter on every call rather than an afterthought: product 1135 returns $11.02 on the US storefront, 13,74 € on the German one, ¥1,856 in Japan, £12.71 in the UK and ₩14,460 in Korea, and price_by_country returns up to twelve of those side by side in a single call. The storefronts are not merely repriced — they are different catalogues, so the same vitamin C category holds 785 products in the US, 765 in Germany, 755 in Japan and 736 in the UK. A product record carries the brand, the SKU, the price with an explicit ISO currency beside it, the stock state, the supplement facts parsed out of iHerb's own panel into rows, the ingredient list, the pack size, shipping weight and dimensions, the rating and rating count, and the images. Reviews are public and come back with the per-star breakdown, the verified-purchase flag and iHerb's own summary of what customers said.
What changes when you change the country, and what does not
Everything on this page was measured against the live storefronts on one day. The first two rows are the ones that decide whether this API fits what you are building, so they go first.
| Field | What comes back | What it means |
|---|---|---|
| price_amount + currency | A number and an ISO currency code, always together, never merged into one string. The same product id: US 11.02 USD, GB 12.71 GBP, DE 13.74 EUR, JP 1856 JPY, KR 14460 KRW, AU 23.80 AUD, CA 19.85 CAD, IN 1355.54 INR, BR 79.03 BRL, TR 677.35 TRY | The currency is part of the answer, not something you infer from the country. Ukraine is the row that proves the point: the Ukrainian storefront prices in USD, not the local currency, so a country-to-currency lookup table on your side would have been wrong there. price_display carries iHerb's own formatted string alongside, so you can show exactly what the storefront shows. |
| rating_count | An integer — but it is shared across a product group, not per variant | Against us, and worth knowing before you build on it. Products 475 and 16539 are different sizes of the same supplement and both report exactly 25,485 ratings, because iHerb counts reviews per product family. If you sum rating_count across a brand's catalogue you will double-count. Use it per product, not as a total. |
| supplement_facts | Rows parsed out of iHerb's nutrition panel — name, amount, daily value. 6 of 6 on vitamin C, probiotics, whey protein and fish oil; 5 of 6 on green tea; 3 of 6 on pet health; 2 of 6 on coffee; 0 of 6 on shampoo | Present when the product has a panel and absent when it does not — a shampoo has no supplement facts, so 0 of 6 there is the source being right. The pooled figure across 48 products in 8 categories is 34 of 48, which is why the per-category breakdown is printed rather than the average. |
| in_stock + stock_status + stock_left_count | A boolean, a label (in_stock, in_stock_low, not_available, out_of_stock) and, only when stock is low, a remaining-units integer | stock_left_count was null on all 48 US products sampled, because iHerb prints a remaining count only when a product is actually running low — we saw it live on the German storefront as 9 units on a product that was plentiful in the US. Treat it as a low-stock signal, not an inventory feed. back_in_stock_date comes back where iHerb publishes one. |
| country_of_origin | Always null | Against us. The field exists in iHerb's data and is empty on all 48 products we sampled, so we return null rather than guessing it from the brand's address. If country of origin is what you need, this API does not have it. |
| ingredients, suggested_use, warnings | Plain text, with iHerb's markup removed. ingredients 44 of 48, suggested_use 48 of 48, warnings 43 of 48 | iHerb publishes these as HTML fragments; every string this API returns is stripped of tags and entities, checked across 48 product records, a full search payload and a reviews payload. Coffee is the category that thins out — 2 of 6 for ingredients. |
Real request and response JSON
Captured from the indexed primary action, search, on .
{
"method": "POST",
"url": "https://api.reefapi.com/iherb/v1/search",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"keyword": "vitamin c",
"country": "US"
}
}{
"ok": true,
"meta": {
"api": "iherb",
"endpoint": "search",
"mode": "live",
"latency_ms": 4509.1,
"record_count": 24,
"bytes": 328110,
"cache_hit": false,
"upstream_requests": 2,
"charged_credits": 3,
"version": "1.0.0"
},
"data": {
"keyword": "vitamin c",
"country": "US",
"currency": "USD",
"total": 14942,
"returned": 24,
"page": 1,
"sort": null,
"sorted_population_differs": false,
"spelling_suggestion": null,
"auto_corrected": false,
"matched_product_id": null,
"products": [
{
"product_id": 61864,
"sku": "CGN-00931",
"name": "California Gold Nutrition, Gold C®, USP Grade Vitamin C, 1,000 mg, 60 Veggie Capsules",
"brand": "California Gold Nutrition",
"brand_code": "CGN",
"url": "https://www.iherb.com/pr/california-gold-nutrition-gold-c-usp-grade-vitamin-c-1-000-mg-60-veggie-capsules/61864",
"review_url": "https://www.iherb.com/r/california-gold-nutrition-gold-c-usp-grade-vitamin-c-1-000-mg-60-veggie-capsules/61864",
"country": "US",
"currency": "USD",
"price_amount": 6.42,
"price_display": "$6.42",
"list_price_display": "$6.42",
"price_hidden": false,
"price_per_serving": "$0.11/serving",
"discount_percent": null,
"rating": 4.8,
"rating_count": 387625,
"in_stock": true,
"is_discontinued": false,
"is_available": true,
"is_sponsored": false,
"is_new": false,
"package_quantity": "60 count",
"product_form": "Vegetarian capsule",
"potency": "1,000 mg"
},
{
"product_id": 61865,
"sku": "CGN-00932",
"name": "California Gold Nutrition, Gold C®, USP Grade Vitamin C, 1,000 mg, 240 Veggie Capsules",
"brand": "California Gold Nutrition",
"brand_code": "CGN",
"url": "https://www.iherb.com/pr/california-gold-nutrition-gold-c-usp-grade-vitamin-c-1-000-mg-240-veggie-capsules/61865",
"review_url": "https://www.iherb.com/r/california-gold-nutrition-gold-c-usp-grade-vitamin-c-1-000-mg-240-veggie-capsules/61865",
"country": "US",
"currency": "USD",
"price_amount": 16.96,
"price_display": "$16.96",
"list_price_display": "$16.96",
"price_hidden": false,
"price_per_serving": "$0.07/serving",
"discount_percent": null,
"rating": 4.8,
"rating_count": 387624,
"in_stock": true,
"is_discontinued": false,
"is_available": true,
"is_sponsored": false,
"is_new": false,
"package_quantity": "240 count",
"product_form": "Vegetarian capsule",
"potency": "1,000 mg"
},
{
"product_id": 96338,
"sku": "LKN-01409",
"name": "California Gold Nutrition, Vitamin C, Quali®-C, 1,000 mg, 60 Veggie Capsules",
"brand": "California Gold Nutrition",
"brand_code": "CGN",
"url": "https://www.iherb.com/pr/california-gold-nutrition-vitamin-c-quali-c-1-000-mg-60-veggie-capsules/96338",
"review_url": "https://www.iherb.com/r/california-gold-nutrition-vitamin-c-quali-c-1-000-mg-60-veggie-capsules/96338",
"country": "US",
"currency": "USD",
"price_amount": 10.28,
"price_display": "$10.28",
"list_price_display": "$10.28",
"price_hidden": false,
"price_per_serving": "$0.17/serving",
"discount_percent": null,
"rating": 4.7,
"rating_count": 40298,
"in_stock": true,
"is_discontinued": false,
"is_available": true,
"is_sponsored": false,
"is_new": false,
"package_quantity": "60 count",
"product_form": "Vegetarian capsule",
"potency": "1,000 mg"
}
]
}
}What the iHerb API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| search | Keyword search on one country's storefront. Returns the storefront's own result total plus the filtered total so a filter's effect is visible. | Pricing teams call search to get keyword search on one country's storefront. | keyword, country, page, page_size, sort, ... |
| category | Browse one catalogue category on one country's storefront. | Marketplace operators call category to get browse one catalogue category on one country's storefront.. | slug, country, page, page_size, sort, ... |
| detail | One product in full on one country's storefront: price, stock count, supplement facts, ingredients, pack size, rating, shipping weight. | Catalog enrichment teams call detail to get one product in full on one country's storefront. | product_id, country |
| batch_detail | Up to 20 products in one call, on one storefront. iHerb has no batch route of its own, so this fans out — but it is priced below the equivalent single calls. | Retail analysts call batch_detail to get up to 20 products in one call, on one storefront. | product_ids, country |
| price_by_country | The same product priced across several national storefronts in one call — price, currency, availability and shipping restrictions side by side. This is what iHerb being a cross-border retailer actually means in data. | Pricing teams call price_by_country to get the same product priced across several national storefronts in one call. | product_id, countries |
| reviews | Customer reviews for a product, with the per-star breakdown and iHerb's own summary of them. Public — no account is involved. | Marketplace operators call reviews to get customer reviews for a product, with the per-star breakdown and iHerb's own summary of them. | product_id, country, page |
| categories | Every browsable catalogue category iHerb publishes (~1 480). | Catalog enrichment teams call categories to get every browsable catalogue category iHerb publishes (~1 480).. | search |
| filters | The filter vocabulary for a keyword or category on one storefront — brand codes, category ids, attribute ids and how many products sit behind each, so the opaque ids the other actions take are discoverable. | Retail analysts call filters to get the filter vocabulary for a keyword or category on one storefront. | keyword, slug, country |
Call search from your stack
curl -X POST https://api.reefapi.com/iherb/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"keyword":"vitamin c","country":"US"}'import requests
r = requests.post(
"https://api.reefapi.com/iherb/v1/search",
headers={"x-api-key": REEF_KEY},
json={
"keyword": "vitamin c",
"country": "US"
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/iherb/v1/search", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"keyword": "vitamin c",
"country": "US"
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.iherb.search with {"keyword":"vitamin c","country":"US"}.Who uses this API and why
- Price a product across borders before you launch there: give price_by_country one product id and a dozen markets and get back the price, currency, availability and local display string for each, so you can see what iHerb charges in a market before you set your own price against it.
- Watch a competitor's supplement range in one country: run a category or brand-filtered search on that storefront and store price_amount with its currency, the rating and the rating count, then re-run it on a schedule to follow price moves and review growth.
- Build a supplement comparison or ingredient search: pull supplement_facts as rows plus the ingredient text across a category and compare dosage per serving between brands, using price_per_unit and pack size to get a real cost per serving rather than a cost per bottle.
- Check where a product is actually sold: price_by_country tells you which storefronts list an item and which do not, and each record carries the restricted-countries list and a banned flag, which is the difference between a product you can source and one you cannot.
- Mine reviews for product research: pull the per-star breakdown and the review text for a product, filter to verified purchases, and read iHerb's own summary of customer sentiment alongside the raw reviews.
Questions developers ask before integrating
How do I get the price in a specific country?
Pass country on any call — search, category, detail, batch_detail or reviews all take it, and it defaults to US. Thirty storefronts are supported: US, CA, MX, BR, GB, DE, FR, IT, ES, NL, PL, SE, TR, UA, IL, AE, SA, ZA, IN, JP, KR, HK, TW, SG, MY, TH, VN, PH, AU and NZ. Every response repeats the country and the ISO currency it was priced in, so a stored row can never lose track of which storefront it came from. If a storefront cannot be reached for a request, the call fails with a clear error instead of quietly answering from a different country — a price in the wrong currency is worse than no price.
Can I compare one product across several countries in one call?
That is what price_by_country does. Give it a product id and up to twelve country codes and it returns one row per storefront with the price, the ISO currency, the local display price, the stock state and whether the product is listed there at all. Products are not on every storefront — when one is missing, that row says so rather than being dropped, so you can see where a product is simply not sold. No currency conversion is applied anywhere in this API: each figure is the number iHerb itself prints in that market, because an FX rate we invented would be the least reliable number on the page.
Are the reviews real reviews, or just the rating?
Real reviews, and no account is involved in reading them. Each page returns ten with the review text, the title, the star rating, the date, the language, the verified-purchase flag, the helpful-vote counts and how many photographs are attached. Alongside them you get the average, the total, and the full per-star breakdown — for product 468 that is 6,580 ratings split 5,314 five-star, 871 four, 305 three, 52 two and 38 one — plus iHerb's own written summary of what customers said. Product 468 runs to 653 pages of reviews. Reviewer display names are withheld by default and returned only if you explicitly ask for them; handles and avatars are never returned.
Do the filters actually narrow the results, or are they accepted and ignored?
Every filter this API exposes narrows the result, and we publish the proof. Against an unfiltered 14,940 results for vitamin c: the four-star band returns 8,909, the NOW Foods brand 756, California Gold Nutrition 319, the cheapest price band 248, the immune-support health topic 2,604, the vegan attribute 4,820 and the iTested programme 273. In-stock-only takes 14,940 to 14,468. Two filters that iHerb itself advertises are deliberately not exposed here: one is accepted and changes nothing, and the other returns an error for every value. Rather than pass those through and let you believe they worked, we left them out.
Why is the rating filter called rating_band and not min_rating?
Because it is a band and not a minimum, and the honest name saves you a wrong result. Asking for band 3 returns products rated roughly 2.8 to 3.7 — it excludes the four- and five-star products, rather than including everything above three. Measured on one storefront: band 5 returns 5,818 products rated about 4.8 and up, band 4 returns 8,909 rated roughly 3.8 to 4.7, band 3 returns 36, band 2 returns 6 and band 1 returns 2. The filters action prints the live count sitting behind each band so you can see the shape before you query.
Does sorting just reorder the results?
No, and this one surprised us enough to put it in the response. Unsorted, vitamin c returns 14,807 results; sorted by price, by rating, by newest or by any other explicit sort, the same query returns 10,559. Sorting changes which products are in the set by about 29 percent, it does not merely change their order. The search response carries a sorted_population_differs flag so this is visible in the data rather than only in the documentation. Featured and relevance are the two that leave the total alone.
How do I find the brand codes and attribute ids the filters want?
Call the filters action with a keyword or a category slug. It returns iHerb's own vocabulary for that query with a live product count beside every option: 1,056 brands, 1,349 category ids, plus health topics, price bands, programmes and the attribute groups that cover diet and certification, product form, age range and skin or hair concern. That is 28 filter groups and 2,725 options on a single query. The codes are opaque — NOW Foods is NOW, 100% PURE is URE — so reading them from this call is the only reliable way to get them right.
How do I get product ids in the first place?
Three ways, and none of them needs you to know an id in advance. Search by keyword; browse a category, with all 1,483 category slugs available from the categories action; or, if you already have an iHerb URL, the id is the last path segment. Search also resolves a SKU or part number directly, so a query that exactly matches a product comes back flagged as an exact match. A search row and a detail record agree: we checked six ids from search through to detail and got the same id, the same type, the same SKU and the same price to the cent on all six.
What is the iHerb API?
iHerb API is a ReefAPI endpoint group for supplements and natural health, priced in 30 countries. It returns live JSON through POST requests under /iherb/v1.
Is the iHerb API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. iHerb calls use the same shared credit balance as every other ReefAPI engine.
Do I need an iHerb login or account?
No login to iHerb is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the iHerb data?
The page example is captured from a live search call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the iHerb API use?
iHerb actions currently cost 1-3 credits per successful call. Failed or blocked calls are free. All APIs draw from one credit pool.
Can I call iHerb from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call iherb actions with the same key, credit pool and JSON envelope used by normal REST requests.