INCI Beauty Safety Score & Ingredients Scraper
Pricing
from $4.50 / 1,000 results
INCI Beauty Safety Score & Ingredients Scraper
Scrape INCI Beauty by barcode: the 0-20 safety score, full risk-rated INCI composition and ingredient reference dictionary. Score INCI, pay per result.
Pricing
from $4.50 / 1,000 results
Rating
0.0
(0)
Developer
Extractify Labs
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
2
Monthly active users
a month ago
Last modified
Categories
Share
🧴 INCI Beauty Safety Score & Ingredients Scraper
Scan a barcode, get the score French shoppers actually check. This actor turns incibeauty.com into a clean, structured feed: every cosmetic product keyed by its EAN/GTIN barcode, carrying INCI Beauty's published 0-20 "Note INCI Beauty" safety score, the full ordered ingredient (INCI) composition with each ingredient's risk class, product images and retail price offers. Alongside the products you get a 16,879-record INCI ingredient reference dictionary (INCI name, CAS, EINECS, functions, risk class, origin, multilingual names). Two entities, one dataset, joinable on the ingredient identifier.
The key thing to understand up front: we reproduce INCI Beauty's own published data, faithfully. The 0-20 score and the green-to-red ingredient ratings are theirs, captured verbatim. This actor invents no methodology and computes no score of its own. If you have ever been burned by a scraper that bolts on its own opinionated "safety rating," that is exactly the trap this avoids.
🇫🇷 INCI Beauty est un service du marché français. Cet acteur extrait les produits cosmétiques (score 0-20 « Note INCI Beauty », composition INCI complète, classe de risque par ingrédient) et le dictionnaire de référence des ingrédients INCI d'incibeauty.com.
👤 Who it's for
- 💄 Cosmetic brands & formulators (R&D, regulatory, competitive marketing). See exactly how your SKUs and your competitors' score on a French-market gatekeeper, ingredient by ingredient, and benchmark composition against your own catalog.
- 📱 Clean-beauty, "dupe" and comparison apps. Barcode in, score plus composition out, so you can power "is this safe?" and "show me a better-rated alternative" without building a scoring system.
- 🛒 Retailers & e-commerce teams enriching product pages with a recognized safety score and surfacing better-rated SKUs.
- 🔬 Researchers & NGOs running ingredient-prevalence and cosmetic-safety studies across the catalog plus the full ingredient dictionary.
- ✍️ Affiliate & SEO content sites building score-plus-price comparison content that earns engagement.
✅ What you get
- 🎯 The real 0-20 "Note INCI Beauty" score, plus the quality tier behind the colored-flower badge, captured exactly as INCI Beauty publishes it.
- 🌿 Per-ingredient risk, green to red. Every ingredient in the composition carries its hazard level (0 = no concern, higher = more concern) and its penalty families, aligned to the declared order.
- 🧪 The full ordered INCI composition for each product, not a summary. This is the headline field.
- 🔍 A transparent score breakdown (valid ingredient count, composition size, clean and bio flags) so you can see why a product scored the way it did and reconcile it against your own data.
- 🆔 EAN/GTIN as the primary key, so products drop straight into retail catalogs, open product databases and your own SKU lists.
- 📚 A 16,879-record INCI ingredient dictionary: official INCI name, CAS, EINECS, food-additive E-number, cosmetic functions, risk/penalty class, origin, free-text notes, localized names (22 locales) and a count of how many products contain each ingredient.
- ⏱️ Freshness built in. Risk classes and scores are a moving target on INCI Beauty as their knowledge base updates. Every row carries a
scraped_atcapture timestamp, and products carry the source's own composition date, so a periodic re-crawl keeps you current instead of stuck with a one-time dump. - ⚙️ You choose what to pull: products only, the ingredient dictionary only, or both in one run. Narrow by brand, barcode, ingredient or specific URLs. Toggle composition and price.
🗂️ Scope & coverage (what's in, what's not)
Covered
- 🚀 Products: the cosmetic catalog keyed by EAN/GTIN, walked brand by brand across the full A-Z brand index (hundreds of thousands of products, on the order of ~300,000), de-duplicated by barcode. No result-window cap, so a full crawl reaches the whole brand-listed catalog.
- 🧬 Product composition & score: the complete per-product INCI composition (ordered list + per-ingredient risk + score breakdown), captured for each product by default.
- 💶 Price offers: the merchant price offers shown on each product page (EUR by default).
- 📖 Ingredients: the full browsable INCI reference dictionary, 16,879 verified distinct ingredients, de-duplicated by ingredient id.
Not covered (by design)
- 💬 Product reviews / Q&A are not collected. They appear only on a Cloudflare-protected product page with no API path, so this actor does not fetch them. The review fields remain in the schema (always empty) for transparency.
- 🏷️ Brandless products (any product not listed under a brand) fall outside the brand-walk, the one structural item edge.
- 🔤 Ingredient synonym tail beyond the 16,879 browsable records (a much larger backend synonym keyspace) is intentionally out of default scope.
- 🔒 Account-gated B2B / login-walled feeds are out of scope. This actor reads only what INCI Beauty shows publicly to anonymous visitors; it never logs in.
These edges could be covered later by companion actors if you need them. They are boundaries, not defects.
📊 Output fields
The actor writes one dataset with two row types. Every row has an entity field set to either product or ingredient. Product rows fill the product fields; ingredient rows fill the ingredient fields; a small set of fields is shared by both. Use the built-in Products and Ingredient reference dataset views to see each as a clean table, or filter on entity yourself.
Shared fields (both entities)
| Field | Type | Description |
|---|---|---|
entity | string | Row type: product or ingredient. Use it to filter, or pick the matching dataset view. |
sourceUrl | string | The incibeauty.com page this row was collected from. |
website | string | Source website host (incibeauty.com). |
scrapeDate | string | UTC date (YYYY-MM-DD) the row was collected. Scores and risk classes change over time, so this matters. |
scraped_at | string | null | UTC capture timestamp (ISO-8601). The freshness key for the mutable score and risk data. |
country | string | null | ISO country of the service (FR). |
currency | string | null | Price currency for product offers (EUR). |
product_locale | string | null | Locale of the captured row (default fr). |
locale_variants | array | null | Other-language versions of the page available (hreflang variants). |
canonical_url | string | null | Canonical page URL. |
Product fields (entity = "product")
| Field | Type | Description |
|---|---|---|
ean_gtin | string | null | The product barcode (EAN / GTIN). Primary key for products. Several barcode forms can occur (13-digit, zero-padded, hyphenated). |
product_name | string | null | Product title. |
brand | string | null | Brand name. |
brand_slug | string | null | Brand slug (the key to the brand's page). |
marque_parent | string | null | Parent company or group behind the brand, when published. |
inci_score | number | null | The 0-20 "Note INCI Beauty" overall safety score. |
score_quality_tier | string | null | Quality tier behind the colored-flower badge. |
score_breakdown | object | null | The components behind the 0-20 score: score value, count of valid ingredients, composition size, and the clean / bio flags. |
is_unrated | boolean | null | True when the product is not yet scored. |
is_approximative_note | boolean | null | True when the score is approximate. |
product_category | string | null | Cosmetic category path. |
full_inci_composition | array | null | The headline field. The full ordered INCI ingredient list. Each entry carries the ingredient name, official name, risk level and function families. |
composition_ingredient_name | array | null | The official INCI names of the composition, in declared order. |
composition_ingredient_position | array | null | The 1-based declared position of each ingredient. |
per_ingredient_risk_class | array | null | Per-ingredient hazard level (0 = no concern, higher = more concern), aligned to the composition order. |
per_ingredient_penalty_reasons | array | null | Risk/penalty families per ingredient, aligned to the composition order. |
composition_status | string | null | Whether the composition is fully expanded (the normal case) or, in a rare fallback, returned in raw form. In the published actor this is the expanded form. |
composition_ciphertext | string | null | Empty in normal runs; populated only in the rare raw fallback noted above. |
composition_ciphertext_b64_len | integer | null | Diagnostic length value, present only alongside the rare fallback. |
product_image_large | string | null | Large product image URL. |
product_image_small | string | null | Small product image URL. |
product_image_thumb | string | null | Thumbnail image URL (from the brand listing card). |
user_photos | array | string | null | User-submitted photos when available. |
where_to_buy_table | array | null | Merchant price offers. Each offer carries retailer, price value, currency, availability, a display string and a shop link. |
acheter_currency_options | array | null | Currencies offered by the price widget. |
acheter_response_status | integer | null | Status of the price/offers lookup (200, or 404 when a product has no offers). |
date_compo | string | null | When INCI Beauty last computed the composition/score (ISO-8601). A second freshness signal. |
similar | object | array | null | Related/recommended products. |
alternative_products | array | null | "Produits alternatifs" links. Not collected (bot-protected page; always null) — for related products see similar. |
comment_count_new | integer | null | Count behind the "new comments" badge. |
comment_count_total | integer | null | Total review/comment count. Not collected (always null). |
reviews_comments | array | null | User reviews/comments. Not collected — the reviews page is bot-protected (always empty). |
review_author | string | null | Public review author pseudonym. Not collected (always null). |
review_body | string | null | Review free text. Not collected (always null). |
review_date | string | null | Review date. Not collected (always null). |
review_id | integer | null | Review identifier. Not collected (always null). |
product_mini | object | string | null | A lighter product card surface, when available. |
product_subscription_state | string | boolean | null | The anonymous "searchable" flag for the product. |
brand_logo | string | null | Brand logo image URL. |
product_weight | string | null | Net weight / volume, from the product information block. |
skin_type | string | array | null | Target skin type(s), from the product information block. |
certifications | array | null | Certifications / labels (e.g. bio, clean). Sparse; present mainly on certified products. |
product_information | array | object | null | The product information block: weight/volume, skin type, period-after-opening, usage advice. |
engagement_stats | object | null | Public engagement counters (scans, likes). |
product_natural_extracts | array | object | null | Natural-extract details for the product. |
Ingredient fields (entity = "ingredient")
| Field | Type | Description |
|---|---|---|
ingredient_id | integer | null | Integer ingredient id. Primary key for ingredients, and the join key from a product's composition. |
ingredient_slug | string | null | URL slug. |
inci_name | string | null | Official INCI name. |
ingredient_french_name | string | null | French common name. |
cas_number | string | null | CAS registry number. |
einecs_number | string | null | EINECS / EC number. |
additif_enumber | string | null | Food-additive E-number, when applicable. |
ingredient_description | string | null | Free-text "À savoir" note, when present. |
ingredient_functions | array | null | Cosmetic functions, each with a name and description. |
ingredient_risk_penalty_status | string | null | The colored-flower risk/penalty rating label. |
ingredient_risk_penalty_tier | string | null | The risk tier behind the flower icon. |
ingredient_origin | array | null | Origin classification (e.g. vegetal, synthetic). |
ingredient_classification | array | null | Classification labels. |
ingredient_names_other_languages | array | null | Names in other languages, from the detail page. |
ingredient_name_localized | object | null | A {locale: name} map across 22 locales. |
ingredient_products_containing | array | null | A sample of products that contain this ingredient, each with barcode, name, brand and score. |
ingredient_nb_produits | integer | null | How many products contain this ingredient (a scale signal). |
ingredient_natural_extract | object | string | null | Natural-extract detail for the ingredient, when available. |
inci_name_md5 | string | null | Stable hash of the INCI name. |
ingredient_spellcheck_name | string | null | Normalized name. |
ingredient_id_synonyme | integer | null | Synonym id (0 = canonical record). |
ingredient_link | string | null | Canonical ingredient link. |
🔗 About the product ↔ ingredient join. A product's composition carries an ingredient id, and the ingredient dictionary is keyed by that same id, so the two streams are designed to be joined on the ingredient identifier. Run with
entity = bothto get both in one feed.
🔧 Input
Everything is optional. Leave it all on the defaults for a quick, non-empty sample run.
| Input | What it does |
|---|---|
What to collect (entity) | products, ingredients, or both. Products are EAN-keyed and scored with full composition; ingredients are the reference dictionary. |
Start URLs (startUrls) | Specific INCI Beauty page URLs to collect: a product page (/produit/<barcode>), an ingredient page (/ingredients/<id>-<name>), or a brand page (/brand/<brand-slug>). Leave empty to crawl by the filters below. |
Brands (brands) | Brand slugs to crawl (e.g. loreal-paris, nivea). Only products from these brands are returned. Empty = walk the full A-Z brand catalog. |
Product barcodes (eans) | A list of EAN / GTIN barcodes to look up directly, skipping the brand walk. Ideal for enriching an existing barcode list. |
Ingredient identifiers (ingredientIds) | A list of ingredient id-name segments (e.g. 12345-aqua) to look up directly from the dictionary. |
Maximum results (maxItems) | Stop after this many records per stream (products and ingredients are capped independently). Lower it for a quick test. The free daily-test default is 10. |
Include price offers (includePrice) | ON by default; adds negligible cost. Collects the retail price offers shown on each product page. Products only. |
Enrich ingredient records (enrichIngredients) | OFF by default. Adds extra naming, classification and CAS detail to each ingredient at the cost of one extra request per ingredient. Ingredients only. |
Proxy (proxyType) | No proxy (default, fastest and cheapest) works for the whole actor. Apify Proxy routes through your own Apify account (you pay Apify for that traffic) if you want to rotate IPs. |
⚡ Quick sample run (the default, finishes fast)
This is the prefilled default. It pulls a small slice of the ingredient dictionary and finishes non-empty in well under five minutes, with no proxy.
{"entity": "ingredients","maxItems": 10,"enrichIngredients": false,"proxyType": "none"}
💄 One brand, products with composition and score
Pull a single brand's products, each with the full risk-rated composition, the 0-20 score and price offers.
{"entity": "products","brands": ["respire"],"maxItems": 100,"includePrice": true,"proxyType": "none"}
🔢 A handful of barcodes (enrich your own SKU list)
Resolve specific barcodes straight to their scored product records.
{"entity": "products","eans": ["3760368740730", "4005808851904"],"includePrice": true,"proxyType": "none"}
📦 Sample output
A product row (values are illustrative placeholders):
{"entity": "product","ean_gtin": "3760368740730","product_name": "Deodorant Stick Fleur de Coton","brand": "Respire","brand_slug": "respire","inci_score": 19.5,"score_quality_tier": "fleurfont1","score_breakdown": { "score_sur20": 19.5, "valid_incis": 3, "composition_count": 3, "is_ib_clean": true, "is_bio": false },"product_category": "Deodorant","composition_ingredient_name": ["HELIANTHUS ANNUUS SEED OIL", "PARFUM", "TOCOPHEROL"],"composition_ingredient_position": [1, 2, 3],"per_ingredient_risk_class": [0, 2, 0],"where_to_buy_table": [{ "retailer": "Example Shop", "price_value": 9.9, "price_currency": "EUR", "price_availability": "in_stock" }],"product_image_large": "https://incibeauty.com/photos/products/large/.../image.jpg","date_compo": "2025-08-20T04:52:45Z","sourceUrl": "https://incibeauty.com/produit/3760368740730","scrapeDate": "2026-06-22","scraped_at": "2026-06-22T18:00:00Z"}
An ingredient row (values are illustrative placeholders):
{"entity": "ingredient","ingredient_id": 1447,"inci_name": "HELIANTHUS ANNUUS SEED OIL","ingredient_french_name": "Huile de graines de tournesol","cas_number": "8001-21-6","einecs_number": "232-273-9","ingredient_functions": [{ "function_name": "Emollient", "function_desc": "Softens the skin." }],"ingredient_risk_penalty_status": "No concern","ingredient_risk_penalty_tier": "1","ingredient_origin": ["Vegetal"],"ingredient_name_localized": { "en": "Sunflower seed oil" },"ingredient_nb_produits": 227635,"sourceUrl": "https://incibeauty.com/ingredients/1447-helianthus-annuus-seed-oil","scrapeDate": "2026-06-22","scraped_at": "2026-06-22T18:00:00Z"}
❓ FAQ
How fast is it, and how many results will I get?
The quick sample default (10 ingredient records, no proxy) finishes non-empty in well under five minutes. A full crawl scales with how much you ask for: the products catalog runs into hundreds of thousands of records (on the order of ~300,000), and the ingredient dictionary is 16,879 verified records. Use maxItems to cap either stream while you test.
How fresh is the data?
You get whatever INCI Beauty publishes at the moment you run the actor. Scores and per-ingredient risk classes are mutable, they change as INCI Beauty updates its knowledge base, so every row carries a scraped_at timestamp and products also carry the source's own date_compo. Re-run on a schedule to keep current; this is a refreshable feed, not a one-time dump.
Where does the score come from? Is it your rating? No. The 0-20 score, the quality tier and the per-ingredient risk classes are INCI Beauty's own published data, captured faithfully. This actor computes no score and invents no methodology.
Do I need a proxy? No. The default No proxy option works for the whole actor and is the fastest and cheapest. Apify Proxy is optional and routes through your own Apify account (you pay Apify for that traffic) if you want to rotate IPs.
How does billing work?
This actor uses Pay Per Result: you are billed per item written to the dataset. There is no separate start fee. If you are on a free plan, the run stops gracefully when it reaches your usage limit, it does not crash, so you always keep the results collected up to that point. Use maxItems to control exactly how many results (and how much spend) you want.
Can I get just the products, or just the ingredients?
Yes. Set What to collect to products, ingredients, or both. Both streams land in the same dataset, tagged by the entity field, and the dataset ships with separate Products and Ingredient reference views.
Can I look up specific products by barcode? Yes. Put your EAN / GTIN barcodes in the Product barcodes input and each one is resolved straight to its scored product record, skipping the brand walk. Perfect for enriching an existing SKU list.
Are reviews included? No. Reviews appear only on a bot-protected product page (no API path), so this actor does not collect them. It focuses on the 0-20 score, the full risk-rated composition, price, and the 16,879-ingredient dictionary.
Is this legal? This actor collects data that INCI Beauty displays publicly to anonymous visitors. You are responsible for using the output in line with applicable law and INCI Beauty's terms. See the disclaimers below.
⚠️ Disclaimers
Unofficial and not affiliated. This actor is unofficial and is not affiliated with, authorized by, or endorsed by INCI Beauty or Touslesprix. It is not "the INCI Beauty API." No third-party trademarks or logos are used. All product, brand and service names belong to their respective owners.
Public data. This actor collects data that INCI Beauty displays publicly to anonymous visitors.
Faithful reproduction. The 0-20 INCI Beauty score, the per-ingredient risk classes and the compositions are INCI Beauty's published data, reproduced faithfully. This actor does not invent a scoring methodology and does not compute its own scores or ratings.
Personal data. By default this actor collects no personal data — it returns public cosmetic product and ingredient information. Product reviews (which would contain author pseudonyms and free text) are not collected, because their source page is bot-protected. Use any output in line with applicable law and INCI Beauty's terms.
Responsible use. Use this data in compliance with applicable law and INCI Beauty's terms. You are responsible for your use of the output, including any reuse, redistribution, or processing of personal data.
🔎 Keywords: INCI Beauty scraper, cosmetic safety score, Note INCI Beauty, INCI ingredients, composition cosmétique, score de sécurité cosmétique, EAN GTIN cosmetics, ingredient risk class, base de données ingrédients INCI, CAS EINECS, cosmetic ingredient database.