As of October 7, 2026, Shifter has the largest pool of live US IPs, more than Oxylabs and Bright Data, at a fraction of the cost.Shifter now has the largest pool of live US IPs

See benchmarks

Grocery Price Monitoring: Tracking Delivery Apps & Retailer Sites by City

How to monitor grocery prices across cities: why the same product costs more in one store than another, how delivery apps pick a store, and a city-by-city collection setup with residential proxies.

Industry Solutions · Updated October 30, 2026 · 6 min read
citiesbasket price
One basket, priced store by store in five cities. The amber dots are the same basket in a delivery app.
Knowledge
On this page
  1. Where grocery prices vary
  2. How delivery apps and grocer sites pick a store
  3. Building the basket
  4. Collecting city by city
  5. Reading delivery apps
  6. Keeping the data clean
  7. The bottom line

Grocery prices are local. A carton of eggs can cost one price in a suburban store, another in the city centre, and a third in a delivery app that adds its own markup to the same shelf. If you price against local rivals, check a brand’s promotions or follow food inflation by region, you need prices from each city you care about, not one national average. That is a core price intelligence job, and it is harder for groceries than for most retail.

This guide explains where grocery prices vary, how delivery apps decide which store you see, and how to set up a collection that reads each city the way a local shopper does.

Where grocery prices vary

Grocers rarely run one price list. The usual layers are:

  • Price zones. Chains group stores into zones by local competition and costs. Two stores of the same chain, a few kilometres apart, can sit in different zones.
  • Store-level promotions. Weekly flyers and loyalty offers often differ by region, and some deals are only valid in selected stores.
  • Delivery app markups. Third-party apps may show prices above the in-store shelf price, plus service and delivery fees that change by area and time of day.
  • Availability. An item can be in stock in one store and missing in another, which changes what a basket really costs.
  • Pack sizes and own brands. The same product line can come in different sizes by region, which hides price changes unless you compare unit prices.

A single national scrape blends all of this into one misleading number. You need the store, the city and the channel attached to every price you record.

How delivery apps and grocer sites pick a store

Most grocery sites will not show a full catalogue until they know where you are. They decide in roughly this order:

  1. A saved store or address, from a cookie or the account.
  2. The address or postcode you type into the store picker or delivery check.
  3. Your IP location, as a first guess before you choose anything.

That has a practical consequence. The IP gets you into the right city and makes the first guess land near the store you want. The exact store, down to the postcode, is set by the address you give the site. So a reliable setup does both: a residential IP in the target city, and the store or delivery address entered in the same session, so the two never disagree. Our post on when city-level proxy targeting matters covers why a mismatch between IP and chosen location can change what a site serves.

Building the basket

Before collecting anything, fix what you will compare:

  • A fixed basket of 50 to 300 products: staples, your own top sellers and the items your rivals promote most.
  • A matching key for each product, such as the barcode (GTIN) where the site exposes it, otherwise a brand, name and size match you check by hand once.
  • Unit price (per kg, per litre, per unit) next to the shelf price, so pack-size changes do not look like price changes.
  • A store list per city: which stores and which delivery areas represent that city for you.

Keep the basket stable. Changing it every week makes trends impossible to read.

Collecting city by city

For each city, open a session through residential proxies targeted at that city, set the store in the site, then read the basket. Keep one IP for the whole session with a sticky session ID, so the site does not see the shopper jump between locations halfway through.

customer-USERNAME-country-us-city-chicago-sid-chi-store-118-ttl-900:PASSWORD

The session ID (sid) keeps the same exit for up to the ttl in seconds. Use one ID per store, so each store visit looks like one shopper. For a large market, spread the work across its main cities, for example Chicago, Dallas and Atlanta on the United States pages, instead of reading the whole country from one place.

A minimal loop in Python looks like this:

import requests

GATEWAY = "p.shifter.io:443"
USER, PASS = "USERNAME", "PASSWORD"

def session_for(city, store_id):
    s = requests.Session()
    proxy = f"http://customer-{USER}-country-us-city-{city}-sid-{city}-{store_id}-ttl-900:{PASS}@{GATEWAY}"
    s.proxies = {"http": proxy, "https": proxy}
    return s

def read_basket(city, store_id, products):
    s = session_for(city, store_id)
    # 1. Set the store the way the site expects (store picker or address check).
    s.post("https://grocer.example/api/store/select", json={"storeId": store_id}, timeout=30)
    rows = []
    for p in products:
        r = s.get(f"https://grocer.example/api/product/{p['sku']}", timeout=30)
        if r.status_code != 200:
            rows.append({**p, "city": city, "store": store_id, "error": r.status_code})
            continue
        d = r.json()
        rows.append({**p, "city": city, "store": store_id,
                     "price": d.get("price"), "unit_price": d.get("unitPrice"),
                     "promo": d.get("promotion"), "in_stock": d.get("available")})
    return rows

The endpoints here are placeholders. Many grocer sites load prices from a JSON endpoint after the store is set; reading that endpoint is lighter and more stable than parsing the page.

Reading delivery apps

Delivery apps add two things you must record separately: the item price in the app and the fees. Capture:

  • Item price in the app next to the shelf price from the grocer’s own site, to measure the markup.
  • Service and delivery fees for a fixed basket value, since fees often depend on the order total.
  • Time of collection, because fees and availability shift during the day.

Compare like with like: same store, same basket, same hour.

Keeping the data clean

  • Store every price with city, store, channel, time and unit price. Without the store, you cannot explain a change.
  • Flag promotions instead of averaging them in. A two-week deal is not a price cut.
  • Watch for missing items. An empty price is often an out-of-stock, which is a signal in itself.
  • Check for personalised prices. Logged-in loyalty prices can differ from guest prices. Collect as a guest unless loyalty pricing is what you study. Our guide to detecting geo-personalized and dynamic pricing shows how to separate the two.
  • Collect only public prices, at a polite rate, and respect each site’s terms.

The bottom line

A grocery price only means something with its city, store and channel attached. Fix a basket, decide which stores stand for each city, enter each city through a residential IP located there, set the store inside the site in the same session, and record unit prices, promotions and fees separately. Run it weekly for staples and daily for the items you compete on, and you will see local price moves as they happen instead of one blurred national number.

Frequently asked questions

What is grocery price monitoring?

It is the regular collection of shelf and delivery prices for a fixed basket of grocery products, store by store and city by city. Retailers use it to price against local rivals, brands use it to check promotions and price rules, and analysts use it to follow food inflation by region.

Why do grocery prices differ between cities?

Grocers set prices per store or per price zone, based on local competition, rent, delivery costs and demand. Delivery apps add their own markups and fees on top of the store price. The same item can therefore show several prices on the same day, depending on where the shopper is.

Can I monitor grocery prices by ZIP code with proxies?

Proxies place you in a city, not in a ZIP code. On most grocery sites the exact store is chosen by the address or store picker, not by the IP. The reliable setup is a residential IP in the right city, plus the store or delivery address set inside the site, in the same session.

How often should grocery prices be collected?

Weekly is enough for most staples, since many grocers change prices on a weekly promotion cycle. Collect daily for fresh produce, items on promotion and categories you compete on hardest, and right after a known promotion starts.

Ready to get started?

Try Shifter's residential proxies, 205M+ IPs, 195+ countries, from $0.10/GB.

Get Started