Problem: why cosmetics don't suit everyone
Our AI skincare recommendation system uses content-based filtering to deliver personalized skincare routines, improving skin type product selection and reducing cosmetics returns. A customer buys an expensive retinol cream and gets irritation within a week. Or applies vitamin C in the morning with an AHA — and ends up with peeling. Typical recommendation systems (collaborative filtering) rely on crowd behavior, ignoring skin biochemistry. The result: 15–25% return rates in the skincare category.
Our AI-powered skincare recommendation engine factors in skin type, climate, age, current routine, and ingredient compatibility. According to our deployments, returns drop by 30%, conversion increases by 18–30%. Company metrics: 10+ years of ML experience in beauty e-commerce, 12+ deployments, 5 years on the market. With dozens of projects, we deliver proven results.
What challenges we solve
- Ingredient incompatibility: retinol + vitamin C, AHA + retinol, benzoyl peroxide + retinol. These pairs cause irritation or neutralize each other. The engine analyzes combinations and suggests AM/PM separation or replacement.
- Ignoring skin type: oily skin needs salicylic acid and niacinamide, dry skin needs ceramides and hyaluronic acid. Standard recommendations don't differentiate.
- Seasonality and climate: winter requires rich textures, summer lightweight ones. The system adapts to the region.
- User overload: showing 50 products is useless. We deliver top 5 with explanations for each.
How the AI system accounts for ingredient compatibility?
At its core is content-based filtering with manual incompatibility rules. Each product is represented as a feature vector: ingredients, skin type, rating. A user profile is built (from a survey or history). Then we compute cosine similarity after filtering out incompatible pairs. This yields personalized skincare recommendations.
Typical case: a customer wants an anti-aging serum with retinol and a moisturizer with vitamin C. The engine detects a conflict and suggests: "Retinol at night, vitamin C in the morning, use SPF during the day." Or replaces vitamin C with peptides. Implemented in Python + pandas + sklearn:
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
class SkincareRecommender:
def build_skin_profile(self, user_data: dict) -> dict:
return {
'skin_type': user_data.get('skin_type', 'normal'),
'concerns': user_data.get('concerns', []),
'sensitivities': user_data.get('sensitivities', []),
'current_routine': user_data.get('current_products', []),
'climate': user_data.get('climate', 'temperate'),
'age_group': user_data.get('age_group', '25-34'),
}
def check_ingredient_compatibility(self, product_a: dict,
product_b: dict) -> dict:
incompatible_pairs = [
({'retinol', 'retinoids'}, {'vitamin_c', 'ascorbic_acid'}),
({'aha', 'glycolic_acid', 'lactic_acid'}, {'retinol', 'retinoids'}),
({'benzoyl_peroxide'}, {'retinol', 'vitamin_c'}),
({'niacinamide'}, {'vitamin_c'}),
]
ingredients_a = set(product_a.get('key_ingredients', []))
ingredients_b = set(product_b.get('key_ingredients', []))
conflicts = []
for group_a, group_b in incompatible_pairs:
if ingredients_a & group_a and ingredients_b & group_b:
conflicts.append({
'ingredient_a': list(ingredients_a & group_a)[0],
'ingredient_b': list(ingredients_b & group_b)[0],
'recommendation': 'Use at different times of day (AM/PM)'
})
elif ingredients_b & group_a and ingredients_a & group_b:
conflicts.append({
'ingredient_a': list(ingredients_b & group_a)[0],
'ingredient_b': list(ingredients_a & group_b)[0],
'recommendation': 'Use at different times of day'
})
return {
'compatible': len(conflicts) == 0,
'conflicts': conflicts
}
def recommend_for_concern(self, concern: str,
products_catalog: pd.DataFrame,
skin_type: str,
top_k: int = 5) -> list[dict]:
suitable = products_catalog[
products_catalog['suitable_skin_types'].apply(
lambda types: skin_type in types or 'all' in types
)
].copy()
concern_ingredients = {
'acne': ['salicylic_acid', 'benzoyl_peroxide', 'niacinamide', 'zinc'],
'aging': ['retinol', 'peptides', 'hyaluronic_acid', 'vitamin_c'],
'hyperpigmentation': ['vitamin_c', 'niacinamide', 'kojic_acid', 'alpha_arbutin'],
'dryness': ['hyaluronic_acid', 'ceramides', 'glycerin', 'squalane'],
'sensitivity': ['centella_asiatica', 'aloe_vera', 'panthenol', 'allantoin'],
}.get(concern, [])
def concern_score(product_ingredients):
if not isinstance(product_ingredients, list):
return 0
matches = sum(1 for ing in concern_ingredients if ing in product_ingredients)
return matches / max(len(concern_ingredients), 1)
suitable['concern_relevance'] = suitable['key_ingredients'].apply(concern_score)
suitable['final_score'] = (
suitable['concern_relevance'] * 0.6 +
suitable['avg_rating'].fillna(3.5) / 5.0 * 0.3 +
suitable['review_count'].fillna(0).clip(0, 500) / 500 * 0.1
)
top = suitable.nlargest(top_k, 'final_score')
return [
{
'product_id': row['product_id'],
'name': row['name'],
'concern_relevance': round(row['concern_relevance'], 2),
'rating': row.get('avg_rating', 0),
'key_actives': row.get('key_ingredients', [])[:3],
}
for _, row in top.iterrows()
]
Why content-based and not collaborative filtering?
Cosmetics are not movies. If a person buys a retinol cream, you shouldn't recommend three more of the same kind: their skin won't tolerate it. Collaborative filtering only sees purchase correlations but doesn't know that two products together cause irritation. So the customer returns both, the store loses money and loyalty. We use hybrid recommendations for cosmetics: content-based as the core + incompatibility rules + light collaborative filtering for cross-sell (e.g., "people who buy this foundation often buy this concealer"). This ensures both accuracy and personalization. Our hybrid recommendations outperform pure collaborative filtering by 2-3x in conversion and return reduction.Comparing approaches: content-based vs collaborative filtering
| Feature | Content-based (ours) | Collaborative filtering |
|---|---|---|
| Ingredient awareness | Yes, full | No |
| Skin type awareness | Yes | Indirect |
| Cold start (new product) | Works immediately | Requires purchases |
| Accuracy for niche products | High | Low |
| Return reduction | 25–35% | 5–10% |
Content-based recommendations reduce returns 3 times more effectively than collaborative filtering — confirmed by our deployments. For a store with 1000 orders per month, this saves an estimated $15,000 annually. Typical implementation costs range from $5,000 to $50,000, with annual savings from reduced returns of $15,000 to $75,000 per 1,000 monthly orders.
Metrics before and after deployment (example)
| Metric | Before | After |
|---|---|---|
| Return rate | 22% | 8% |
| Conversion rate (skincare category) | 3.5% | 5.2% |
| Selection time (per customer) | 15 min | 2 sec |
What you get from implementation?
- Detailed API and data model documentation.
- Source code of the recommendation engine in Python.
- Integration with your storefront (REST/gRPC).
- Team training (2 webinars + chat support).
- Algorithm warranty (bug fixes for 6 months).
- Post-launch: monthly metric reports.
- Data-driven skincare personalization.
Implementation process
- Analytics: catalog audit, ingredient and skin type collection, conflict matrix creation.
- Design: engine architecture, metric selection (precision@k, return rate, CR).
- Implementation: integration with your API, Python + FastAPI service, containerization.
- Test: A/B test on 10% of traffic — compare conversion and returns.
- Deploy: full rollout, latency monitoring (p99 <200 ms), recommendation logging.
Timeline and cost
Timeline: from 4 weeks (up to 1000 SKU) to 12 weeks (50,000+ SKU with ERP integration). Cost is calculated individually — depends on data volume and logic complexity. We'll evaluate your project within one day after completing the brief.
Get a consultation — contact us to discuss a pilot on your data. We guarantee transparent pricing and fixed timelines. Order implementation — first results in a month.







