Other

Ulta Beauty API

Ulta Beauty API returns live Ulta Beauty data as clean JSON for ulta beauty The primary endpoint, search, returns product results including product id, sku id, name, brand and image.

3 actionsLive JSON1,000 free creditsMCP-ready
Get a free keyOpen in playground

🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.

Developers reach for it when they need to validate, enrich, classify and normalize operational data without maintaining one-off scraping code or separate API contracts. If you were about to build or fix a Ulta Beauty scraper, this API is the maintained alternative — it returns the same data as clean JSON, with the proxies, rotation and anti-bot handling already solved. This page covers the live example, request shape, response shape and available actions: search, price, product_detail. Every request uses the same ReefAPI envelope, one API key and one shared credit pool, so it fits alongside the rest of your data stack.

Live example

Real request and response JSON

Captured from the indexed primary action, search, on .

Captured request
{
  "method": "POST",
  "url": "https://api.reefapi.com/ulta/v1/search",
  "headers": {
    "x-api-key": "$REEF_KEY",
    "content-type": "application/json"
  },
  "body": {
    "category": "/shop/makeup/face/foundation",
    "max_results": 20
  }
}
Captured response
{
  "ok": true,
  "meta": {
    "api": "ulta",
    "endpoint": "search",
    "mode": "live",
    "latency_ms": 1653.1,
    "record_count": 20,
    "bytes": 905763,
    "cache_hit": false,
    "completeness_pct": 100,
    "stop_reason": "limit_reached",
    "method": "ulta_graphql_page",
    "search_mode": "category",
    "source": {
      "route": "/dxl/graphql Page → ProductListingResults",
      "upstream_calls": 1,
      "upstream_pages": 1,
      "page_size": 64
    },
    "pagination": {
      "page": 1,
      "per_page": 64,
      "total_results": 225,
      "returned": 20,
      "has_more": true,
      "next_page": 2
    },
    "filters": {
      "applied": [],
      "ignored": [],
      "notes": null
    },
    "notes": null
  },
  "data": {
    "products": [
      {
        "product_id": "pimprod2057355",
        "sku_id": "2651970",
        "url": "https://www.ulta.com/p/double-wear-stay-in-place-longwear-matte-foundation-pimprod2057355?sku=2651970",
        "name": "[redacted-name]",
        "brand": "Estée Lauder",
        "image": "https://media.ultainc.com/i/ulta/2651970",
        "image_alt": null,
        "list_price": 52,
        "list_price_max": 52,
        "sale_price": null,
        "sale_price_max": null,
        "price": 52,
        "currency": "USD",
        "on_sale": false,
        "discount_amount": null,
        "rating": 4.3,
        "review_count": 9926,
        "variant_label": "57 colors",
        "badge": null,
        "badge_tags": [],
        "promo_text": "Bundle & Save!",
        "additional_offers_text": null,
        "sponsored": false,
        "limited_stock": false
      },
      {
        "product_id": "pimprod2051406",
        "sku_id": "2635749",
        "url": "https://www.ulta.com/p/studio-fix-powder-plus-foundation-pimprod2051406?sku=2635749",
        "name": "[redacted-name]",
        "brand": "MAC",
        "image": "https://media.ultainc.com/i/ulta/2635749",
        "image_alt": null,
        "list_price": 39,
        "list_price_max": 39,
        "sale_price": 31.2,
        "sale_price_max": 31.2,
        "price": 31.2,
        "currency": "USD",
        "on_sale": true,
        "discount_amount": 7.8,
        "rating": 3.8,
        "review_count": 3453,
        "variant_label": "71 colors",
        "badge": null,
        "badge_tags": [
          "Sale"
        ],
        "promo_text": null,
        "additional_offers_text": null,
        "sponsored": false,
        "limited_stock": false
      },
      {
        "product_id": "xlsImpprod5770257",
        "sku_id": "2264064",
        "url": "https://www.ulta.com/p/cc-cream-with-spf-50-xlsImpprod5770257?sku=2264064",
        "name": "[redacted-name]",
        "brand": "IT Cosmetics",
        "image": "https://media.ultainc.com/i/ulta/2264064",
        "image_alt": null,
        "list_price": 39,
        "list_price_max": 39,
        "sale_price": null,
        "sale_price_max": null,
        "price": 39,
        "currency": "USD",
        "on_sale": false,
        "discount_amount": null,
        "rating": 4.3,
        "review_count": 22005,
        "variant_label": "30 colors",
        "badge": null,
        "badge_tags": [],
        "promo_text": null,
        "additional_offers_text": null,
        "sponsored": false,
        "limited_stock": false
      }
    ],
    "category": {
      "path": "/shop/makeup/face/foundation",
      "url": "https://www.ulta.com/shop/makeup/face/foundation",
      "title": "Foundation",
      "result_count": 225,
      "page": 1,
      "page_size": 64
    },
    "suggestions": null,
    "facets": {
      "sort": [
        {
          "value": "best_sellers",
          "label": "Best Sellers"
        },
        {
          "value": "price_asc",
          "label": "Price (low to high)"
        },
        {
          "value": "price_desc",
          "label": "Price (high to low)"
        }
      ],
      "filters": [
        {
          "group_id": "FORM",
          "title": "Form",
          "select": "MULTI",
          "param": "form",
          "values": [
            "[trimmed-depth]",
            "[trimmed-depth]",
            "[trimmed-depth]"
          ]
        },
        {
          "group_id": "FINISH",
          "title": "Finish",
          "select": "MULTI",
          "param": "finish",
          "values": [
            "[trimmed-depth]",
            "[trimmed-depth]",
            "[trimmed-depth]"
          ]
        },
        {
          "group_id": "COVERAGE",
          "title": "Coverage",
          "select": "MULTI",
          "param": "coverage",
          "values": [
            "[trimmed-depth]",
            "[trimmed-depth]",
            "[trimmed-depth]"
          ]
        }
      ]
    }
  }
}
Actions

What the Ulta Beauty API does

ActionDescriptionConcrete use caseKey params
searchFind products on ulta.com (US). Browse a `category` — `/shop/makeup/face/foundation`, `/shop/hair/shampoo-conditioner/shampoo`, `/shop/skin-care/moisturizers` — for the precise, fully pageable result set with Ulta's own total, or give a free-text `query` ('mascara', 'vitamin c serum', 'dyson airwrap') to let Ulta's own type-ahead decide which category answers it. Every product comes back with Ulta's own product id and sku, the name, brand, image, list and sale price (a range when the shades differ), the star rating and review count, the shade/size count and Ulta's badges and promo text. Narrow with `brand`, `min_rating`, `sort` and any facet Ulta publishes for that category; the live facet vocabulary comes back WITH counts in every category response, so a filter value is never a guess.Ops teams call search to find products on ulta.com (US).query, category, page, max_results, sort, ...
priceRe-check ONE variant's price and stock, cheaply. Give it the product_id and the sku_id you already hold and it returns the current price, the regular price, whether that variant is in stock, and nothing else — no description, images, ingredients, variants or reviews. Built for refreshing a catalogue you already have rather than discovering products: it reads the same small module Ulta's own shade swatch fires, so it costs a fraction of a full product_detail. Note that sku_id is REQUIRED, because Ulta stocks and prices every shade and size separately — a product can be on sale and buyable in one size while another is sold out, so there is no single product-level answer.Developer tools call price to get re-check ONE variant's price and stock, cheaply.product_id, sku_id, url
product_detailGet one Ulta Beauty product in full, by Ulta's product id or by its ulta.com URL — brand, name, the marketing copy in both plain text and its original Markdown, the full ingredient list, how-to-use, size, category path, list and sale price, availability, star rating and question count, the complete image AND video gallery with dimensions, Ulta's merchandising highlights and active promotions, one row per shade/size variant carrying that variant's OWN sku, price, sale price, stock flag, swatch and product images, and the customer reviews inline with the rating histogram, the recommended ratio, the most helpful positive and negative review, and the reviewer-reported attribute rollups. One call, everything the product page shows.Validation workflows call product_detail to get one Ulta Beauty product in full, by Ulta's product id or by its ulta.com URL.product_id, sku_id, url, reviews, variant_prices
Code samples

Call search from your stack

curl -X POST https://api.reefapi.com/ulta/v1/search \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"category":"/shop/makeup/face/foundation","max_results":20}'
MCP one-liner
Ask your MCP-connected assistant: call reefapi.ulta.search with {"category":"/shop/makeup/face/foundation","max_results":20}.
Use cases

Who uses this API and why

  • Ops teams use Ulta Beauty to find products on ulta.com (US).
  • Developer tools use Ulta Beauty to get re-check ONE variant's price and stock, cheaply.
  • Validation workflows use Ulta Beauty to get one Ulta Beauty product in full, by Ulta's product id or by its ulta.com URL.
FAQ

Questions developers ask before integrating

What is the Ulta Beauty API?

Ulta Beauty API is a ReefAPI endpoint group for ulta beauty It returns live JSON through POST requests under /ulta/v1.

Is the Ulta Beauty API free to try?

Yes. ReefAPI starts with 1,000 free credits, no card required. Ulta Beauty calls use the same shared credit balance as every other ReefAPI engine.

Do I need a Ulta Beauty login or account?

No login to Ulta Beauty is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.

How fresh is the Ulta Beauty data?

The page example is captured from a live search call, and production requests fetch live data through ReefAPI rather than a static sample.

How many credits does the Ulta Beauty API use?

Ulta Beauty actions currently cost 2 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.

Can I call Ulta Beauty from an AI assistant or MCP client?

Yes. Connect ReefAPI once through MCP and your assistant can call ulta actions with the same key, credit pool and JSON envelope used by normal REST requests.

Is the Ulta Beauty API a Ulta Beauty scraper?

It is the managed alternative to a DIY Ulta Beauty scraper. Instead of building and maintaining your own scraper — proxies, headless browsers, captcha and constant breakage — you call one ReefAPI endpoint and get the same ulta beauty back as clean JSON.

Why does my Ulta Beauty scraper keep getting blocked?

Most Ulta Beauty scrapers break on anti-bot defenses, rate limits and IP bans that need rotating residential proxies and browser fingerprinting to clear. ReefAPI handles all of that for you — no proxies, no captchas, no maintenance — and returns live JSON. Blocked or failed calls are free.

docs / ulta

Ulta Beauty

Ulta Beauty

base /ulta/v13 endpoints
post/ulta/v1/price2 credits

Re-check ONE variant's price and stock, cheaply. Give it the product_id and the sku_id you already hold and it returns the current price, the regular price, whether that variant is in stock, and nothing else — no description, images, ingredients, variants or reviews. Built for refreshing a catalogue you already have rather than discovering products: it reads the same small module Ulta's own shade swatch fires, so it costs a fraction of a full product_detail. Note that sku_id is REQUIRED, because Ulta stocks and prices every shade and size separately — a product can be on sale and buyable in one size while another is sold out, so there is no single product-level answer.

ParameterAllowed / rangeDescription
product_idrequired
sku_idrequired
urloptional
Try in playground →
post/ulta/v1/product_detail2 credits

Get one Ulta Beauty product in full, by Ulta's product id or by its ulta.com URL — brand, name, the marketing copy in both plain text and its original Markdown, the full ingredient list, how-to-use, size, category path, list and sale price, availability, star rating and question count, the complete image AND video gallery with dimensions, Ulta's merchandising highlights and active promotions, one row per shade/size variant carrying that variant's OWN sku, price, sale price, stock flag, swatch and product images, and the customer reviews inline with the rating histogram, the recommended ratio, the most helpful positive and negative review, and the reviewer-reported attribute rollups. One call, everything the product page shows.

ParameterAllowed / rangeDescription
product_idoptionalUlta's own product id, exactly as `search` returns it — e.g. `pimprod2057355`. Ulta also uses `xlsImpprod…`, `mkt…`, `gwp…`, `VP…` and `fs…` prefixes; all are accepted verbatim. This alone is enough: the slug in an Ulta product URL is decorative and the id resolves the product on its own. Provide `product_id`, or a product `url`.
sku_idoptionalOptional. Ulta's numeric sku for ONE variant (shade/size). Every variant of the product is returned whichever sku you pass — the sku only decides which one Ulta treats as selected, and therefore which shade's price, images and 'selected' flag appear at the top level. Omit it to get Ulta's default variant.
urloptionalA full ulta.com product URL — an alternative to `product_id`. The `?sku=` suffix is honoured if present.
variant_prices = autooptionalauto · all · noneHow hard to work for the per-variant price matrix. This knob exists because of a real Ulta behaviour: an ulta.com product page prices ONLY the shade or size it has selected — the other swatches carry no price at all — so every additional variant price is a separate (small) request. `auto`, the default, fetches all of them when the product has 12 or fewer variants, which covers every size/format set (a 4-size perfume really is $37/$110/$145/$180 and a 5-size moisturiser $20/$35/$42/$50/$66, so those must never be guessed). On a big shade set it samples 3 shades spread across the range; measured across four products with 26-71 shades, every sampled shade of a given product had the identical price, so if the 3 agree it stops there and tells you in `product.price_note` — and if they disagree it fetches the rest. `all` always fetches every variant (capped at 60). `none` skips it. A variant whose price was NOT measured is null and `price_measured` is false; the product price is never copied down onto it. `meta.coverage.variant_pricing` reports exactly what was fetched.
reviews = 8optional0–25How many written reviews to inline with the product (0-25; 25 is the review host's own per-page ceiling, established by bisection — 100 is rejected by it). Set 0 to skip the review call entirely: the rating, the review count and the two most-helpful reviews still come from the product page itself, so you lose the review list, the rating histogram and the reviewer-reported attribute rollups, and save one upstream request.
Try in playground →