# Grocery Cart Price & Deal Finder (`rustic_soybean/grocery-cart-price-deal-finder`) Actor

Compare grocery searches such as ham, milk, eggs near a ZIP code. Groups local in-stock listings into named-brand, store-brand, organic comparison tiers; normalizes unit prices; compares full and split carts; matches weekly-ad deals when product and chain align; and caps downstream source spending.

- **URL**: https://apify.com/rustic_soybean/grocery-cart-price-deal-finder.md
- **Developed by:** [Chris Johnson](https://apify.com/rustic_soybean) (community)
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Grocery Cart Price & Deal Finder

Enter ordinary grocery names and a ZIP code to compare nearby grocery listings and weekly-ad deals. You can type `ham`, `milk`, or `eggs`; a brand and package size are optional. Put a quantity at the start of a line, such as `2 x milk`, when you need more than one package.

### Who this helps

Shoppers comparing grocery prices and weekly-ad deals near a ZIP code using everyday item names.

### What you get

- Live retailer listings with the actual listing name, brand, package size, current price, reported regular price, sale status, and unit price when the source provides it.
- Reported in-stock status and the retailer branch's address when available.
- Retailer-reported unit prices converted to a shared base unit when the unit is recognized, so compatible package sizes can be compared.
- Product listings grouped into named-brand, store-brand, and organic tiers, with a choice to see all tiers, store-brand candidates only, or the same reported brand.
- Straight-line distance from the ZIP code center to branch coordinates, plus an in-radius full-cart comparison and a lowest-price split-basket estimate.
- Local weekly-ad deals with price and advertised validity dates.
- A separate coupon lead when returned flyer text explicitly mentions a coupon or digital offer.
- Carefully matched weekly-ad offers when the chain and product names line up and no package-size conflict is detected.
- Like-for-like basket comparisons showing the cheapest complete branch cart versus a split cart for the same product tier and variants, including the price difference.
- Links and timestamps for returned source records, plus source Actor run IDs, statuses, and reported usage charges in the summary.

The Actor keeps generic input convenient and returns the real product names for review. For example, a search for `ham` may return different cuts, brands, or package sizes. It does not assume those products are interchangeable. Product tiers are inferred from the source's brand and product tags plus a list of common store brands. A tier is a helpful grouping, not a guarantee of equivalence. Basket totals use each selected package's listed price times the requested quantity; they do not normalize package sizes.

### How local totals work

Store carts group listings by the exact branch ID returned by the shopping source. A store cart includes only listings explicitly reported in stock, with a known branch and distance within your selected radius. The distance is a straight-line estimate from the ZIP code center, not driving distance. A complete cart means a priced listing was found for every requested item at that branch; check the selected names, brands, and sizes before relying on the total.

The split-basket estimate selects the lowest observed in-stock package price for each item from eligible local offers. It may use several branches. When a branch has coordinates, offers outside the selected radius are excluded. If the source returns offers for your ZIP code but omits exact branch coordinates, those offers remain available in the split-basket estimate and are marked `zip_scoped_distance_unverified`; they are not claimed to be within the radius. Separate unit-price comparison records compare retailer-reported or package-derived prices on a shared basis, such as price per ounce or fluid ounce. They compare listings only within a product tier and variant group. If a large weight-based listing does not make clear whether its price is per pound or for the whole package, it is left out of unit-price rankings instead of being guessed. Tier labels and store-brand equivalence are inferred from listing names, brand fields, and source tags; they are candidate groupings, not proof that brands, cuts, or quality are equivalent. Basket comparison records show the exact products selected and compare a complete store cart with a split cart using the same tier and variant for each item. Tax, delivery, membership pricing, and checkout-only discounts are excluded.

Retailer sale prices are included in cart totals when the source reports them as current listing prices. A `weekly_deal_match` record is created only when the retailer chain matches and product names overlap strongly, with any detected package-size conflict rejected. The flyer source does not identify the exact branch, so flyer prices are never merged into cart totals. If the package size or promotion format is unclear, the record says the prices are not directly comparable. The Actor never subtracts coupon savings from a total. A coupon lead means the returned flyer text mentioned a coupon; check the store account, clipping requirements, item eligibility, limits, and checkout price.

### Inputs

- **Your grocery list:** one simple item per line, up to 25 items; optional quantity prefix such as `2 x milk`.
- **ZIP code:** five-digit U.S. ZIP code.
- **Search radius:** 1–100 miles, default 25.
- **Stores to include:** optional grocery retailer names. Leave empty to search up to the 8 closest recognized grocery chains found within the selected radius. Store discovery can also return unrelated businesses, which are excluded from product searches. A user-supplied retailer list overrides automatic selection.
- **Include weekly ads:** enabled by default.
- **Maximum source charges:** defaults to $1 per run, allocated across the downstream store, product, and flyer searches. The normal 4-item sample still allows up to 100 store records, 300 product records, and 40 flyer records under these caps. Set a lower cap for a smaller search or a higher cap for broader results.
- **Product matching:** compare all available tiers, store-brand candidates, or listings with the same reported brand.
- **Result caps:** tune live product and weekly-ad result counts to manage source usage.

Example:

```json
{
  "cartItems": ["ham", "milk", "eggs", "2 x bread"],
  "zipCode": "08234",
  "radiusMiles": 25,
  "includeFlyerDeals": true,
  "sourceSpendLimitUsd": 2,
  "matchMode": "all_tiers"
}
```

No provider API key is required in the input.

`all_tiers` is the default. It keeps store-brand candidates, other named brands, organic products, and unclassified listings in separate comparison groups. `private_label_equivalent` keeps listings classified as store brands. `exact_brand_only` keeps listings with a reported brand and groups by that brand. Each listing retains the brand and product name used to make the grouping, and the output marks product equivalence as unverified.

### Source usage and costs

This Actor calls two other Apify Actors under the account running it:

- `abotapi/instacart-grocery-price-scraper` discovers local stores and searches retailer listings. Its published price is $1.50 per 1,000 product or store results. It requires an Apify residential proxy; proxy usage can add cost, and the source notes that residential proxies are not included in the free plan.
- `gratifying_graph/us-grocery-deals` searches local weekly-ad deals when enabled. Its published pricing is $0.0005 per run start plus $0.002 per returned deal record.

These are separate source Actor charges in addition to any price for this Actor. Actual charges depend on results, proxy usage, and current source pricing. The run summary includes source run information and any usage charge values exposed by Apify.

The `sourceSpendLimitUsd` input allocates a total maximum across the downstream runs and passes each run an Apify spending cap and result cap. The default allocation reserves 15% for local-store discovery, 60% for product search, and the remainder for weekly ads. Without weekly ads, the product search receives the unallocated share. The summary lists each cap and result limit. If a source hits its allocated cap, its returned results may be partial. This does not cap the price of running this Actor itself.

### Dataset records

The dataset contains `retail_offer`, `unit_price_comparison`, `weekly_ad_deal`, `coupon_lead`, `weekly_deal_match`, `store_cart`, `basket_comparison`, and `split_basket` records. The summary is saved as the `SUMMARY` key-value record. Retail offers and flyer deals stay separate so an agent or person can tell observed shelf listings from advertised offers. Store-cart totals include a comparison profile; only compare them as like-for-like when their profile keys match. Each record carries its source, evidence, and limits where available.

This Actor does not place orders, access retailer accounts, or verify checkout prices.

### Related Actors

- [Exact-SKU Shopping Comparison](https://apify.com/rustic_soybean/exact-sku-shopping-comparison) — Compares supplied offers for the exact same product code.
- [Social Purchase Intent API](https://apify.com/rustic_soybean/social-purchase-intent-api) — Finds public social posts that signal purchase interest.

# Actor input Schema

## `cartItems` (type: `array`):

Enter one simple item per line: ham, milk, eggs. Brand and package size are optional. To request multiple packages, start a line with a quantity, such as 2 x milk.

## `zipCode` (type: `string`):

U.S. ZIP code used to find local grocery stores and weekly ads.

## `radiusMiles` (type: `integer`):

Exact in-radius cart totals use known branch coordinates. ZIP-scoped offers without coordinates may still appear in the split-basket estimate, clearly marked with distance unverified.

## `retailers` (type: `array`):

Optional store or chain names, one per line. Leave blank to search up to the 8 closest recognized grocery chains; unrelated businesses found during store discovery are skipped.

## `includeFlyerDeals` (type: `boolean`):

Looks for current local flyer prices and flags coupon mentions when the flyer source explicitly includes them.

## `sourceSpendLimitUsd` (type: `number`):

Hard total cap for downstream store, product, and weekly-ad source charges. Defaults to $1; the normal 4-item example still permits up to 100 store records, 300 product records, and 40 flyer records. This does not include this Actor's own run price.

## `matchMode` (type: `string`):

Choose whether to compare all product tiers, store-brand candidates only, or listings with the same reported brand. Generic item names still work.

## `maxProducts` (type: `integer`):

Caps upstream product records to control run size and source charges.

## `maxFlyerDealsPerItem` (type: `integer`):

Caps weekly-ad deal results returned for each grocery item.

## Actor input object example

```json
{
  "cartItems": [
    "ham",
    "milk",
    "eggs",
    "bread"
  ],
  "radiusMiles": 25,
  "retailers": [],
  "includeFlyerDeals": true,
  "sourceSpendLimitUsd": 1,
  "matchMode": "all_tiers",
  "maxProducts": 300,
  "maxFlyerDealsPerItem": 10
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset records include retail offers and comparisons; the split_basket record includes selected offers, ZIP scope, and a distance warning when exact branch coordinates are unavailable.

## `summary` (type: `string`):

Source run caps and status, source spending limit, store coverage, distance, stock, unit-price basis, sale, flyer-match, and coupon evidence.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "cartItems": [
        "ham",
        "milk",
        "eggs",
        "bread"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("rustic_soybean/grocery-cart-price-deal-finder").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "cartItems": [
        "ham",
        "milk",
        "eggs",
        "bread",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("rustic_soybean/grocery-cart-price-deal-finder").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "cartItems": [
    "ham",
    "milk",
    "eggs",
    "bread"
  ]
}' |
apify call rustic_soybean/grocery-cart-price-deal-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rustic_soybean/grocery-cart-price-deal-finder"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/UsNmX5LFgegC6p4Af/builds/2eRHxPvjqwK6J03eT/openapi.json
