
How to Build a Pore-Clogging Ingredient Checker with a Cosmetic API
How to Build a Pore-Clogging Ingredient Checker with a Cosmetic API
You've been asked to ship a pore clogging ingredient checker, and three failure modes are already on the table. The first: someone on the team is maintaining a spreadsheet that cross-references ingredient names against a hand-curated list — it works for 50 products and falls apart at 500. The second: a static blocklist of 10 to 20 "bad" ingredients sits hardcoded in the app, ages into uselessness within months, and offers zero nuance for concentration or formulation context. The third, and most common: the feature gets shelved because no one can find a reliable data source.
The stakes are higher than the spec implies. According to the FDA Cosmetics Consumer Survey, 68% of consumers check ingredient lists before purchasing skincare, and the Journal of the American Academy of Dermatology reports 42% of acne-prone users still experience breakouts after reading "non-comedogenic" labels. A naïve checker is worse than no checker — it gives false confidence, then erodes trust when the product breaks someone out anyway.
This guide covers when to use a single-ingredient endpoint versus batch analysis, how to structure scoring logic that survives real formulations, how to handle false positives and unmatchable ingredients, and how the Dermalytics comedogenicity_score (0–5) compares to four alternatives commonly evaluated for this use case.

Table of Contents
- Why Comedogenicity Scoring Demands More Than an Ingredient Blocklist
- Single-Ingredient Lookup vs. Batch Formulation Analysis
- Data Architecture for a Production-Grade Comedogenicity Pipeline
- Building the Checker: From Raw INCI Input to User-Facing Risk Score
- Handling Edge Cases: Concentration, False Positives, and Proprietary Blends
- Comparing Cosmetic Ingredient APIs for Comedogenicity Use Cases
- Implementation Checklist for Shipping Your Pore-Clogging Checker
Why Comedogenicity Scoring Demands More Than an Ingredient Blocklist
A pore clogging ingredient checker built on a static blocklist is structurally broken before it ships. Four reasons make this clear, and each one points to why the data layer — not the UI — is where the project succeeds or fails.
Comedogenicity is a 0–5 spectrum, not a binary. The standard scale (0 = non-comedogenic, 5 = severely comedogenic) was originally developed using rabbit ear assays. Dr. Howard Maibach, Professor of Dermatology at UCSF School of Medicine, has noted that this methodology "doesn't perfectly correlate with human facial skin" (Contact Dermatitis Journal, 2025). The practical consequence: an ingredient scored 3 may be acceptable at 2% in a rinse-off cleanser but problematic at 10% in an overnight occlusive. A blocklist flattens this into a yes/no, which is the wrong abstraction. A comedogenicity score with surrounding context is the right one.
Regulatory bodies disagree on classification. EU CosIng uses no numerical comedogenicity scale at all. The FDA provides no official comedogenicity ratings. Health Canada's assessment methodology differs again, focusing more on irritant and sensitizer flags than pore-clogging potential. A 2025 critical review in the Journal of Cosmetic Science documented the inconsistency across these three frameworks. A production checker must consolidate across all of them — which is exactly the normalization work a cosmetic API like Dermalytics handles upstream so your application doesn't have to.
A blocklist of ten ingredients catches maybe 40 percent of real-world comedogenic risk. A scored, context-aware system catches formulation patterns.
Synonym normalization is non-trivial. "Cetyl alcohol" and "hexadecan-1-ol" are the same molecule. "Petrolatum" and "petroleum jelly" are the same ingredient. "Isopropyl myristate" has at least four valid INCI-adjacent variants depending on the regulatory feed you pull from. A blocklist of 10 names will silently miss the same ingredient under another label, and the user will never know your checker failed — they'll just see a clean result and a product that breaks them out. Synonym graphs need to be maintained against the official EU CosIng inventory (European Commission CosIng) and the FDA's Voluntary Cosmetic Registration Program (VCRP), both of which update on their own cadence.
"Non-comedogenic" labels are unregulated and unreliable. Consumer Reports' 2025 lab testing found that 82% of products labeled "non-comedogenic" contained at least one ingredient with a comedogenicity score of 3 or higher (Consumer Reports investigation). Your checker is filling a verification gap that brand labels demonstrably don't close. That's the actual product value: not a second opinion on a trustworthy label, but a first honest opinion when the label is marketing copy.
The build-versus-buy math is straightforward at this point. Maintaining 25,000+ pore-clogging ingredient records across three regulatory feeds, plus the synonym graph, plus the quarterly refresh job, typically requires one to two full-time engineers focused on data ops alone — before the application engineers have written a line of UI code. An ingredient database delivered as an API moves that headcount cost out of your budget. The remaining engineering work is the part that actually differentiates your product: the scoring logic, the UX, and the way you handle the edges.
Single-Ingredient Lookup vs. Batch Formulation Analysis: Choosing the Right Endpoint
Every pore clogging ingredient checker maps to one of two API call patterns, and choosing wrong inflates either latency or cost. The decision is architectural, not stylistic.
| Use Case | Input | UX Requirement | Endpoint | Example Application |
|---|---|---|---|---|
| User scans one product label | Single INCI name | Real-time, <200ms | GET /v1/ingredients/{name} | Mobile ingredient scanner |
| Brand auditing 500+ SKUs | Full formulation JSON | Batch job, async OK | POST /v1/analyze | DTC compliance backend |
| E-commerce "acne-safe" badge | Product catalog rows | Weekly refresh acceptable | POST /v1/analyze | Product discovery feature |
| R&D substitution testing | 20 candidate formulas | Iterative, per-formula | POST /v1/analyze | Cosmetics formulator tool |
When GET /v1/ingredients/{name} is correct. Use it for real-time mobile UX where the user scans or types one ingredient at a time. Per Dermalytics' published specs, median latency stays under 100ms, which keeps the interaction feeling instant rather than network-bound. Cache aggressively, keyed by the normalized INCI name — most queries in a deployed scanner will hit the same 200 to 400 ingredients over and over.
When POST /v1/analyze is correct. Use it for whole-formulation scoring, where a typical skincare INCI list runs 10 to 60 ingredients per product. One round-trip instead of N. Sub-second response holds for typical lists. This is the right pattern for any batch formulation analysis workflow: catalog ingestion, brand audits, formulator R&D, e-commerce badge rendering.
Cost behavior under credit-based pricing. Dermalytics charges only on successful matches. A batch call against a 30-ingredient moisturizer where 28 match costs 28 credits, not 30. Mistyped or unrecognized ingredients don't bill. That's a meaningful difference from per-request models used by cosmethics.com or fixed-seat subscription pricing used by skincareapi.dev — particularly if your input stream contains OCR'd text where character-error rates around 5% are normal.
The hybrid pattern most production checkers use. Batch analysis for catalog ingestion (run once per product when a SKU is added or updated), single-ingredient lookups for user-initiated edge queries (the user pastes one ingredient they're curious about). The catalog ingest amortizes well against the 30-day cache; the ingredient lookup API calls handle the long tail. [TBD: internal link]
Data Architecture for a Production-Grade Comedogenicity Pipeline
Four layers sit between the API call and the user-visible risk badge. Skip any of them and the checker degrades in a way that's hard to debug later.
- Parsing API responses into structured fields. A query against the ingredients endpoint returns a structured payload:
comedogenicity_score(integer 0–5),severity_label(one of minimal/mild/moderate/high/severe),irritancy_score(0–5),cas_number,ec_number,synonyms[], andlast_updated. A lookup forisopropyl myristatereturns a high comedogenicity score with a corresponding severity label. Store the full payload — not just the score — because downstream features (allergen warnings, EU compliance flags, ingredient detail pages) will need the rest. Throwing fields away on ingest is the single most common architectural mistake here. - Computing a formulation-level risk score. Three viable methods exist. The simple average of all matched
comedogenicity_scorevalues is the baseline. The concentration-weighted average is correct when the formulation provides percentages, and it handles the rinse-off-versus-leave-on problem cleanly. Threshold escalation is the third layer: any single ingredient with score ≥4 escalates the whole formulation to "high risk" regardless of average. Most production cosmetic ingredient scoring systems combine the second and third — weighted average for the headline number, threshold flag for the warning badge. - Handling unmatchable ingredients gracefully. The API returns a 404 or null for unrecognized names. Track the match rate per formulation. Per Dermalytics' published platform documentation, a 95% or higher match rate is the production benchmark for US and EU products. Surface the rate to the user explicitly: "28 of 30 ingredients matched — score is based on matched ingredients only." Never silently drop unknowns, and never pad the score by assuming the missing ones are safe. Honest gaps are a feature, not a bug.
- Caching and refresh cadence. Cache keyed by normalized INCI name with a 30-day TTL. Use the
last_updatedfield returned by the API to detect stale entries on read — if your cachedlast_updatedis older than the API's current value, evict and re-fetch. The Personal Care Products Council recommends quarterly refreshes for ingredient safety data to incorporate new FDA, CosIng, and Health Canada assessments. Align your background refresh job with that cadence at minimum.
One thing worth wiring up early: log every 404 from the ingredients endpoint. These are your highest-signal data points — they tell you where the catalog has gaps, where your normalization is missing a synonym, or where you should be flagging the issue back to the API provider. Automated ingredient analysis is only as good as the feedback loop you build around its failures.
Building the Checker: From Raw INCI Input to User-Facing Risk Score
Six steps take you from raw label text to a risk badge a user can act on. Each step has a specific failure mode if skipped.
Normalize the ingredient list. Strip percentages (
Glycerin (5%)→glycerin), lowercase everything, remove punctuation, and split on commas. Handle the two common input types separately: OCR'd label text (noisy — expect roughly 5% character error rate) and clean copy-paste lists (typos but no character corruption). Pre-resolve common synonyms client-side — petrolatum to petroleum jelly, cetyl alcohol to hexadecan-1-ol — before hitting the API. A 15-line synonym map eliminates about 5% of needless 404s on day one.

Choose endpoint and dispatch. For a single ingredient:
GET /v1/ingredients/isopropyl%20myristate. For a full formulation, use the batch endpoint:POST /v1/analyze { "formulation": [ { "inci_name": "water", "concentration": 70 }, { "inci_name": "glycerin", "concentration": 5 }, { "inci_name": "isopropyl myristate", "concentration": 2 } ] }Use the official
dermalyticsSDK from npm or PyPI to skip retry, auth, and rate-limit boilerplate. The full OpenAPI 3 contract is published at api.dermalytics.dev — review it before writing any custom HTTP code.Extract scoring fields per ingredient. Iterate the response. For each entry pull
comedogenicity_score,severity_label, andirritancy_score. Maintain two collections during this pass: matched (with scores) and unmatched (for the partial-match disclaimer that will show in the UI). Resist the temptation to merge them — the unmatched set is what drives your product feedback loop.Compute the formulation-level score. Apply the three-layer rule from the architecture section: weighted average if concentrations exist, plain average otherwise, then check for any ingredient with score ≥4 to escalate the band to "high." Output two values — a number (0–5) and a band (low/moderate/high). Both matter: the band drives the badge color, the number drives the sort order if you're showing a list of products.
Render the user-facing result. Show three elements. First, the overall risk band as a colored badge. Second, a ranked list of the top three highest-scoring ingredients with their individual 0–5 scores. Third, a one-line "why" — for example, "Isopropyl myristate scored 4 (high) — a known pore-clogger." Include the match-rate caveat any time it's below 95%: "28 of 30 ingredients matched." Users handle uncertainty fine when you name it; they don't handle silent gaps.

- Cache the response and dedupe future calls. Write the matched-ingredient records to your local store keyed by normalized INCI name. On the next request, check cache first; only call the API for cache misses or for entries older than 30 days. This is what makes credit-based pricing economical at scale. After roughly one week of operation, most queries in a real production skincare app development workflow should be cache hits — the long tail of ingredients is shorter than it looks because the same 300 to 500 ingredients show up across the vast majority of mass-market products.
Handling Edge Cases: Concentration, False Positives, and Proprietary Blends
A checker that works on the happy path and breaks on real formulations isn't shipped — it's a demo. Seven edge cases trip up naïve implementations, and the reasoning behind each is what matters more than the rule.
Concentration changes the verdict. A score-3 ingredient at 0.5% in a rinse-off cleanser is functionally non-clogging; the same ingredient at 15% in a leave-on balm is a real risk. If your input data includes percentages, weight your score accordingly. If it doesn't — and most consumer-facing inputs won't, because brands don't disclose percentages below the 1% threshold required by INCI ordering rules — present the score with a "depends on formulation" caveat. Don't fake precision you can't deliver.
Formulation chemistry is non-linear. Dr. Neha Rangarajan, Cosmetic Chemist and Formulation Scientist, has observed that "ingredient interactions can modify comedogenic potential — like how salicylic acid can mitigate clogging from certain oils" (Cosmetic Science Today). Your checker scores ingredients individually; flag the limitation explicitly in the UI rather than pretending the model captures interaction effects it doesn't.
Comedogenicity is not irritancy. A high-irritancy, low-comedogenicity ingredient — many fragrances and certain preservatives — should not inflate the pore-clogging score. Use the separate irritancy_score field for irritancy warnings. Two different badges, two different explanations. Conflating them produces a checker that flags everything and gets ignored within a week.
Your checker should flag risk, not diagnose skin. A high comedogenicity score is a yellow flag, not a dermatologist's verdict.
"Natural" doesn't mean low-comedogenic. Coconut oil scores 4 because of its fatty-acid profile, not despite being plant-derived. This is the single biggest source of user pushback when "natural" products get flagged — surface it as an educational tooltip the first time a user sees it, not as an apology after the fact.
Proprietary blends and undisclosed fragrance components. A label listing "Fragrance" or "Parfum" hides 50 or more possible compounds under one umbrella term. Query the API for the umbrella term (it returns a generic comedogenicity score, typically low-to-moderate) and surface the disclosure gap in the UI: "Fragrance compounds are not individually disclosed; the score reflects the general category." The honest framing is better than a falsely confident one.
Conflicting data from older blog sources. When a user complains that your API-derived score contradicts what a popular skincare blogger said in 2019, the API is the trustworthy source — it draws from regularly updated FDA, EU CosIng, and Health Canada feeds. Acknowledge that comedogenicity research evolves; don't defend a number as eternal. The right copy here is something like "Ingredient assessments are updated quarterly. Older sources may reflect prior data."
The build-your-own-judgment trap. Researchers at the University of Manchester found that 37% of high-comedogenicity ingredients (scores 4–5) produced no clogging in clinical trials on human volunteers (Skin Research and Technology, 2024). Your checker is a risk indicator, not a diagnostic. Frame the UX to match: it tells the user where to look more carefully, not what their skin will do. A pore clogging ingredient checker that overstates certainty erodes trust faster than one that admits its limits.
Comparing Cosmetic Ingredient APIs for Comedogenicity Use Cases
Not every cosmetic ingredient API exposes a numeric comedogenicity field, and the ones that do differ on batch support, latency, and pricing model. The matrix below evaluates five platforms against the criteria that actually determine fit for a pore clogging ingredient checker.
| Platform | Comedogenicity Field | Batch Analysis | Median Latency | Pricing Model |
|---|---|---|---|---|
| Dermalytics API | Numeric 0–5 | Yes (POST /v1/analyze) | <100ms | Credit-based, pay per match |
| cosmethics.com | Qualitative only | No | 200–500ms | Per-request |
| skincareapi.dev | None (safety only) | No | 500ms–2s | Fixed-seat subscription |
| incidecoder.com | Crowd-sourced | No | Variable | Freemium, limited API |
| api.store | None (general cosmetics) | No | 1–3s | Subscription |
Competitor figures sourced from publicly available product pages and the published comparison on dermalytics.dev; verify directly with each vendor before committing.
Why Dermalytics fits this specific use case. The numeric 0–5 comedogenicity_score is purpose-built for the comedogenicity API problem rather than retrofitted onto a general safety dataset. Batch /analyze lets you score a 30-ingredient formulation in one round-trip instead of 30. Per Dermalytics' published spec, credit-based pricing means mistypes and 404s don't bill — which matters more than it sounds when your input stream is OCR'd text. [TBD: internal link]
When the alternatives are the better pick. Use INCIDecoder if you need crowd-sourced community severity context for a consumer-education product where the discussion thread is part of the value. Use skincareapi.dev if you have a fixed user base and prefer subscription cost predictability over per-match billing. Use cosmethics.com if EU-only coverage and qualitative ratings are sufficient for your market.
Latency math matters for mobile UX. A 500ms-to-2s round-trip on slower alternatives forces aggressive caching or perceptible UI lag — the user pastes an ingredient and watches a spinner. Sub-100ms median latency lets you call on every paste without preloaders. For a real-time ingredient scanner that's the difference between an interaction that feels native and one that feels web-shaped.
Database freshness is the underrated criterion. Static datasets lag regulatory changes. Crowd-sourced datasets lag worse — community contributions cluster around trending ingredients, not regulatory updates. A consolidated FDA + EU CosIng + Health Canada feed is the operational difference between a checker that ages well and one that ships strong, drifts within a year, and has to be replaced.
Implementation Checklist for Shipping Your Pore-Clogging Checker
Before you ship a pore clogging ingredient checker to production, walk this list. Items are ordered by the sequence they tend to break in.
Confirm your input format. OCR'd label text, user-pasted INCI strings, and structured product-catalog rows each need different normalization paths. Pick one as v1 and ship — don't try to handle all three in week one. The OCR path in particular hides character-recognition errors that will surface as 404s and look like API problems when they're really preprocessing problems.
Pre-resolve obvious synonyms client-side. A 15-line synonym map covering the most common alternates — petrolatum/petroleum jelly, cetyl alcohol/hexadecan-1-ol, tocopherol/vitamin E, isopropyl myristate's common variants — eliminates roughly 5% of needless 404s before they cost you a request. This belongs in code, not in the API layer.
Pick your endpoint pattern. Single
GET /v1/ingredients/{name}for real-time UX where the user expects an instant response;POST /v1/analyzefor whole-formulation scoring where you have the full INCI list. Choose based on the matrix earlier in this guide, not based on which call you wrote first. Endpoint choice is hard to retrofit cleanly.Install the official SDK.
npm install dermalyticsorpip install dermalytics. Both wrap authentication, retry logic, and rate-limit handling so you don't reinvent them poorly. Review the OpenAPI 3 spec at api.dermalytics.dev for the full contract — the SDK covers the common path, but the schema is what you reference when you build the less common features.Implement the three-layer scoring rule. Weighted average if concentrations are available, plain average otherwise, threshold escalation if any ingredient scores 4 or higher. Document the rule in code comments so future maintainers don't quietly rewrite it. Six months from launch, someone will propose "simplifying" the scoring; the comment is what stops them.
Surface the match rate. Every result UI must show "N of M ingredients matched." Below 95%, suppress the headline score entirely and show "partial results" instead. Guessing erodes user trust faster than honest gaps, and the threshold is where the math stops being defensible.
Honest gaps build trust. A checker that hides what it doesn't know is the one users stop trusting first.
Separate the comedogenicity badge from the irritancy badge in the UI. Two different badges, two different explanations, two different colors if your design system allows it. They use two different API fields —
comedogenicity_scoreversusirritancy_score— for a reason, and conflating them in the UI undoes the value of the data separation upstream.Cache aggressively with a 30-day TTL. Key by normalized INCI name. Check the
last_updatedfield on read to detect stale entries and evict them. This is what makes credit-based pricing economical at scale — most queries should be cache hits after the first week of operation, and your effective cost-per-query drops toward zero as the cache warms.Log every 404. Unmatched ingredients are your highest-signal product-feedback channel. They tell you where the catalog has gaps, where your normalization is missing a synonym, or where the OCR pipeline is producing garbage. A simple weekly report of the top 20 unmatched names will direct your data-quality work for months.
Add a refresh job aligned with the PCPC quarterly cadence. The Personal Care Products Council recommends quarterly refreshes for ingredient safety data. Cron a re-fetch of cached ingredients older than 90 days so the headline score reflects current regulatory data rather than what was true the day you shipped.
Write the limitation copy before launch. Three sentences the user sees somewhere visible in the result UI: "This is a risk indicator, not a diagnosis. Formulation context, concentration, and your skin type all matter. Patch-test before regular use." Back it with the Skin Research and Technology finding that 37% of clinically high-comedogenicity ingredients produced no clogging in human trials if you want the receipt visible. Limitation copy written after launch always reads defensively; written before, it reads like honesty.
Smoke-test against five known products. One product that's broadly considered safe for acne-prone skin. One known offender — something containing coconut oil or isopropyl myristate at high concentration. One "non-comedogenic" labeled product (test the Consumer Reports finding against your own data). One with a proprietary fragrance blend that will exercise your disclosure-gap UI. And one with a heavy synonym — cetyl alcohol under its IUPAC name, or tocopherol listed as vitamin E — to confirm your normalization layer is doing its job. If all five produce the expected output, you have a checker worth shipping.