Ulta Beauty API endpoint
Searches Ulta Beauty's product catalog by keyword, with real page-based pagination. Returns products with brand, pricing, rating, and review count. An unrecognized/nonsense keyword returns a genuine empty result rather than a fallback set. Requesting a page beyond the available results returns a normal, empty result rather than an error.
/ulta/searchquery is required, 1 to 200 characters. page is optional, 1-based, defaults to 1.
Notable response behavior:
has_more is the upstream's own genuine "more pages available" marker: true on every page with more results after it, false on the real last page and on any page beyond it.page beyond the available results returns a normal 200 with an empty products array and has_more: false, not an error.query returns a genuine empty result (count: 0, result_count: 0) rather than a fallback set.list_price/sale_price are Ulta's own display-formatted price strings (e.g. "$12.99 - $13.99"), since a search card's list price is often a range across a product's own color/shade variants -- use /ulta/product/{productId} for one variant's single resolved price.| Field | Filled in, of 70 checked | Values in the sample |
|---|---|---|
| product_id | 70 | |
| sku_id | 70 | |
| brand_name | 70 | “Maybelline” and 21 other values |
| product_name | 70 | “Lash Sensational Sky High Mascara” and 69 other values |
| list_price | 70 | “$12.99 - $13.99” and 27 other values |
| promo_text | 36 | Free Gift with purchase (23), Bundle & Save! (13) |
| rating | 69 | 3.5 to 4.8, median 4.3 |
| review_count | 69 | 3 to 24,530, median 1,870 |
| variant_label | 55 | 2 colors (21), 2 sizes (14), 3 colors (10) and 5 more |
| image_url | 70 | media.ultainc.com |
| url | 70 | ulta.com |
| sponsored | 12 | true in 12 of 12 |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| query | string | Yes | Search keyword | mascara | |
| page | integer | No | 1 | Result page, 1-based, defaults to 1 | 1 |
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/ulta/search?query=mascara&page=1" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"query": "mascara",
"page": 1,
"page_size": 64,
"count": 3,
"result_count": 382,
"has_more": true,
"products": [
{
"product_id": "pimprod2020260",
"sku_id": "2574523",
"brand_name": "Maybelline",
"product_name": "Lash Sensational Sky High Mascara",
"list_price": "$12.99 - $13.99",
"rating": 4.5,
"review_count": 11861,
"variant_label": "9 colors",
"image_url": "https://media.ulta.com/i/ulta/2574523",
"url": "https://www.ulta.com/p/lash-sensational-sky-high-mascara-pimprod2020260?sku=2574523"
}
],
"source_url": "https://www.ulta.com/dxl/graphql?...",
"fetched_at": "2026-08-10T10:00:00Z"
}
}Request schema
No body schema
Response schema
#/definitions/ulta.searchResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| code | integer | No | 200 | |||
| data | ulta.SearchResponse | No | ||||
| data.count | integer | No | ||||
| data.fetched_at | string | No | ||||
| data.has_more | boolean | No | ||||
| data.page | integer | No | ||||
| data.page_size | integer | No | ||||
| data.products | array | No | ||||
| data.products[].brand_name | string | No | ||||
| data.products[].discount | string | No | ||||
| data.products[].image_url | string | No | ||||
| data.products[].is_limited_stock | boolean | No | ||||
| data.products[].list_price | string | No | ||||
| data.products[].product_id | string | No | ||||
| data.products[].product_name | string | No | ||||
| data.products[].promo_text | string | No | ||||
| data.products[].rating | number | No | ||||
| data.products[].review_count | integer | No | ||||
| data.products[].sale_price | string | No | ||||
| data.products[].sku_id | string | No | ||||
| data.products[].sponsored | boolean | No | ||||
| data.products[].url | string | No | ||||
| data.products[].variant_label | string | No | ||||
| data.query | string | No | ||||
| data.result_count | integer | No | ||||
| data.source_url | string | No | ||||
| msg | string | No | OK |
| Status | Description | Schema |
|---|---|---|
| 400 | Bad Request | #/definitions/app.Response |
| 429 | Too Many Requests | #/definitions/app.Response |
| 503 | Service Unavailable | #/definitions/app.Response |
Use environment variables for secrets and keep Crawlora API keys server-side.
curl -X GET "https://api.crawlora.net/api/v1/ulta/search?query=mascara&page=1" \
-H "x-api-key: $CRAWLORA_API_KEY"