@cosme Japan Beauty Rankings — Rating, Review & Price Stats
Pricing
from $20.00 / 1,000 category ranking summaries
@cosme Japan Beauty Rankings — Rating, Review & Price Stats
The @cosme ranking of any Japanese cosmetics category in one call: every ranked product with its 0-7 rating, review count, price points and release date, plus rating and price quartiles, brand concentration, rank movement and awards. Review text is never collected. アットコスメのランキング統計を1コールで。
Pricing
from $20.00 / 1,000 category ranking summaries
Rating
0.0
(0)
Developer
h ichi
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
@cosme Japan Beauty Rankings — Rating, Review-Count & Price Stats in One Call
Which Japanese cosmetics are ranking right now, at what price and at what rating? One call per category answers it with the whole top 50 of the @cosme ranking — the ranking Japanese beauty buyers actually shop off — plus the aggregate distribution behind it.
@cosme is Japan's dominant beauty review platform, and its category rankings are the closest thing the market has to a public demand signal. This Actor turns one ranking into one compact market record:
rating— min / Q1 / median / Q3 / max on @cosme's 0–7 scale, so you can see whether a category is a tight field of 5.1s or has a real quality gap at the toppriceJpy— the same quartiles over each product's cheapest listed size, plus USD at the current rate. What price point is winning this category?reviewCount— median and maximum review counts. The distinction between a 2002 staple with 8,727 reviews and a 2026 launch with 17 sitting three ranks apartbrandTop/brandCount/topBrandShare— brand concentration: is the category owned by one house or contested by 42?rankMovement— how many of the ranked products moved up, stayed, fell or are new entries. The mix tells you whether the category is churning or frozenbestCosmeCount,variantsPerProductMedian, and the ranking's ownrankingUpdatedOnandaggregationPeriod- Optionally every ranked product (rank, movement, brand, rating, review count, every size/price pair, release date, best-cosme flag, product URL)
Built for brands benchmarking their own position and cross-border beauty resellers deciding what to stock: the ranking is what sells in Japan, and this Actor gives you the price and rating level it sells at.
No login, no API key, nothing stored between runs.
⚠️ What this Actor deliberately does not collect
@cosme is a review site, so this needs saying plainly:
Review text, reviewer names, reviewer profiles and review photos are never collected — by design, permanently.
| Not collected | Why |
|---|---|
| Review bodies (the text people write) | It is user-authored personal content. Statistics do not need it |
| Reviewer names, ages, skin types, profile pages | Personal data about individuals who are not the subject of this product |
| Review photos | Same — user-uploaded personal content |
Review permalinks and the product's /review/ tab URL | Emitting the link is emitting the pointer. No record ever contains a .../review/ URL — url is always the product page |
What is collected is the review count — a number — and the aggregate rating value. That is the entire review-side footprint of this Actor.
This is not a promise in prose, it is enforced in code. src/main.py carries a DELIBERATE EXCLUSION block and an executable guard, review_text_leaks(record), which scans every value of an emitted record for the review markers (review-body, review-text, reviewer-desc, /reviewer/, /review/, /reviews/) and returns the ones it finds. The test suite asserts it returns [] for every emitted record shape. If a future change ever tag-strips a whole product block or copies the review-tab link, the markers come along with it and the build fails. Every field is read out of the single HTML element that carries its class token — a review body has no path into a record even by accident.
Pricing — from $0.02 per category, no subscription
| Event | Price | When |
|---|---|---|
| Category ranking summary | $0.02 | Per category that produced products |
| Individual product | $0.002 | Only if you enable Include individual products |
A default run (1 category, whole top 50, summary only) costs $0.02. With individual products on it is $0.02 + 50 × $0.002 = $0.12. A category that returns nothing is never charged.
Input
| Field | Example | Notes |
|---|---|---|
categories | ["item/1069"] | <axis>/<id>, axis ∈ item / effect / skin / age / pickup. A full ranking URL is accepted and normalized. Each category costs $0.02 |
pagesPerCategory | 5 | 10 products per page; the ranking is only 50 deep, so 5 is the whole thing and the maximum. Lower it for a fast top-10 read |
includeIndividualItems | false | Enable to also get each ranked product as a record (+$0.002 each) |
convertToUsd | true | Adds USD price stats at the current exchange rate |
Finding a category id
Open any @cosme ranking in a browser and copy the URL: https://www.cosme.net/categories/item/1069/ranking/ → item/1069. The item axis is the product-type ranking (cleansers, serums, lipsticks…); effect, skin, age and pickup are @cosme's other ranking axes and all work the same way.
Only the main ranking is read. If you paste a ranking-rise (急上昇), ranking-age (年代), ranking-skin (肌質) or ranking-search (お好み) URL the run fails with a clear message instead of quietly billing you for the plain ranking, which is a different result set with a different aggregation window.
Output example (type: "category_summary")
Measured on item/1069 (リキッドクレンジング / liquid cleansers), 2026-08-01:
{"type": "category_summary","category": "item/1069","categoryName": "リキッドクレンジング","rankingUpdatedOn": "2026-07-31","aggregationPeriod": { "from": "2026-04-30", "to": "2026-07-29", "raw": "2026/4/30〜2026/7/29" },"productsRanked": 50,"totalListingsFound": 50,"pagesFetched": 5,"ratingScale": 7,"rating": { "min": 3.7, "q1": 4.9, "median": 5.1, "q3": 5.4, "max": 6.9, "count": 50 },"priceJpy": { "min": 352, "q1": 1463, "median": 1760, "q3": 3242, "max": 7260, "count": 42 },"reviewCount": { "median": 186, "max": 8727, "count": 50 },"brandTop": [["ビオデルマ", 4], ["Chacott COSMETICS(チャコット・コスメティクス)", 2], ["ビフェスタ", 2]],"brandCount": 42,"topBrandShare": 0.08,"rankMovement": { "up": 8, "stay": 21, "down": 19, "new": 2, "unknown": 0 },"bestCosmeCount": 2,"variantsPerProductMedian": 1,"checkedAt": "2026-08-01T05:41:12.884Z","sourceUrl": "https://www.cosme.net/categories/item/1069/ranking/","priceUsd": { "min": 2.3, "q1": 9.55, "median": 11.49, "q3": 21.17, "max": 47.41 },"exchangeRateJpyUsd": 0.00653}
And one optional product record (type: "product") — note that url is the product page and every size/price pair is kept:
{"type": "product","category": "item/1069","categoryName": "リキッドクレンジング","rank": 1,"rankMovement": "stay","rankMovementJa": "順位変わらず","productId": "2892367","name": "サンシビオ エイチツーオー D","brand": "ビオデルマ","brandId": "4680","ratingScale": 7,"rating": 5.4,"reviewCount": 8727,"minPriceJpy": 1463,"priceVariants": [{ "size": "100ml", "priceJpy": 1463 },{ "size": "250ml", "priceJpy": 3069 },{ "size": "500ml", "priceJpy": 3810 },{ "size": "850ml", "priceJpy": 5060 }],"priceVariantCount": 6,"priceLabelJa": "税込価格","releaseDate": "2002-07-05","releaseDateRaw": "2002/7/5","bestCosme": true,"url": "https://www.cosme.net/products/2892367/"}
Notes on the data
- The rating scale is 0–7, not 0–5. @cosme rates on seven points, so a 5.4 is a strong product, not an impossible one. Every record carries
ratingScale: 7so you cannot compare it against a five-star rating from another site by accident. (To rescale to 5 points:rating / 7 * 5.) - The aggregation window is part of the answer. @cosme recomputes each ranking on a rolling ~3-month window and publishes both dates in the page header; both are on every record as
rankingUpdatedOnandaggregationPeriod. Two rankings are only comparable when their windows are — a snapshot without them is not interpretable, which is why they are never omitted. - The ranking is 50 deep. That is the whole population, not a sample.
productsRankedis normally exactly 50 (10 per page × 5 pages), so the quartiles are the true quartiles of the ranked set rather than an estimate. There is no page 6. - One product, many prices. A Japanese cosmetic is usually sold in several sizes on one line (「税込価格:100ml・1,463円 / 250ml・3,069円 / 500ml・3,810円」). All pairs are parsed;
minPriceJpy— the cheapest listed size — is the representative price used inpriceJpy, because a product that also sells an 850 ml bottle is not "more expensive" than one that only sells 100 ml.priceVariantCounttells you how many sizes there were. - Not every product has a price. Open-price products (「オープン価格」) and refill-only lines carry a size with no yen amount; they keep
priceJpy: nulland are excluded frompriceJpy, which is whypriceJpy.count(42 above) can be lower thanproductsRanked(50). Nothing is invented to fill the gap. - Prices are the tax-included list prices @cosme publishes (
priceLabelJarecords the site's own label), not shop prices and not sold prices. - Rank movement is @cosme's own icon:
up(including its 「10位以上順位アップ」 variant),stay,down,new(ランキング初登場). An unrecognized icon is reported asunknownrather than folded intostay. bestCosmeflags products carrying the ベストコスメ award badge on the ranking page.- Brand names are read from the brand link only. Brands with a paid tie-up carry a second link whose text is a notice; it is excluded, so one brand stays one entry in
brandTop. - Encoding: @cosme serves Shift_JIS, which is decoded explicitly. Japanese brand, product and category names come through intact.
What this Actor does not do
- No review text, ever. See the section above — this is the product's hard constraint, not a limitation
- No product dumps by default. The product is the statistic; individual products are opt-in and separately priced
- No login-only data and no
/api/paths. Everything comes from public ranking pages; the paths @cosme disallows in robots.txt are never requested - No stored dataset. Every run fetches live; nothing is retained between runs
- No browser. Plain HTTP, 256 MB, a run stays well inside 120 s
Reliability
Requests are throttled to 1.5 s and a soft 95 s wall-clock budget keeps a multi-category run inside its timeout. Page 1 of every category always runs, so every category produces a summary; if the budget stops the follow-up pages, the affected summary says so with truncatedForTimeLimit: true and a smaller pagesFetched — a top-10 read is never passed off as the full top 50. If every category fails the run fails loudly rather than returning an empty success.