By Varun Mahajan, FounderPublished Last updated Part of the quick commerce data and api guideMore on quick commerce
What you need, and what it costs
The tracker is one Python file. It asks the Rewalto API for the Blinkit readings at one pin code, keeps each one in a SQLite file with the time it was read, and then prints every product whose price or stock changed between its two newest readings. You never open Blinkit and you never run a browser. Everything comes from one documented read, GET /v1/data/observations.
- Python 3.9 or newer, and the
requestspackage. SQLite ships with Python. - A Rewalto API key with the
data:readscope. Every account gets 1,000 free credits a month. - A six-digit pin code Rewalto holds for Blinkit. The live list is below and on the Blinkit data page.
Reads cost 1 credit per 10 records delivered, rounded up per page. A page of 100 records is 10 credits. Reading the same records again within seven days is free, and a page that comes back empty costs nothing. With the free 1,000 credits a month that is 10,000 records; that figure is arithmetic from the published rate, not a promise of what one pin code holds. The credits reference has the full rules.
The current pin codes, refresh and rate for Blinkit are read from the Rewalto data catalogue each time this page is served. The commerce data page lists them too.
The whole script, 64 lines
This is the exact file we ran against the live API on 1 November 2026. Save it as blinkit_tracker.py. It takes three arguments: the pin code, how many days back to read, and an optional brand. The key comes from the environment, never from the file.
import os, sqlite3, sys, time
from datetime import datetime, timedelta, timezone
import requests
BASE = "https://api.rewalto.com"
HEAD = {"Authorization": f"Bearer {os.environ['REWALTO_API_KEY']}"} # keep the key out of the code
PIN = sys.argv[1] if len(sys.argv) > 1 else "560001" # a six-digit pin code Rewalto holds for Blinkit
DAYS = int(sys.argv[2]) if len(sys.argv) > 2 else 1 # read only the last day; the API default is 30
BRAND = sys.argv[3] if len(sys.argv) > 3 else None # exact text, case-sensitive, as Blinkit wrote it
MAX_PAGES = 10 # at most 1,000 records, 100 credits, per run
def read_blinkit(pincode, since, brand=None):
"""Yield Blinkit readings for one pin code, newest first, following the cursor."""
params = {"retailer": "blinkit", "pincode": pincode, "from": since, "limit": "100"}
if brand:
params["brand"] = brand
pages = tries = 0
while pages < MAX_PAGES:
r = requests.get(f"{BASE}/v1/data/observations", params=params, headers=HEAD, timeout=60)
if r.status_code == 402:
sys.exit("Out of credits: " + r.json()["error"]["message"])
if r.status_code in (429, 500, 503) and tries < 4: # retry the same page a few times
tries += 1
time.sleep(int(r.headers.get("Retry-After", 2 ** tries)))
continue
r.raise_for_status()
body, pages, tries = r.json(), pages + 1, 0
print(f"page {pages}: {len(body['data'])} records, {body['meta']['credits']['charged']} credits")
yield from body["data"]
if not body["page"]["nextCursor"]:
return
params["cursor"] = body["page"]["nextCursor"] # same filters, next page
def main():
db = sqlite3.connect("blinkit_prices.db")
db.execute("""create table if not exists price (
sku text, pin text, observed_at text, title text, brand text,
price_paise integer, mrp_paise integer, in_stock integer,
primary key (sku, pin, observed_at))""")
since = (datetime.now(timezone.utc) - timedelta(days=DAYS)).strftime("%Y-%m-%dT%H:%M:%SZ")
new = 0
for row in read_blinkit(PIN, since, BRAND):
stock = row["inStock"] # true, false or null; null stays null, never "out of stock"
new += db.execute("insert or ignore into price values (?,?,?,?,?,?,?,?)", (
row["retailerSku"], row["pincode"], row["observedAt"], row["title"], row["brand"],
row["priceMinor"], row["mrpMinor"], None if stock is None else int(stock))).rowcount
db.commit()
print(f"stored {new} new readings for pin code {PIN}")
# What changed: each product's newest reading against the one before it.
q = """select title, observed_at, price_paise, in_stock, prev_price, prev_stock from (
select title, observed_at, price_paise, in_stock,
lag(price_paise) over (partition by sku order by observed_at) as prev_price,
lag(in_stock) over (partition by sku order by observed_at) as prev_stock,
row_number() over (partition by sku order by observed_at desc) as rn
from price where pin = ?) where rn = 1"""
for title, at, price, stock, prev_price, prev_stock in db.execute(q, (PIN,)):
if None not in (price, prev_price) and price != prev_price:
print(f"PRICE {title}: Rs {prev_price / 100:.2f} to Rs {price / 100:.2f} (read {at})")
if None not in (stock, prev_stock) and stock != prev_stock:
print(f"STOCK {title}: {'back in stock' if stock else 'out of stock'} (read {at})")
if __name__ == "__main__":
main()
python3 -m venv venv && . venv/bin/activate
pip install requests
python blinkit_tracker.py 560001 7 DoveThe steps below take the script apart in the order it runs. If you only want it working, the two blocks above are enough.
Step 1: get a key and check it
Create an API key in your Rewalto account with only the data:read scope, and keep it in your shell or your secret store, not in the code. Then check it. The identity call costs nothing and starts no data read; it tells you which organisation the key belongs to and which scopes it carries.
export REWALTO_API_KEY="rwk_..." # your key, from your own secret store
curl https://api.rewalto.com/v1/whoami -H "Authorization: Bearer $REWALTO_API_KEY"A 401 here means the key is missing, mistyped, expired or revoked. Fix that before you go further. The first request guide and the API keys reference cover creating, rotating and revoking keys.
Step 2: read one pin code
If you want to see the shape of a record before you spend anything, call the free sample first. It needs no key and returns real rows that are each at least seven days old.
curl "https://api.rewalto.com/v1/data/samples?dataset=price_history"The function read_blinkit in the script makes the paid read. It sends retailer=blinkit, the pin code, a from time and limit=100, plus the brand when you give one. The brand is matched exactly and is case-sensitive, so write it as Blinkit writes it. Without from the API reads the last 30 days, which at a busy pin code is a lot of records; the script asks for one day unless you say otherwise.
Each record carries the retailer, the retailer’s product id, the pin code, the time it was read, the title, brand and pack size, the price and MRP, the currency, the in-stock flag and the source address. Prices come in paise: divide by 100 for rupees. A price that could not be read is null, never 0. The data reference lists every field and filter.
Step 3: follow the cursor and respect the limits
A response holds up to limit records, newest first, and a page.nextCursor value. When it is not null, the script sends it back as cursor with exactly the same filters to get the next page. A cursor sent with different filters is refused, so never change the brand or the time window halfway through a loop.
Each page reports what it cost in meta.credits.charged, and the script prints it, so you see the spend as it happens. MAX_PAGES stops a run after ten pages, at most 100 credits, however much the pin code holds. Raise it once you know what a run costs you.
Two answers stop or slow the loop. A 402 means your credits cannot cover the next page, and the script exits rather than retrying. A 429 means you hit the rate limit; the script waits for the time in the Retry-After header and asks for the same page again. It does the same, a few times only, for a 500 or 503, which the contract marks as safe to retry a bounded number of times. The errors reference lists every code.
Step 4: store every reading
The table is keyed by product id, pin code and the time of the reading, and the insert ignores a row it already has. That makes a second run over the same window harmless: nothing is stored twice, and the API does not charge again for records you read in the last seven days.
SQLite is enough for one pin code and a handful of brands for a long time. When you track many pin codes, or want a dashboard on top, move the same table to Postgres or any database you already run. Keep the same three columns as the key, and the rest of the script does not change.
Keep the time of every reading. A price without its time cannot be checked, and it cannot be set beside tomorrow’s reading. Keep prices in paise as whole numbers, so nothing is lost to rounding. And never turn a missing value into a guess: a null price stays null, and a null stock flag stays null rather than becoming “out of stock”.
Step 5: print what changed
The last query uses two window functions. For each product, lag finds the reading before the newest one and row_number picks the newest. When both prices are known and differ, the script prints a price line; when both stock flags are known and differ, it prints a stock line. A product read only once prints nothing, because there is nothing to compare yet.
Here is the output of the run on 1 November 2026 at 5:49 pm IST: pin code 560001, the last seven days, brand Dove, starting from an empty file. It read 176 records for 18 credits and found 11 price changes. These are that run’s numbers, kept as an example; your run will show what Blinkit showed at your pin code on your day. The script prints each reading’s time exactly as the API sends it; below, those times are shown in IST.
page 1: 100 records, 10 credits
page 2: 76 records, 8 credits
stored 176 new readings for pin code 560001
PRICE Dove Intense Repair Hair Conditioner: Rs 235.00 to Rs 220.00 (read 1 Nov 2026, 2:38 AM IST)
PRICE Dove Daily Shine Hair Conditioner: Rs 214.00 to Rs 200.00 (read 1 Nov 2026, 2:38 AM IST)
PRICE Dove Body Love Supple Bounce Body Lotion (400 ml): Rs 416.00 to Rs 384.00 (read 29 Oct 2026, 7:17 AM IST)
PRICE Dove 3% Vitamin C Brightening Body Wash: Rs 340.00 to Rs 320.00 (read 1 Nov 2026, 1:52 AM IST)
PRICE Dove 5% Niaciamide Serum Body Wash: Rs 340.00 to Rs 320.00 (read 29 Oct 2026, 7:19 AM IST)
PRICE Dove Exfoliating Body Wash: Rs 465.00 to Rs 434.00 (read 29 Oct 2026, 7:19 AM IST)
PRICE Dove Peptide Bond Strength Leave in Conditioner: Rs 315.00 to Rs 337.00 (read 30 Oct 2026, 12:09 AM IST)
PRICE Dove Original Deodorant Roll on (for Women): Rs 182.00 to Rs 156.00 (read 1 Nov 2026, 2:02 AM IST)
PRICE Dove Beautiful Curls 10-In-1 Hair Mask: Rs 247.00 to Rs 232.00 (read 1 Nov 2026, 1:31 AM IST)
PRICE Dove 10 in 1 Peptide Bond Strength Hair Mask: Rs 234.00 to Rs 220.00 (read 1 Nov 2026, 1:30 AM IST)
PRICE Dove Hair Fall Rescue Conditioner: Rs 235.00 to Rs 220.00 (read 1 Nov 2026, 2:38 AM IST)The same command run again two minutes later stored nothing new and was charged nothing, because every record had already been read within seven days:
page 1: 100 records, 0 credits
page 2: 76 records, 0 credits
stored 0 new readings for pin code 560001Step 6: run it daily
Blinkit is read every day, so a daily run is enough. Keep the key in a file only you can read, such as .env with the line export REWALTO_API_KEY="...", and let cron start the script each morning. Ask for one day back, so each run reads only what is new.
30 7 * * * cd $HOME/blinkit-tracker && . ./.env && venv/bin/python blinkit_tracker.py 560001 1 Dove >> tracker.log 2>&1Send the output to a log file, as the line above does, and read it once a week at first. A run that stops early prints the reason on its last line: out of credits, a key problem or a page the API could not answer after a few tries. Nothing is lost when a run fails, because the next run asks for the same window again and the database ignores what it already has. If you miss a few days, run the script once by hand with more days back and it fills the gap.
The cost follows from the rate. In the example run one brand at one pin code came to 176 records over seven days, so a daily run for the same brand would read about a seventh of that, a few credits a day. Arithmetic from the published rate: 1,000 free credits a month cover 10,000 records, so a few brands at a few pin codes fit inside the free credits. A whole pin code with no brand filter can hold far more, which is what MAX_PAGES is for.
Make it better
- Several pin codes in one read: send
locationwith a city, area or dark store id from the free location lookup, plusconfirmPinswith the number of pin codes it resolves to. The API refuses a different number, so you always agree to the size of the read first. - The same product across apps: filter by
productIdinstead of brand, and drop the retailer filter, to set a product’s Blinkit readings beside its readings on other apps. - One product at one place: filter by
retailerSkutogether with the retailer, since a retailer’s product id is unique only within that retailer. - A quick check by hand: the free pin-code availability tool checks one brand at one pin code with no key.
- From an AI agent: the MCP server (preview) has a
list_observationstool that reads the same records at the same rates; see the MCP guide (preview).
What this tracker cannot tell you
The readings describe what Blinkit showed shoppers at the pin codes and times read. They are not sales and not demand, and they say nothing about how fast a product moves. A missing reading is unknown, not out of stock. A price is what a shopper saw at that pin code and time, before coupons, bank offers, membership prices and delivery fees, so it is not a checkout total.
Rewalto reads Blinkit’s public search results the way a shopper sees them, and keeps each reading with its source address, its time and an evidence hash of the response read; the response itself is not kept. Rewalto is not affiliated with or endorsed by Blinkit, and is not a partner of Blinkit. Blinkit is a trademark of its owner. Rewalto’s API serves what Blinkit shows shoppers, read from its public pages with the pin code and time of each reading. It is not Blinkit’s own API or feed.
If you are still weighing whether to build your own collection instead, the Blinkit scraper alternative guide sets out the work a scraper keeps asking for.
Troubleshooting
401: the key is missing, wrong, expired or revoked. Run the identity check from step 1.403: the key lacks thedata:readscope. Create one that has it.402: the credits left cannot cover the next page, so the API sends no data and the script stops. Credits reset each month.429: too many requests. Wait for the reset in theRetry-Afterheader and try the same page again.- An empty list: nothing matched your filters in that window. It costs nothing. Check the brand’s exact spelling and widen the days.
400on a later page: the cursor was sent with different filters. Start the loop again without a cursor.500or503that keeps coming back: quote thex-request-idheader of the response when you report it.
See everything Rewalto reads, and start free, at rewalto.com.
Common questions
How do I build a Blinkit price tracker in Python?
Call GET /v1/data/observations on the Rewalto API with retailer=blinkit and a six-digit pin code, store each reading with its time in a database, and compare each product's two newest readings. The tutorial on this page has the full script, and the output of a dated run.
Is there a Blinkit API I can use for prices?
Rewalto's API gives you Blinkit prices by pin code. It serves what Blinkit shows shoppers, read from its public pages and kept with the pin code and time of each reading. It is not Blinkit's own feed.
How much does it cost to track Blinkit prices with the API?
Reads cost 1 credit per 10 records delivered, and every account gets 1,000 free credits a month, which is 10,000 records at that rate. Re-reading the same records within 7 days is free, and an empty page costs nothing. Rupee prices on the site are excluding GST.
Can I track Blinkit stock as well as price?
Yes. Every reading carries an in-stock flag, which is true, false or null when the page had no signal. A missing reading means unknown, not out of stock.
Which Blinkit pin codes can I track?
The pin codes Rewalto holds for Blinkit are listed in the catalogue and on the Blinkit data page, and a fresh read can be requested at any pin code. The rate is shown before a read runs.
Can an AI agent do this instead of a script?
Rewalto's MCP server is in preview at mcp.rewalto.com/mcp, and its list_observations tool reads the same records at the same rates. A script is the safer choice for a daily job today.
Does this scrape Blinkit?
No. The script reads Rewalto's API only. Rewalto reads Blinkit's public search results the way a shopper sees them and keeps the records; you never touch Blinkit.