Ulta Beauty Scraper — Products, Prices, Ingredients & Reviews
Pricing
from $0.35 / 1,000 products
Ulta Beauty Scraper — Products, Prices, Ingredients & Reviews
Scrape Ulta Beauty (ulta.com) products by search, category or brand: prices, sale prices, every shade with its own price, ingredients, stock, ratings and full customer reviews. Pay per result.
Pricing
from $0.35 / 1,000 products
Rating
0.0
(0)
Developer
Unfenced Group
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
20 hours ago
Last modified
Categories
Share
Ulta Beauty Scraper

Scrape products, prices, ingredients and customer reviews from Ulta Beauty (ulta.com). Search by keyword or paste category, brand, sale or product URLs, and get every shade and size with its own price, stock and shipping availability, highlights such as clean and vegan, the full star-rating breakdown and complete customer reviews. No API key required.
Why this scraper?
🔎 Every way into the catalog
Search terms, category pages, whole departments, brand pages, sale and promotion pages, site-search URLs and single product pages, sorted the six ways Ulta sorts: relevance, best sellers, top rated, new arrivals, and price in either direction. Brand-name searches follow Ulta's own redirect to the brand page.
🎨 Every shade and size priced
Foundations with 50+ shades and products in several sizes come back with each variant's own SKU, price, sale price, availability, shade description and swatch image, in one product row.
🧴 Complete product data
Description, ingredient list, how to use, warnings, size, highlights (clean ingredients, cruelty free, vegan and more), category path, all images and videos.
📦 Stock and fulfilment
Online stock, shipping speed, same-day delivery, current offers such as gifts with purchase, and the Replenish & Save subscription price.
⭐ Full customer reviews
Every review, not a sample: rating, title, full text, reviewer location, date, recommend answer, verified-buyer badge, helpful votes, customer photos and whether the review was imported from the brand. The product row gets the 1–5 star breakdown and recommend percentage.
📉 Price tracking between runs
Each product is marked NEW, UNCHANGED, PRICE_DROP or PRICE_INCREASE against your earlier runs, with the previous price. Turn on Only new products and price changes for a daily feed.
Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
searchTerms | array | [] | Keywords to search, e.g. ["vitamin c serum"]. Each term is searched separately. |
startUrls | array | [] | Category, department, brand, promotion, search or product URLs from www.ulta.com. |
sortBy | string | "relevance" | relevance, best_sellers, top_rated, new_arrivals, price_asc or price_desc. |
maxItems | integer | 100 | Maximum products across all terms and URLs. 0 = no limit. Reviews do not count. |
fetchDetails | boolean | false | Add full product details from each product page. |
variantPrices | boolean | true | With details on, price every shade and size, not only the one shown first. |
includeReviews | boolean | false | Add customer reviews as separate rows after each product. |
maxReviewsPerProduct | integer | 20 | Reviews per product. 0 = all reviews. |
reviewSort | string | "newest" | newest, oldest, most_helpful, highest_rating or lowest_rating. |
brands | array | [] | Only these brands (case-insensitive). |
minPrice | integer | (empty) | Minimum current price in USD. |
maxPrice | integer | (empty) | Maximum current price in USD. |
onlyOnSale | boolean | false | Only products currently on sale. |
minRating | integer | (empty) | Minimum average star rating, 1–5. |
inStockOnly | boolean | false | Skip out-of-stock products (exact with fetchDetails). |
onlyChanges | boolean | false | Only products that are new or changed price since your earlier runs. |
proxyConfiguration | object | none | Optional. The actor switches to a proxy by itself if needed. |
If you give no search term and no URL, the actor searches vitamin c serum as an example.
Output schema
The dataset holds two record types, told apart by recordType. Each product row is followed directly by its review rows. Every field is present on every row of its type; values the site does not publish are null.
Product rows — always present
| Field | Type | Description |
|---|---|---|
recordType | string | Always product for product rows. |
productId | string | Ulta product ID, e.g. pimprod2044189. |
skuId | string | Ulta SKU of the shade or size shown. |
url | string | Product page URL. |
name | string | Product name. |
brand | string | Brand name. |
variantLabel | string | Shade/size summary from the listing (e.g. 57 colors), or the selected shade with details on. |
variantCount | integer | Number of shades or sizes. |
price | number | Current price in USD (sale price if on sale, otherwise regular price). |
priceMin | number | Lowest current price across shades and sizes. |
priceMax | number | Highest current price across shades and sizes. |
listPrice | number | Regular price in USD. |
salePrice | number | Sale price in USD (null if not on sale). |
onSale | boolean | True when the current price is below the regular price. |
discountAmount | number | Discount in USD (null if not on sale). |
discountPercent | integer | Discount as a percentage of the regular price (null if not on sale). |
currency | string | Always USD. |
kitPrice | number | Kit or set value where Ulta shows one (usually null). |
promoText | string | Promotion shown on the product card, e.g. Buy 1 Get 1 50% Off (null if none). |
additionalOffers | string | Extra offers note, e.g. +1 offers (null if none). |
badges | array | Card badges such as New, Sale, Only at Ulta, Online only. |
isNew | boolean | Marked as new. |
isOnlyAtUlta | boolean | Exclusive to Ulta Beauty. |
isOnlineOnly | boolean | Sold online only. |
isLimitedStock | boolean | Flagged by Ulta as limited stock. |
limitedStockMessage | string | Ulta's limited-stock text (null if not limited). |
sponsored | boolean | Sponsored placement in the results. |
rating | number | Average star rating (1–5). |
reviewCount | integer | Total number of reviews. |
imageUrl | string | Main product image URL. |
position | integer | Rank in the search or category results (null for sponsored cards). |
sourceType | string | search, category, brand, promotion or product. |
sourceQuery | string | Search term that found the product (null for URL input). |
sourceUrl | string | Page the product was collected from. |
detailFetched | boolean | True when the row was enriched from the product page. |
contentHash | string | Stable hash of product ID and name, for de-duplication. |
changeStatus | string | NEW, UNCHANGED, PRICE_DROP or PRICE_INCREASE compared with your earlier runs. |
previousPrice | number | Price seen in your previous run (null for new products). |
priceChange | number | Current price minus previous price (null for new products). |
firstSeenAt | string | When your runs first saw this product (ISO 8601). |
scrapedAt | string | When the row was collected (ISO 8601). |
Product rows — with fetchDetails: true
| Field | Type | Description |
|---|---|---|
description | string | Full product description as formatted text (headings and bullets in Markdown). |
descriptionText | string | The same description as plain text. |
summary | string | Short product summary. |
howToUse | string | Usage directions. |
ingredients | string | Full ingredient list. |
restrictions | string | Coupon and shipping restrictions (null if none). |
prop65Warning | string | California Prop 65 warning where shown (null otherwise). |
highlights | array | Product highlights, e.g. Clean Ingredients, Cruelty Free, Vegan, Fragrance Free. |
size | string | Product size, e.g. 1.0 oz (null for multi-size products; see variants). |
variantType | string | What the variants differ in: Color, Size or similar. |
variants | array | Every shade or size: skuId, name, shadeDescription, price, listPrice, salePrice, available, outOfStockLabel, selected, tags, imageUrl, swatchUrl, url. |
images | array | All product image URLs in full resolution. |
videos | array | Product video URLs. |
breadcrumbs | array | Category path, e.g. Makeup, Eyes, Mascara. |
category | string | Category path joined with :. |
categoryLevel1 | string | Top-level category. |
categoryLevel2 | string | Second-level category. |
categoryLevel3 | string | Third-level category (null if none). |
inStock | boolean | Available to buy online. |
stockStatus | string | Ulta's stock status, e.g. InStock. |
shipAvailable | boolean | Can be shipped. |
shipMessage | string | Shipping availability text. |
shipSpeed | string | Shipping speed text, e.g. Usually ships in 24 hours. |
sameDayDeliveryOffered | boolean | Same-day delivery offered for the product. |
subscriptionPrice | number | Replenish & Save subscription price (null if not offered). |
subscriptionDiscountPercent | integer | Replenish & Save discount (null if not offered). |
promotions | array | Promotion tags on the product page. |
offers | array | Current offers on the product page, such as gifts with purchase: title, description, expiry. |
questionsCount | integer | Number of customer questions. |
topPositiveReview | object | Ulta's featured positive review: headline, comment. |
topCriticalReview | object | Ulta's featured critical review: headline, comment. |
Product rows — with fetchDetails: true or includeReviews: true
| Field | Type | Description |
|---|---|---|
ratingHistogram | object | Number of reviews per star level, keys 1 to 5. |
recommendedPercent | integer | Share of reviewers who would recommend the product (null when there are too few answers). |
nativeReviewCount | integer | Reviews written on ulta.com. |
syndicatedReviewCount | integer | Reviews imported from the brand's own site. |
reviewPhotoCount | integer | Customer photos in the review summary. |
reviewAttributes | object | What reviewers said about themselves or the product, counted, e.g. {"Skin Type": {"Dry": 18, "Oily": 5}} (null when not collected for the product). |
reviewsCollected | integer | Reviews saved for this product in this run. Null when reviews are off, and when more than 1,000 reviews per product are requested (those rows are written as they arrive, before the count is known). |
Review rows — with includeReviews: true
| Field | Type | Description |
|---|---|---|
recordType | string | Always review. |
reviewId | string | Review ID. |
productId / skuId | string | Product the review belongs to. |
productName / brand / productUrl | string | Product context, so each review row stands alone. |
rating | integer | Star rating, 1–5. |
headline | string | Review title. |
comments | string | Full review text. |
nickname | string | Reviewer's public nickname. |
location | string | Reviewer's stated location (often a city and state). |
createdAt / updatedAt | string | Review dates (ISO 8601). |
bottomLine | string | Reviewer's answer to "would you recommend" (Yes, No or null). |
isRecommended | boolean | The same answer as true/false (null if not answered). |
isVerifiedBuyer | boolean | Verified buyer badge. |
isVerifiedReviewer | boolean | Verified reviewer badge. |
isStaffReviewer | boolean | Staff reviewer badge. |
helpfulVotes / notHelpfulVotes | integer | Votes from other shoppers. |
isSyndicated | boolean | Imported from the brand's own website. |
syndicationSource | string | Where an imported review came from (null otherwise). |
properties | object | The reviewer's tags where given, e.g. Pros, Cons, Best For, Describe Yourself, Skin Type. |
photos | array | Customer photo URLs. |
disclosure | string | sampling or sweepstakes when the reviewer received the product free (null otherwise). |
isIncentivized | boolean | True when a disclosure is present. |
scrapedAt | string | When the review was collected (ISO 8601). |
Example product record (with details)
{"recordType": "product","productId": "pimprod2056740","skuId": "2651804","url": "https://www.ulta.com/p/345-relief-cream-pimprod2056740?sku=2651804","name": "345 Relief Cream","brand": "Dr. Althea","variantLabel": null,"variantCount": 1,"price": 18.9,"priceMin": 18.9,"priceMax": 18.9,"listPrice": 27,"salePrice": 18.9,"onSale": true,"discountAmount": 8.1,"discountPercent": 30,"currency": "USD","kitPrice": null,"promoText": null,"additionalOffers": null,"badges": ["Sale"],"isNew": false,"isOnlyAtUlta": false,"isOnlineOnly": false,"isLimitedStock": false,"limitedStockMessage": null,"sponsored": false,"rating": 4,"reviewCount": 54,"imageUrl": "https://media.ultainc.com/i/ulta/2651804","position": 1,"sourceType": "product","sourceQuery": null,"sourceUrl": "https://www.ulta.com/p/345-relief-cream-pimprod2056740?sku=2651804","detailFetched": true,"description": "#### Benefits\n\n- POS-ACNE CARE : Specifically designed to care for skin after breakouts, this cream helps reduce the look of post-acne marks and supports skin’s…","descriptionText": "Benefits\n• POS-ACNE CARE : Specifically designed to care for skin after breakouts, this cream helps reduce the look of p…","summary": "Dr. Althea 345 Relief Cream is a lightweight regenerating ointment-gel cream formulated to care for post-acne skin. Packed with nutrients, it skillfully combines 3 blemish-care, 4 nourishing, and 5 soothing ingredients to help calm irritation, replenish moisture, and support clearer-looking skin.","howToUse": "Apply an adequate amount evenly over the face and gently pat for better absorption as the final step in your skincare routine.","ingredients": "Aqua (Water), Melaleuca Alternifolia (Tea Tree) Leaf Water, Propanediol, Glycerin, 1,2-Hexanediol, Hydrogenated Polydece…","restrictions": null,"prop65Warning": null,"highlights": ["Clean Ingredients","Vegan","Sustainable Packaging","K Beauty"],"size": "1.69 oz","variantType": null,"variants": [{"skuId": "2651804","name": null,"shadeDescription": null,"price": 18.9,"listPrice": 27,"salePrice": 18.9,"available": true,"outOfStockLabel": null,"selected": true,"tags": [],"imageUrl": null,"swatchUrl": null,"url": "https://www.ulta.com/p/345-relief-cream-pimprod2056740?sku=2651804"}],"images": ["https://media.ulta.com/i/ulta/2651804","https://media.ulta.com/i/ulta/2651804_alt01"],"videos": [],"breadcrumbs": ["Skin Care","Moisturizers","Face Moisturizer"],"category": "Skin Care:Moisturizers:Face Moisturizer","categoryLevel1": "Skin Care","categoryLevel2": "Moisturizers","categoryLevel3": "Face Moisturizer","inStock": true,"stockStatus": "InStock","shipAvailable": true,"shipMessage": "In stock and ready to ship","shipSpeed": "Usually ships in 24 hours","sameDayDeliveryOffered": true,"subscriptionPrice": 17.96,"subscriptionDiscountPercent": 5,"promotions": [],"offers": [{"title": "Free Gift with purchase","description": "Online only free Sunday Riley Good Genes sample with select skincare purchase (valid thru 10.3.26 on shipped orders only; pickup and same-day delivery not eligible. While quantities last)","expiry": null}],"questionsCount": 1,"topPositiveReview": {"headline": "Magic cream","comment": "I usually am not one to write reviews but this cream is so good it's a must. I am 26 years…"},"topCriticalReview": {"headline": "I'm not the targeted audience","comment": "BEFORE YOU READ, THIS PRODUCT JUST DIDN'T WORK FOR ME BECAUSE IT IS NOT COMPATIBLE WITH MY…"},"ratingHistogram": {"1": 3,"2": 7,"3": 6,"4": 7,"5": 31},"recommendedPercent": 83,"nativeReviewCount": 54,"syndicatedReviewCount": 0,"reviewPhotoCount": 1,"reviewAttributes": null,"reviewsCollected": 25,"contentHash": "4895f34a671335f5","changeStatus": "NEW","previousPrice": null,"priceChange": null,"firstSeenAt": "2026-09-19T14:07:34.563Z","scrapedAt": "2026-09-19T14:07:34.562Z"}
Example review record
{"recordType": "review","reviewId": "574532018","productId": "pimprod2056740","skuId": "2651804","productName": "345 Relief Cream","brand": "Dr. Althea","productUrl": "https://www.ulta.com/p/345-relief-cream-pimprod2056740?sku=2651804","rating": 3,"headline": "Not as good as the first version..","comments": "Okay so Ive loveeeeed the first version of the 345 cream and it really helped me alot with my acne. But Im super bummed that they chaged the formula and added some new things as well as took some of the other good things out, its just not the same and im really disappointed, I tried buying it acouple times to give it a shot but its just not it anymore:(((( \nIt was worth spending the money when it was helping, but its not helping me now. I do hope thatll itll help alot of people, its just not for me ❤️","nickname": "Riri","location": "Hamilton OH","createdAt": "2026-02-18T22:51:57.348Z","updatedAt": "2026-09-08T18:30:12.358Z","bottomLine": null,"isRecommended": null,"isVerifiedBuyer": false,"isVerifiedReviewer": false,"isStaffReviewer": false,"helpfulVotes": 45,"notHelpfulVotes": 6,"isSyndicated": false,"syndicationSource": null,"properties": {},"photos": [],"disclosure": null,"isIncentivized": false,"scrapedAt": "2026-09-19T14:07:34.301Z"}
Examples
Search two keywords and get the best sellers first:
{"searchTerms": ["vitamin c serum", "retinol"],"sortBy": "best_sellers","maxItems": 200}
Full product data for a category, every shade priced:
{"startUrls": [{ "url": "https://www.ulta.com/shop/makeup/face/foundation" }],"fetchDetails": true,"maxItems": 100}
The 50 most critical reviews of one product:
{"startUrls": [{ "url": "https://www.ulta.com/p/tartelette-xl-tubing-mascara-pimprod2044189?sku=2621780" }],"includeReviews": true,"maxReviewsPerProduct": 50,"reviewSort": "lowest_rating"}
Daily price-drop feed for one brand's sale items (schedule this daily):
{"startUrls": [{ "url": "https://www.ulta.com/brand/cerave" }],"onlyOnSale": true,"onlyChanges": true,"maxItems": 0}
💰 Pricing
You pay only for results saved to your dataset. There is no charge per run and no charge for failed requests.
| Result | Price per 1,000 |
|---|---|
| Product (from search, category, brand or sale pages) | $0.35 |
| Product with full details | $0.79 |
| Customer review | $0.09 |
| Example run | Cost |
|---|---|
| 1,000 products | ~$0.35 |
| 1,000 products with full details | ~$0.79 |
| 100 products with details + 20 reviews each (2,000 reviews) | ~$0.26 |
| 10,000 products | ~$3.50 |
A product page URL in Start URLs always returns the full product, billed as a product with details. Pricing every shade and size adds no cost. Use Max products and Max reviews per product to control your spend exactly.
Flat-rate alternatives typically charge $29–$49/month regardless of usage.
Performance
| Run size | Typical time |
|---|---|
| 100 products | under 30 seconds |
| 1,000 products | about 1 minute |
| 100 products with full details | 1–5 minutes (the upper end for products with 50+ shades, such as foundation) |
| All reviews of a product with 10,000+ reviews | about 3 minutes |
Known limitations
- Prices and stock are those shown to an anonymous visitor on ulta.com with no store selected; store pickup availability and member-only offers are not included.
- Ulta's review service returns at most 10,000 reviews per sort order. For products with more, the actor collects from both ends (newest and oldest) and removes duplicates, which covers up to 20,000 reviews per product.
- Sponsored product cards appear in results as Ulta shows them; they are flagged with
sponsored: trueand carry no position. - Search and category pages carry no ingredients, stock or shade prices; turn on Fetch full product details for those.
- Reviews imported from a brand's own website do not carry a "would recommend" answer, so
recommendedPercentis null for products whose reviews are nearly all imported.
Technical details
- Source: ulta.com — United States, prices in USD
- Coverage: the full public catalog: search, categories, departments, brands, sale and promotion pages, product pages and customer reviews
- Change tracking: key-value store
ulta-beauty-scraper-historyin your account, 180-day retention - Retry: automatic retry with exponential backoff, and automatic proxy fallback if the site starts refusing requests
- Memory: 256 MB
Rate this actor
If this scraper does its job, a short review on the Reviews tab helps other users find it. Something not working? Open an issue on the Issues tab instead — issues get fixed.
Need a custom scraper?
Unfenced Group builds Apify actors for any website — for free.
If the site you need isn't in our portfolio yet, just ask. We scope, build, and publish it at no cost to you. You only pay for results — we absorb the compute and proxy costs ourselves. Same pay-per-result pricing, same quality, same standards as every actor in this portfolio.
Get in touch: www.unfencedgroup.nl