Kroger API endpoint
Searches Kroger products by keyword and returns product cards (price, unit price, brand, size, stock level) plus the facet groups Kroger offers for the query (brands, nutrition, savings, price range and more). It supports real pagination, and the source field reports which path answered. Facet filters and sort apply to the primary path only: when any of them is set, a failure of that path returns an error rather than silently falling back to unfiltered results.
/kroger/searchSearches Kroger products by keyword and returns product cards: price, unit price, size, SNAP EBT eligibility, and low-stock flag.
Query parameters:
query (required) — search keyword.page (optional) — one-based result page, default 1.Facet filters and sort (all optional, JSON path only — see below):
sort — result order. One of relevance (default), name_asc,
popularity_desc. Any other value returns 400 before any upstream
request is made.brands — comma-separated brand names, e.g. Halo Top,Rebel.nutrition — comma-separated nutrition/dietary facet values, e.g.
Gluten Free.flavor — comma-separated flavor facet values, e.g. Chocolate.scent — comma-separated scent facet values, e.g. Bergamot.savings — comma-separated savings facet values. On Sale is the
confirmed value.more_options — comma-separated more-options facet values. Confirmed
values: SNAP EBT Eligible, In-Stock Items Only.price_min / price_max — price bounds. price_max is required to
filter on price at all; price_min defaults to 0 (an "under $N"
filter). Supplying price_min alone returns 400.Filter values are facet names, taken verbatim from a previous
response's facets[].values[].name — Kroger filters on the display name,
not the slug. Multiple values within one filter are OR-ed together.
Notable response behavior:
Filters and sort apply to the json_api path only. When any of them
is set and that path fails, the request returns an error instead of
falling back to the rendered page — the HTML path cannot honor these
filters, so returning its unfiltered results would be wrong. Unfiltered
requests still fall back as before.
Each result's upc is usable directly as the upc query parameter to
/kroger/product.
For browsing a specific product category instead of keyword search, see
/kroger/category, which returns results in this
same shape.
total_count reflects the number of results Kroger's own page reports as
loaded, not necessarily every result matching the query — Kroger's search
page loads results in batches behind a "Load More Results" control.
source reports which upstream path served the response: json_api
(Kroger's own search API, the primary path) or html (the rendered-page
fallback, used only when the JSON path is unavailable).
Pagination is real on the json_api path — it uses Kroger's own
page offset/size, and has_more reports whether further pages exist. On
the html fallback has_more is always false and paging past page 1
remains best-effort.
facets lists the refinement groups Kroger offers for the query (brands,
nutrition, savings, price range and more), each value with its result
count. Only populated on the json_api path.
brand and stock_level are populated on the json_api path only; the
rendered result cards carry neither.
A missing query returns 400 before any upstream request is made.
| Field | Filled in, of 24 checked | Values in the sample |
|---|---|---|
| upc | 24 | |
| url | 24 | kroger.com |
| title | 24 | “Kroger® 2% Reduced Fat Milk Gallon” and 22 other values |
| image_url | 24 | kroger.com |
| price | 24 | 0 |
| currency | 24 | USD in all 24 |
| unit_price | 24 | “$0.03/fl oz” and 11 other values |
| size | 24 | 1/2 gal (10), 1 gal (5), 6 ct / 8 fl oz (4) and 3 more |
| snap_ebt_eligible | 24 | true in 24 of 24 |
| low_stock | 24 | true in 4 of 24 |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| query | string | Yes | Search keyword | milk | |
| page | integer | No | One-based result page Minimum: 1. | ||
| sort | string | No | Result order. One of: relevance, name_asc, popularity_desc Allowed values: relevance, name_asc, popularity_desc. | ||
| brands | string | No | Comma-separated brand names to filter by, taken verbatim from a previous response's facets | Halo Top,Rebel | |
| nutrition | string | No | Comma-separated nutrition/dietary facet values | Gluten Free | |
| flavor | string | No | Comma-separated flavor facet values | Chocolate | |
| scent | string | No | Comma-separated scent facet values | Bergamot | |
| savings | string | No | Comma-separated savings facet values | On Sale | |
| more_options | string | No | Comma-separated more-options facet values | SNAP EBT Eligible | |
| price_min | number | No | 0 | Lower bound of the price filter; defaults to 0 | 0 |
| price_max | number | No | Upper bound of the price filter; required to filter on price | 8 | |
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/kroger/search?query=milk&page=1&sort=relevance" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"query": "edward & sons",
"page": 1,
"total_count": 37,
"products": [
{
"upc": "0004318200391",
"url": "https://www.kroger.com/p/edward-sons-not-chick-n-bouillon-cubes/0004318200391?fulfillment=PICKUP&searchType=default_search",
"title": "Edward & Sons® Not-Chick'n Bouillon Cubes",
"image_url": "https://www.kroger.com/product/images/medium/front/0004318200391",
"price": 2.99,
"currency": "USD",
"unit_price": "$1.20/oz",
"size": "2.5 oz",
"snap_ebt_eligible": true,
"low_stock": false
}
]
}
}Request schema
No body schema
Response schema
#/definitions/kroger.searchResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| code | integer | No | 200 | |||
| data | kroger.SearchResponse | No | ||||
| data.facets | array | No | ||||
| data.facets[].group | string | No | ||||
| data.facets[].values | array | No | ||||
| data.facets[].values[].count | integer | No | ||||
| data.facets[].values[].name | string | No | ||||
| data.facets[].values[].slug | string | No | ||||
| data.has_more | boolean | No | HasMore reports whether Kroger says more results exist past this page. Only meaningful on the JSON-API path; false on the HTML fallback. | |||
| data.page | integer | No | ||||
| data.products | array | No | ||||
| data.products[].brand | string | No | Brand and StockLevel are populated by the JSON-API path only (the HTML result cards carry neither); both are omitted when the HTML fallback served the response. See Search's doc comment. | |||
| data.products[].currency | string | No | ||||
| data.products[].image_url | string | No | ||||
| data.products[].low_stock | boolean | No | ||||
| data.products[].original_price | number | No | ||||
| data.products[].price | number | No | ||||
| data.products[].size | string | No | ||||
| data.products[].snap_ebt_eligible | boolean | No | ||||
| data.products[].stock_level | string | No | ||||
| data.products[].title | string | No | ||||
| data.products[].unit_price | string | No | ||||
| data.products[].upc | string | No | ||||
| data.products[].url | string | No | ||||
| data.query | string | No | ||||
| data.source | string | No | Source is which upstream path served this response: "json_api" (the primary path) or "html" (the fallback). See Search's doc comment. | |||
| data.total_count | integer | 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/kroger/search?query=milk&page=1&sort=relevance" \
-H "x-api-key: $CRAWLORA_API_KEY"