Sephora Scraper - Products, SKUs, Reviews & 21+ Stores
Pricing
from $1.00 / 1,000 results
Sephora Scraper - Products, SKUs, Reviews & 21+ Stores
From $1/1K. Scrape Sephora products across 21+ storefronts (US, AU, NZ, SG, MY, ID, TH, PH, MX, DE, RO, SE, GR, DK) with a unified schema. Extract brand, title, ingredients, claims, full SKU and shade variants, ratings histogram, top reviews, Q&A, and rich media.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
9
Total users
3
Monthly active users
9 days ago
Last modified
Categories
Share
Sephora Scraper: Product Catalog, Variants, Prices & Reviews
Sephora Scraper turns 14 regional Sephora storefronts into one clean product data feed. Get brand, title, ingredients, claims, the full variant matrix with every shade, size and SKU, pricing and discount fields, ratings, top reviews and top questions and answers, all normalized into a single output shape. Search by keyword or category, paste a URL, or track the Sale collection, then export to JSON, CSV or Excel, or read the results through the API.
Why This Scraper?
- 14 regional storefronts, one input form. United States, Australia, New Zealand, Singapore, Malaysia, Indonesia, Thailand, Philippines, Mexico, Germany, Romania, Sweden, Greece and Denmark, all normalized to the same output shape.
- Three ways to find products. Search by keyword, browse by category slug, or paste any Sephora product, category, brand or search URL and let the scraper detect the storefront.
- Full product detail on demand. Switch on the product detail fetch for ingredients, how-to-use text, claims and, on the US and Southeast Asia storefronts, the complete variant matrix (every shade, size, SKU and UPC). Leave it off for a search-results-only run so you only pay for the fields you actually use.
- Ratings and voice of the customer. Pull the rating histogram, top reviews (with skin type and skin tone tags where available) and top questions and answers, each capped by you.
- Built-in discount tracking. Every record carries
isOnSpecial,wasPrice,savingsAmountandsavingsPercent, always present, never guessed. A non-discounted product gets an explicitfalse/nullrather than a missing field. - Resilient long walks. Forward-paginated result walks checkpoint themselves and resume automatically after a platform restart, and a delta-resume option skips everything a previous run already collected.
- Built for monitoring. Incremental mode classifies every product as NEW, UPDATED or UNCHANGED against the previous run's state, so a recurring schedule returns only what changed.
Use Cases
- Retail price and assortment monitoring: track price, stock status and the Sale collection across storefronts and currencies.
- Beauty affiliate and comparison sites: pull brand, description, ingredients and claims to build product pages without manual entry.
- Review and sentiment research: collect top reviews with skin type and skin tone context, plus the ratings histogram, for a brand's own SKUs or its competitors.
- Variant and shade planning: build a full shade, size and SKU matrix per product for merchandising or QA.
- Recurring monitoring: schedule the actor and use Incremental mode to see only new, changed or discontinued products since the last run.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
market | "sea-nz" |
source.id / source.canonicalUrl | 500000001 / "https://www.sephora.nz/products/sample-foundation" |
source.currency / source.locale | "NZD" / "en-NZ" |
brand | "Sample Brand" |
title / subtitle | "Sample Foundation" / "30ml" |
description | "<p>A self-priming foundation, primes, covers and sets...</p>" |
ingredients | "Aqua, Cyclopentasiloxane, Glycerin, ..." |
howToUse | "Shake well. Apply a small amount onto the back of your hand..." |
claims | ["Cruelty free", "Paraben free", "Vegan"] |
currentSku | "0000000" |
price.current / price.original | 18.0 / 36.0 |
categories | ["Makeup", "Face", "Foundation"] |
options[].values[].value | "1 Fair Neutral" |
variants[].sku / variants[].shade | "0000000" / "1 Fair Neutral" |
variants[].price.current / variants[].price.original | 18.0 / 36.0 |
variants[].price.stockStatus | "IN_STOCK" |
medias[].url | "https://image.example.com/products/sample-zoom.jpg" |
stats.rating / stats.reviewCount | 4.8 / 971 |
ratingHistogram | [{"RatingValue": 5, "Count": 700}, ...] (when reviews are on) |
topReviews[].rating / topReviews[].body | 5 / "Best foundation I have ever tried..." (when reviews are on) |
topQuestions[].question | "Is this product fragrance free?" (when Q&A is on) |
isOnSpecial / wasPrice / savingsAmount / savingsPercent | true / 36.0 / 18.0 / 50 |
soldOut | false |
frontend | "sea" (also "us" or "scc" on a detail-enriched record; on a search-results-only record, the storefront's own code, e.g. "fr", "me", "mx", "br") |
scrapedAt | "2026-01-01T00:00:00.000Z" |
The table above shows a detail-enriched Southeast Asia record. The shape varies by storefront and by whether details were fetched. With Fetch product details off, a record only carries the search-results fields: market, source, brand, title, top-level price, a priceText, thumbnail, rating, reviewCount, isNewArrival, soldOut, frontend and scrapedAt; it has no description, ingredients, howToUse, claims, options, variants or stats. Detail-enriched records from the European storefronts (Germany, Romania, Sweden, Greece, Denmark, plus France, Italy, Spain, Portugal, Poland and Brazil in url mode) have no variants, options, claims or subtitle. claims and subtitle are only produced for the Southeast Asia storefronts.
When Incremental mode is on, every record also carries changeType (NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED), changedFields (the list of top-level fields that changed on an UPDATED record), and firstSeenAt/lastSeenAt timestamps; these four fields are absent on every normal (non-incremental) run.
How to Use
- Pick a mode:
search(choose a storefront, then fill in keywords or category slugs) orurl(paste one or more Sephora links; the scraper detects the storefront from the host). - In search mode, narrow the results with the optional filters (brand, price range, minimum rating, new arrivals, exclusives). These filters also apply to a pasted category or search URL in url mode, but not to a single pasted product URL, which always returns that exact product.
- Switch on product details, reviews and Q&A for the fields you need, and set Max products (and optionally Max pages) to control the size and cost of the run.
- Set the connection to a residential proxy pinned to the storefront's country, then click Start. Download the dataset as JSON, CSV or Excel, or read it through the API.
The storefront dropdown covers the 14 sites above. Paste a URL from a Sephora site the dropdown does not list, such as France, Italy, Spain, Portugal, Poland, Brazil or the Middle East (UAE, Saudi Arabia, Qatar, Kuwait), and URL mode still detects the storefront from the link. Top reviews and top Q&A are only populated on the US storefront and the Southeast Asia storefronts today; other storefronts leave those fields empty even with the switches on.
Search by keyword:
{"mode": "search","storefront": "us","queries": ["foundation", "mascara"],"maxPages": 5,"maxProducts": 100,"fetchDetails": true,"proxyConfiguration": {"useApifyProxy": true,"apifyProxyGroups": ["RESIDENTIAL"],"apifyProxyCountry": "US"}}
Search by category, with filters, reviews and Q&A:
{"mode": "search","storefront": "nz","categories": ["shop/skincare"],"ratingMin": 4,"maxPages": 3,"maxProducts": 60,"fetchDetails": true,"fetchReviews": true,"maxReviewsPerProduct": 10,"fetchQna": true,"maxQnaPerProduct": 5,"proxyConfiguration": {"useApifyProxy": true,"apifyProxyGroups": ["RESIDENTIAL"],"apifyProxyCountry": "NZ"}}
Specials (Sale collection, Southeast Asia storefronts):
{"mode": "search","storefront": "com.au","specialsOnly": true,"maxPages": 3,"maxProducts": 60,"proxyConfiguration": {"useApifyProxy": true,"apifyProxyGroups": ["RESIDENTIAL"],"apifyProxyCountry": "AU"}}
URL mode (single product):
{"mode": "url","urls": ["https://www.sephora.nz/products/rare-beauty-true-to-myself-natural-matte-longwear-foundation"],"fetchDetails": true,"fetchReviews": true,"fetchQna": true,"proxyConfiguration": {"useApifyProxy": true,"apifyProxyGroups": ["RESIDENTIAL"],"apifyProxyCountry": "NZ"}}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/sephora-product-scraper").call(run_input={"mode": "search","storefront": "us","queries": ["foundation"],"maxProducts": 20,})for product in client.dataset(run["defaultDatasetId"]).iterate_items():print(product["brand"], product["title"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/sephora-product-scraper').call({mode: 'search',storefront: 'us',queries: ['foundation'],maxProducts: 20,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Specials, was-price and discount
Sephora's Southeast Asia storefronts (Australia, New Zealand, Singapore, Malaysia, Indonesia, Thailand, Philippines) have exactly one discount collection, the site's own "Sale" page. Set specialsOnly: true to scrape it. The Sale collection does not combine with queries or categories, so those inputs are ignored while it is on and the whole Sale collection is scraped instead. specialsOnly only affects those Southeast Asia storefronts; on any other storefront it is a no-op and your normal queries or categories run as usual.
Every product record, whether from a normal search, a URL, or a specialsOnly run, carries four additive, always-present discount fields: isOnSpecial (boolean), wasPrice (the strike-through original price, null when not discounted), savingsAmount and savingsPercent. A non-discounted product gets isOnSpecial: false and wasPrice: null, never a fabricated markdown. soldOut (boolean) reports stock status.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips everything already collected there, so you don't pay twice. - Incremental mode (
incrementalMode) is for scheduled runs over the same search, category or URL set. The first run returns everything asNEW. Later runs classify each product asNEW,UPDATED(withchangedFieldsnaming what changed) orUNCHANGED(suppressed and not billed unlessemitUnchangedis on) against the state saved from the previous run.REAPPEAREDandEXPIREDonly enter the picture once you turn onemitExpired: a product is reportedEXPIREDonly after a run scans the entire tracked scope without a Max products cap and without Resume being used, and a product only comes back asREAPPEAREDif it was previously markedEXPIREDthis way. If you never turnemitExpiredon, you will only ever seeNEW,UPDATEDandUNCHANGED.stateKeynames or shares the stored state; leave it empty and the actor derives one automatically from the storefront, search terms and filters. With Incremental mode off, output is exactly as before.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape, and the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. If the picker is empty, you haven't authorized a connector yet.
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search or url. |
storefront | string | us | Which of the 14 storefronts to scrape in search mode. |
queries | array | none (prefill: ["foundation"]) | Keywords to search; one search per query. |
categories | array | none (prefill: empty) | Category slugs from the storefront's navigation. |
sortBy | string | relevance | relevance, popular, rating, price-asc, price-desc, or newest. |
specialsOnly | boolean | false | Scrape the Sale collection instead of queries/categories (Southeast Asia storefronts only; a no-op elsewhere). |
urls | array | none (prefill: one example URL) | One or more Sephora URLs to crawl in url mode. |
brands | array | none (prefill: empty) | Brand slugs to filter results. Applies in both modes, except a single pasted product URL. |
priceMin | integer | none | Minimum product price in the storefront's currency. |
priceMax | integer | none | Maximum product price in the storefront's currency. |
ratingMin | integer | 0 | Minimum average rating (0, 3, 4, or 5). |
newOnly | boolean | false | Only products marked as new arrivals. |
exclusiveOnly | boolean | false | Only products marked "Only at Sephora". |
fetchDetails | boolean | false | Fetch the product detail page for ingredients, how-to-use, the full variant list and claims. Also required, in search mode, for reviews and Q&A to be fetched even when those are turned on. |
fetchReviews | boolean | false | Fetch the top reviews per product. Populated today on the US and Southeast Asia storefronts. In search mode, also requires Fetch product details to be on. |
maxReviewsPerProduct | integer | 10 | Cap reviews per product (1 to 100). Ignored unless Fetch top reviews is on. |
fetchQna | boolean | false | Fetch top questions and answers per product. Populated today on the US and Southeast Asia storefronts. In search mode, also requires Fetch product details to be on. |
maxQnaPerProduct | integer | 5 | Cap Q&A entries per product (1 to 50). Ignored unless Fetch top Q&A is on. |
maxPages | integer | none (unlimited) | Optional bound on result pages walked per query, category or URL. Leave empty to walk every result page. |
maxProducts | integer | 20 | Total cap across all queries/URLs. Set to 0 for unlimited. |
proxyConfiguration | object | Residential (US) | Connection settings. A residential connection is what the US and European storefronts need to load reliably. |
resumeFromCheckpoint | boolean | true | Resume a same-run migration or restart from the internal checkpoint. |
resumeFromRunId | string | none | Paste a previous run or dataset ID to skip products it already collected. |
incrementalMode | boolean | false | Turn on for recurring monitoring of the same search, category or URL set. |
stateKey | string | none | Name or share an incremental-mode monitoring state. Leave empty to derive one automatically. |
emitUnchanged | boolean | false | Also return (and bill for) products unchanged since the last run, marked UNCHANGED. |
emitExpired | boolean | false | Also return (and bill for) products no longer found, marked EXPIRED, once a run fully scans the tracked scope. |
mcpConnectors | array | none | Optional: send a summary of each record to apps you authorized under Integrations. |
notionParentPageUrl | string | none | Notion connector only: page under which records are created. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. |
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"market": "sea-nz","source": {"id": 500000001,"crawlUrl": "https://www.sephora.nz/products/sample-foundation","canonicalUrl": "https://www.sephora.nz/products/sample-foundation","retailer": "SEPHORA","currency": "NZD","locale": "en-NZ"},"brand": "Sample Brand","title": "Sample Foundation","subtitle": "30ml","description": "<p>A self-priming foundation, primes, covers and sets...</p>","shortDescription": "<p>3-in-1 foundation primes, covers and sets...</p>","ingredients": "Aqua, Cyclopentasiloxane, Glycerin, ...","howToUse": "Shake well. Apply a small amount onto the back of your hand and use a brush or fingertips to blend onto skin.","claims": ["Cruelty free", "Paraben free", "Vegan"],"currentSku": "0000000","price": {"current": 18.0,"original": 36.0,"currency": "NZD","stockStatus": "IN_STOCK","available": true,"inventory": 13},"categories": ["Makeup", "Face", "Foundation"],"options": [{"name": "shade","id": "0","values": [{ "value": "1 Fair Neutral", "label": "1 Fair Neutral", "id": "0" }]}],"variants": [{"id": "0","sku": "0000000","gtin": "000000000000","name": "1 Fair Neutral","shade": "1 Fair Neutral","size": "30ml","price": {"current": 18.0,"original": 36.0,"currency": "NZD","stockStatus": "IN_STOCK","available": true,"inventory": 13},"highlights": ["NEW", "Only at Sephora"],"swatchUrl": "https://image.example.com/swatches/icon_swatch_0000.png","imageUrl": "https://image.example.com/products/sample.jpg"}],"medias": [{ "url": "https://image.example.com/products/sample-zoom.jpg", "type": "image", "role": "hero" }],"stats": {"reviewCount": 971,"rating": 4.8,"recommendedCount": 800,"totalPhotoCount": 100},"ratingHistogram": [{ "RatingValue": 5, "Count": 700 },{ "RatingValue": 4, "Count": 200 },{ "RatingValue": 3, "Count": 50 },{ "RatingValue": 2, "Count": 15 },{ "RatingValue": 1, "Count": 6 }],"topReviews": [{"id": "0","rating": 5,"title": "Best foundation I have ever tried","body": "Sample review text appears here...","publishedAt": "2026-01-01T00:00:00.000Z","skinType": "combination","skinTone": "fair"}],"highlights": ["NEW", "Only at Sephora"],"isOnSpecial": true,"wasPrice": 36.0,"savingsAmount": 18.0,"savingsPercent": 50,"soldOut": false,"frontend": "sea","scrapedAt": "2026-01-01T00:00:00.000Z"}
Plan Requirement
The default connection setting already uses a residential connection pinned to the United States, which is what the US and European storefronts (Germany, Romania, Sweden, Greece, Denmark, and the wider set reachable through URL mode) need to load reliably. The Southeast Asia storefronts and Mexico work with the default connection in most cases too. When you switch storefronts, pin the connection's country to that storefront's home market, for example NZ for sephora.nz or DE for sephora.de, for the most stable runs. If a request is refused, the actor automatically retries on a different connection rather than failing outright. See the Pricing tab for current rates.
FAQ
How much does it cost?
You pay per record returned, plus a small per-record surcharge when Fetch product details is on. The Pricing tab on the actor page shows the current rates. Use Max products to cap the cost of any run.
Is it legal to scrape Sephora?
This actor collects only publicly available product data. You are responsible for how you use it: follow Sephora's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Product descriptions, images and review text may be subject to Sephora's or its brands' own rights.
Can I get only new or changed products on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated products by default, and unchanged ones are suppressed and not billed. A product that disappears is only reported (as EXPIRED) once you turn on Emit expired products and a run scans the full tracked scope without being capped by Max products or run with Resume. A product that comes back after being marked EXPIRED is then reported as REAPPEARED on the run where it reappears. Without Emit expired products turned on at some point, you will only ever see NEW, UPDATED and UNCHANGED.
Why did my run return no reviews or Q&A even though I turned them on?
Fetch top reviews and Fetch top Q&A currently return data on the US storefront and the Southeast Asia storefronts (Australia, New Zealand, Singapore, Malaysia, Indonesia, Thailand, Philippines). Other storefronts return an empty list for these fields even with the switches on, since their review platform is not wired up yet. In search mode, both switches also require Fetch product details to be on; otherwise they are silently ignored.
Why did my run fail instead of returning an empty dataset?
An unresolvable input, such as an empty search with no queries or categories, leaves the run SUCCEEDED with zero rows and a status message explaining why, so a first-time typo never gets billed for nothing. The run fails outright only for a genuine setup problem: a Resume from run ID that cannot be resolved to a run or dataset your account can read, or Incremental mode combined with a Resume from run ID when that search already has saved incremental state. If the site refuses every request, run it again in a few minutes.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push a summary of each record into Notion, Linear or Airtable.
🔗 Want more e-commerce data?
Pair this actor with these related scrapers from the same team:
| 🥦 ALDI AU Scraper Scrape ALDI Australia (aldi.com.au) products: name, brand, price, was-price, savings... | 🛒 Douglas Germany Scraper Scrape Douglas.de beauty and fragrance products by keyword, category, brand, or URL... |
| 🛒 MUJI Scraper Scrape MUJI products from the United States, Canada and Australia storefronts. Search by... | 🛒 SHEIN Scraper Scrape SHEIN product listings by keyword or from any category, sale or search link... |
| 🛒 Lazada Scrape Lazada products and reviews across SEA markets, including Malaysia, Singapore... | 🛒 druni.es Scrape Druni beauty, cosmetics and perfume products. Search by keyword, category, Ofertas... |
💬 Support & custom scrapers
- 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- 🛠️ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.