Skip to main content

Dermalytics Python SDK

Search cosmetic products and ingredients, retrieve INCI lists, and analyze ingredient data with a typed Python client.

Documentation · Get an API key · OpenAPI

Install

pip install dermalytics

Requires Python 3.8 or later. Keep your API key in an environment variable rather than in source code.

Try without an API key

from dermalytics import Dermalytics

client = Dermalytics()
matches = client.search_ingredients("Niacinamide")
print(matches["data"])

Try the REST API without an API key: 5 requests per IP address in a 24-hour window, starting with the first request. Search returns up to 3 results, with no pagination; analysis accepts up to 5 ingredient names. The quota is shared across all REST data methods. Empty results and invalid requests that reach the API also use an attempt.

Responses keep the same fields. Without an account, credits_remaining is 0; it is not your free-request balance. HTTP headers X-Free-Requests-Remaining and X-Free-Requests-Reset report the remaining attempts and reset time (Unix seconds). HTTP 429 includes Retry-After. Get a key from the dashboard for full access and 100 welcome credits. Supplying an invalid key returns an authentication error; it never falls back to free access. Shared IP addresses share a quota; IPv6 addresses within a /64 share one bucket.

After the second keyless request, client.signup_url contains the registration URL. When the quota is exhausted, RateLimitError also includes the link in its message. The SDK does not open a browser or print unsolicited messages.

Use an API key

Set DERMALYTICS_API_KEY in your environment, then run:

import os
from dermalytics import Dermalytics

client = Dermalytics(api_key=os.environ["DERMALYTICS_API_KEY"])

page = client.search_products("cream", ingredient="Niacinamide", limit=5)

for product in page["data"]:
    print(product["id"], product["name"], product["brand"])

if page["data"]:
    product = client.get_product(page["data"][0]["id"])
    print(product["ingredients"])
    print("Credits remaining:", product["credits_remaining"])

The examples below use this client. Its default base URL is https://api.dermalytics.dev; set base_url in the constructor to use another deployment. Requests are synchronous and use a 30-second HTTP timeout.

Methods and credits

Responses are dictionaries with type annotations. Successful responses include credits_remaining.

Method Returns Credits
search_ingredients(query, *, limit=None, offset=0) IngredientSearchResponse 1 per non-empty page
get_ingredient(name) Ingredient 1 per successful lookup
search_products(query, *, limit=None, offset=0, brand=None, ingredient=None) ProductSearchResponse 1 per non-empty page
get_product(product_id) ProductResponse 1 per successful lookup
analyze_product(ingredients) ProductAnalysis 1 per matched ingredient row

For requests with an API key, empty search pages, missing records and validation errors do not consume credits. Product lookup accepts a UUID returned by product search.

Search ingredients

matches = client.search_ingredients("niacinamide", limit=10)
by_cas = client.search_ingredients("98-92-0")
ingredient = client.get_ingredient("Niacinamide")

print(matches["data"])
print(by_cas["data"])
print(ingredient["functions"], ingredient["trait_flags"])

Search products and paginate

query = "cream"
first_page = client.search_products(
    query, brand="CeraVe", ingredient="Niacinamide", limit=10
)

# Fetch one additional page when needed. Each non-empty page costs 1 credit.
next_offset = first_page["pagination"]["next_offset"]
if next_offset is not None:
    next_page = client.search_products(
        query,
        brand="CeraVe",
        ingredient="Niacinamide",
        limit=10,
        offset=next_offset,
    )
    print(next_page["data"])

Search queries contain 2–100 characters. Ingredient search matches names and synonyms by case-insensitive substring, or CAS/EC numbers exactly. Product search matches product names and brands by case-insensitive substring.

Option Default Accepted values
limit 20 with a key; 3 without Integer from 1 to 50 with a key; 1 to 3 without
offset 0 Integer from 0 to 10,000 with a key; 0 without
brand Omitted Exact brand, case-insensitive; 1–255 characters
ingredient Omitted Exact ingredient name or known synonym, case-insensitive; 1–255 characters

brand and ingredient apply only to product search. Results are ordered by name, then ID. Each page has data, pagination (limit, offset, next_offset) and credits_remaining. A null next_offset means there is no next page within the supported offset range. Requests are never automatically paginated or retried.

Analyze an ingredient list

analysis = client.analyze_product(["Water", "Glycerin", "Niacinamide"])

for ingredient in analysis["ingredients"]:
    if not ingredient["found"]:
        print("Not found:", ingredient["name"])
        continue
    print(ingredient["name"], ingredient["comedogenicity"], ingredient["irritancy"])

print("Credits remaining:", analysis["credits_remaining"])

To analyze a stored product composition, pass [item["name"] for item in product["ingredients"]] to analyze_product. Check that the list is non-empty before calling it. Product lookup and analysis are separate paid operations.

Product fields

Product search returns these fields for each result. Product lookup returns the same fields plus the stored ingredient list.

Field Meaning
id Product UUID; pass it to product lookup
name Product name
brand Brand, or null
category Category name, or null
area face, eyes, lips, body, hair, nails, or null
ingredients_count Number of linked ingredients
traits_cache Stored product trait tags
key_ingredient_tags Stored key-ingredient tags
ingredients Lookup only: entries with id, name and nullable position

Only active products are returned. A product lookup response also includes credits_remaining. Null values mean the information is unavailable; an empty ingredient list means no linked composition is available. Tags describe stored metadata, not independently verified product claims.

Ingredient and analysis fields

Ingredient search returns id, name, cas_no, ec_no, functions, ratings_available and record_updated_at. The availability flags indicate whether comedogenicity and irritancy ratings exist. The timestamp records a database update, not a formulation verification date.

Ingredient lookup returns name, severity, category, synonyms and credits_remaining, together with these detail fields:

  • comedogenicity, irritancy: nullable ratings from 0 to 5.
  • formula, molecular_weight, cas_no, ec_no, ph_eur_name: nullable identifiers and chemical metadata.
  • functions, trait_flags: lists of cosmetic functions and ingredient tags.
  • description: nullable text; currently returned as null.

Analysis returns safety_status, ingredients and credits_remaining. Each ingredient row contains name, found, severity, category and the detail fields above. Severity values are safe, low_risk, moderate_risk and high_risk. Check found and the nullable ratings when interpreting results: a missing record or rating is not evidence of safety.

The SDK returns only documented fields, including nested records. The OpenAPI specification defines the HTTP response schemas.

Handle errors

from dermalytics import DermalyticsError, InsufficientCreditsError, NotFoundError

try:
    ingredient = client.get_ingredient("Niacinamide")
    print(ingredient["name"])
except InsufficientCreditsError:
    print("Add credits in the dashboard before continuing.")
except NotFoundError:
    print("No ingredient matched that name.")
except DermalyticsError as error:
    print(error.message)
Error When it occurs
ValidationError Invalid SDK input or HTTP 400
AuthenticationError HTTP 401 or 403
InsufficientCreditsError HTTP 402
NotFoundError HTTP 404
RateLimitError HTTP 429, including the free-request limit
APIError Network failure, invalid response or another HTTP error, including 503 when the catalog is unavailable

All SDK errors inherit from DermalyticsError. A failed network request can have reached the server and consumed credits; check the balance before retrying a paid operation.

Type hints

The package includes TypedDict response definitions and a py.typed marker for type checkers. Values remain ordinary Python dictionaries.

from dermalytics import ProductSearchResponse

page: ProductSearchResponse = client.search_products("cream", limit=5)
for product in page["data"]:
    print(product["name"])

See all response types for ingredient lookup, analysis, product details and pagination.

Develop

Use a Python version compatible with the development tools in requirements.txt.

python -m venv .venv
source .venv/bin/activate
pip install -e . -r requirements.txt
pytest
mypy dermalytics
python -m build

Resources

Metadata

Release files for dermalytics 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dermalytics 1.0.0
File Size Uploaded Provenance Actions
dermalytics-1.0.0.tar.gz 18.8 kB Without provenance Details for dermalytics-1.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for dermalytics 1.0.0
File Interpreter ABI Platform Actions
dermalytics-1.0.0-py3-none-any.whl Python 3 none any Details for dermalytics-1.0.0-py3-none-any.whl

Total release size: 30.8 kB

Release files / dermalytics-1.0.0.tar.gz

Download URL dermalytics-1.0.0.tar.gz
Size 18.8 kB
Tags Source
SHA-256 checksum
How to use checksums
8a4bb4ebaad87f2399619cb6a451379e2e2dcd157cdd1b016c2fa10623e58a9e
BLAKE2b-256 checksum
How to use checksums
c1888fe49db7869d698eb119eebe7c5e5576f0a16bceba7f0ccd17c9419c7f0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.16

Release files / dermalytics-1.0.0-py3-none-any.whl

Download URL dermalytics-1.0.0-py3-none-any.whl
Size 12.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3278d48a1374ef2553fef7999129f745955748eaa446991b47b2ca311d5508ce
BLAKE2b-256 checksum
How to use checksums
8aa90b2b0e6a8ea7aa3e17e236d3da9282ccdb5a1e6214f1ebd6114a54664ed9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.16

Security for dermalytics 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page