Open Beauty Facts APIworld.openbeautyfacts.org ↗
Search beauty products, look up INCI ingredient lists by barcode, and browse cosmetic categories via the Open Beauty Facts API. 4 endpoints.
What is the Open Beauty Facts API?
The Open Beauty Facts API gives developers access to cosmetic and beauty product data across 4 endpoints, covering full-text product search, barcode lookup, ingredient-based filtering, and category taxonomy. The get_product_detail endpoint returns up to 9 structured fields per product — including the full INCI ingredient list, brand, labels, country of origin, and an image URL — identified by EAN-13 barcode.
curl -X GET 'https://api.parse.bot/scraper/fb148a2a-3597-417d-9698-45cd8da23b99/search_products?page=1&query=shampoo' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace world-openbeautyfacts-org-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: Open Beauty Facts SDK — bounded, re-runnable; every call capped."""
from parse_apis.world_openbeautyfacts_org_api import OpenBeautyFacts, ProductNotFound
client = OpenBeautyFacts()
# Search for products by keyword
for product in client.product_summaries.search(query="shampoo", limit=3):
print(product.product_name, product.brand, product.categories)
# Search by INCI ingredient
for product in client.product_summaries.search_by_ingredient(inci_name="aqua", limit=3):
print(product.product_name, product.brand)
# Navigate from summary to full detail
item = client.product_summaries.search(query="coconut", limit=1).first()
try:
detail = item.details()
print(detail.product_name, detail.ingredients_text, detail.labels)
except ProductNotFound as e:
print("not found:", e.barcode)
# List categories
for cat in client.categories.list(limit=3):
print(cat.name, cat.products)
print("exercised: product_summaries.search / product_summaries.search_by_ingredient / ProductSummary.details / categories.list")
Full-text search over beauty and cosmetic products by name, brand, or keyword. Results are paginated; each product includes name, brand, categories, country, INCI ingredient list, and product URL.
| Param | Type | Description |
|---|---|---|
| page | integer | Page number for paginated results (1-based). |
| queryrequired | string | Search term matching product name, brand, or keyword. |
{
"type": "object",
"fields": {
"page": "integer current page number",
"count": "integer total number of matching products",
"products": "array of product summaries",
"page_size": "integer products per page",
"page_count": "integer total number of pages"
},
"sample": {
"data": {
"page": 1,
"count": 2438,
"products": [
{
"url": "https://world.openbeautyfacts.org/product/8001090662231/coconut-milk-herbal-essences",
"brand": "Herbal Essences",
"barcode": "8001090662231",
"countries": "Maroc",
"categories": "Soins cheveux, Shampoings",
"product_name": "Coconut Milk",
"ingredients_text": "Aqua, Sodium Laureth Sulfate"
}
],
"page_size": 24,
"page_count": 24
},
"status": "success"
}
}About the Open Beauty Facts API
Endpoints and Data Coverage
The API exposes four endpoints against the Open Beauty Facts database. search_products accepts a query string and returns paginated summaries including product name, brand, categories, country, and INCI ingredient text. get_product_detail accepts a barcode (EAN-13 or similar) and returns a single product record with fields: product_name, brand, categories, ingredients_text, labels, countries, image_url, url, and barcode. If the barcode is absent from the database, the endpoint returns input_not_found.
Ingredient and Category Search
search_by_ingredient filters products by a specific INCI ingredient name. The inci_name parameter is matched as a tag — case-insensitive, with spaces normalized to hyphens — so 'sodium laureth sulfate' and 'Sodium Laureth Sulfate' resolve identically. Results follow the same paginated shape as search_products: count, page, page_count, page_size, and a products array. list_categories returns the full category taxonomy — skin care, hair care, makeup, hygiene, and others — with each entry carrying an id, name, url, and products count. The endpoint returns 100 categories per page.
Pagination Behavior
All four endpoints that return lists use 1-based page numbering. Every paginated response includes page, page_count, page_size, and count so callers can determine total results and iterate without a separate metadata request. The search_products and search_by_ingredient endpoints share the same response envelope, making it straightforward to handle both with a single response parser.
The Open Beauty Facts API is a managed, monitored endpoint for world.openbeautyfacts.org — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when world.openbeautyfacts.org changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official world.openbeautyfacts.org API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build an ingredient safety checker that uses
search_by_ingredientto find all products containing a flagged INCI compound. - Populate a product catalog by looking up cosmetics via
get_product_detailwith known EAN-13 barcodes. - Create a category browser that lists all cosmetic taxonomy nodes and their product counts via
list_categories. - Match a scanned barcode to a product's full INCI ingredient list and labels for a cosmetics scanner app.
- Aggregate brand coverage data by querying
search_productswith brand names and counting matching results. - Filter products by country of origin using the
countriesfield returned byget_product_detail. - Cross-reference a product's
categoriesandingredients_textfields to audit formulation trends across a category.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does Open Beauty Facts have an official developer API?+
What does `get_product_detail` return when a barcode isn't in the database?+
input_not_found. It does not throw an HTTP error. Callers should check for this value before attempting to read product fields from the response.How does ingredient matching work in `search_by_ingredient`?+
inci_name parameter is matched as a tag: the value is lowercased and spaces are replaced with hyphens before lookup. For example, 'Sodium Laureth Sulfate' is treated the same as 'sodium-laureth-sulfate'. Partial substring matches within ingredient text are not supported by this endpoint — the match is tag-based.Can I filter `search_products` results by category, country, or label?+
search_products accepts only a free-text query and an optional page parameter. Structured filters like category ID, country, or label are not exposed as inputs. You can fork this API on Parse and revise it to add a filtered-search endpoint that accepts those parameters.Does the API expose nutritional or allergen data beyond the INCI ingredient text?+
ingredients_text, labels, categories, brand, countries, image_url, and product_name. Structured allergen flags, toxicity scores, or per-ingredient hazard data are not part of any response. You can fork this API on Parse and revise it to add an endpoint that surfaces those fields if they exist in the source database.