@cosme Japan Beauty Rankings — Rating, Review & Price Stats avatar

@cosme Japan Beauty Rankings — Rating, Review & Price Stats

Pricing

from $20.00 / 1,000 category ranking summaries

Go to Apify Store
@cosme Japan Beauty Rankings — Rating, Review & Price Stats

@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

h ichi

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

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 top
  • priceJpy — 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 apart
  • brandTop / 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 frozen
  • bestCosmeCount, variantsPerProductMedian, and the ranking's own rankingUpdatedOn and aggregationPeriod
  • 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 collectedWhy
Review bodies (the text people write)It is user-authored personal content. Statistics do not need it
Reviewer names, ages, skin types, profile pagesPersonal data about individuals who are not the subject of this product
Review photosSame — user-uploaded personal content
Review permalinks and the product's /review/ tab URLEmitting the link is emitting the pointer. No record ever contains a .../review/ URLurl 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

EventPriceWhen
Category ranking summary$0.02Per category that produced products
Individual product$0.002Only 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

FieldExampleNotes
categories["item/1069"]<axis>/<id>, axis ∈ item / effect / skin / age / pickup. A full ranking URL is accepted and normalized. Each category costs $0.02
pagesPerCategory510 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
includeIndividualItemsfalseEnable to also get each ranked product as a record (+$0.002 each)
convertToUsdtrueAdds 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: 7 so 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 rankingUpdatedOn and aggregationPeriod. 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. productsRanked is 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 in priceJpy, because a product that also sells an 850 ml bottle is not "more expensive" than one that only sells 100 ml. priceVariantCount tells 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: null and are excluded from priceJpy, which is why priceJpy.count (42 above) can be lower than productsRanked (50). Nothing is invented to fill the gap.
  • Prices are the tax-included list prices @cosme publishes (priceLabelJa records 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 as unknown rather than folded into stay.
  • bestCosme flags 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.