Install
openclaw skills install supermarketSearch grocery products, find store locations, add items to cart, and view profile across all Kroger-family stores — Kroger, Ralphs, Fred Meyer, Harris Teete...
openclaw skills install supermarketSearch grocery products, find stores, add to cart, and view your profile across all Kroger-family stores (Kroger, Ralphs, Fred Meyer, Harris Teeter, King Soopers, Fry's, QFC, Mariano's, Pick 'n Save, and more) — all through the Kroger API via a hosted OAuth proxy. No API keys or developer accounts needed.
This skill uses a hosted OAuth proxy at us-central1-krocli.cloudfunctions.net to handle Kroger API authentication. Here's what it does and doesn't do:
What the proxy handles:
Privacy guarantees (verifiable in source):
tokenUser.ts:44)callback.ts:10)console.errorFull source code: The proxy is open source at firebase/functions/src/ in the krocli repository. You can audit every function: authorize.ts, callback.ts, tokenClient.ts, tokenUser.ts, tokenRefresh.ts.
If you don't trust the hosted proxy, see "Self-Hosting" at the bottom of this document.
All API calls go through the hosted proxy which handles OAuth credentials. The agent never needs a client_id or client_secret.
Two token types:
Before searching products or locations, obtain a client token:
curl -s -X POST https://us-central1-krocli.cloudfunctions.net/tokenClient
Response:
{"access_token": "eyJ...", "expires_in": 1800, "token_type": "bearer"}
Cache the access_token for subsequent requests. It expires in 30 minutes.
curl -s -H "Authorization: Bearer ACCESS_TOKEN" \
-H "Accept: application/json" \
"https://api.kroger.com/v1/products?filter.term=milk&filter.limit=10"
Query parameters:
| Parameter | Required | Description |
|---|---|---|
filter.term | Yes | Search term (e.g. "milk", "organic eggs") |
filter.locationId | No | Store ID for local pricing/availability |
filter.limit | No | Max results (default 10, max 50) |
Response fields to show the user:
data[].productId — UPC codedata[].description — Product namedata[].brand — Brand namedata[].items[].price.regular — Price (when locationId provided)data[].items[].price.promo — Sale price (when available)data[].items[].size — Package sizecurl -s -H "Authorization: Bearer ACCESS_TOKEN" \
-H "Accept: application/json" \
"https://api.kroger.com/v1/locations?filter.zipCode.near=45202&filter.limit=5"
Query parameters:
| Parameter | Required | Description |
|---|---|---|
filter.zipCode.near | Yes | ZIP code to search near |
filter.radiusInMiles | No | Search radius (default 10) |
filter.limit | No | Max results (default 10) |
Response fields to show the user:
data[].locationId — Store ID (use for product pricing)data[].name — Store namedata[].address.addressLine1, city, state, zipCodedata[].phone — Phone numberdata[].hours — Operating hoursWhen the user wants to add items to their cart or view their profile, they need to authenticate with Kroger. This is a one-time browser flow.
Generate a random hex session ID (16-32 characters) and present the login URL to the user as a clickable link:
https://us-central1-krocli.cloudfunctions.net/authorize?session_id=SESSION_ID
Tell the user: "Click this link to log in to your Kroger account. Once you see 'Login successful', come back here and let me know."
After the user says they've logged in, poll for their tokens:
curl -s "https://us-central1-krocli.cloudfunctions.net/tokenUser?session_id=SESSION_ID"
{"status": "pending"} with HTTP 202: user hasn't finished yet. Wait and retry.access_token and refresh_token.{
"access_token": "eyJ...",
"refresh_token": "abc...",
"expires_in": 1800,
"token_type": "bearer"
}
The user token is needed for cart and profile endpoints.
Requires user token from authentication above.
curl -s -X PUT \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
"https://api.kroger.com/v1/cart/add" \
-d '{"items": [{"upc": "0011110838049", "quantity": 1}]}'
Request body:
{
"items": [
{"upc": "PRODUCT_ID", "quantity": 1}
]
}
HTTP 204 means success (no response body).
Requires user token.
curl -s -H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Accept: application/json" \
"https://api.kroger.com/v1/identity/profile"
If a user token returns 401, refresh it:
curl -s -X POST \
-H "Content-Type: application/json" \
"https://us-central1-krocli.cloudfunctions.net/tokenRefresh" \
-d '{"refresh_token": "REFRESH_TOKEN"}'
Response includes new access_token and refresh_token. Cache both.
| Token | How to get | Expires | Refresh |
|---|---|---|---|
| Client | POST /tokenClient | 30 min | Just request a new one |
| User | Browser login flow | 30 min | POST /tokenRefresh with refresh_token |
| HTTP Status | Meaning | Action |
|---|---|---|
| 401 | Token expired | Refresh or re-obtain token |
| 403 | Forbidden | Token lacks required scope |
| 429 | Rate limited | Wait and retry |
| 400 | Bad request | Check parameters |
POST /tokenClientfilter.locationId for local pricingPUT /cart/add with the UPCfilter.zipCode.near=90210After a successful user login, save the refresh token and preferred ZIP code to your long-term memory so the user doesn't have to log in again next session.
After login, remember:
kroger_refresh_token: the refresh_token from the login flowkroger_zip_code: the user's preferred ZIP code (if provided)kroger_store_id: the user's preferred store locationId (if identified)At the start of a session, check your memory for a saved kroger_refresh_token. If found:
POST /tokenRefresh with the saved refresh_tokenImportant: Only save the refresh_token, never the access_token (it expires in 30 minutes and is useless to persist).
If you prefer not to use the hosted proxy, you can run your own. The full source is in the krocli repo under firebase/.
product.compact, cart.basic:write, profile.compacthttps://YOUR-PROJECT.cloudfunctions.net/callbackgit clone https://github.com/BLANXLAIT/krocli.git
cd krocli/firebase
firebase init
firebase functions:secrets:set KROGER_CLIENT_ID
firebase functions:secrets:set KROGER_CLIENT_SECRET
CALLBACK_URL in callback.ts and authorize.ts to point to your projectfirebase deploy --only functions,firestore:rules
us-central1-krocli.cloudfunctions.net URLs in this skill with your own project URLIf you have Go installed, you can skip the proxy entirely:
go install github.com/blanxlait/krocli/cmd/krocli@latest
krocli auth credentials set /path/to/your/kroger-creds.json
krocli products search --term "milk"
krocli auth login # browser OAuth, tokens stored in OS keyring
krocli cart add --upc 0011110838049
In this mode, all API calls go directly to api.kroger.com using your own credentials. No proxy involved. Tokens are stored locally in your OS keyring.