A crawl of 104,945 petrol-pump records from a public API, plus extractors and gap-analysis maps. This post shows the one cleaning step you must do first, and the state-by-state coverage it gives you.
Open-Source Tools · How-To · Energy & fuels models
How to use fuel-retail-outlets: see where India's petrol pumps are, state by state
Revised
· v1.0.0 · what changed
Code: github.com/herrrickshaw/fuel-retail-outlets
Watch the walkthrough
Watch on YouTube: youtu.be/_4NBKi2NCGI
Why it is useful
- Who benefits: fuel-retail, CNG and EV-charging planners, consultants and students who need a pump-level list of India with location, company and fuel type.
- What it replaces: collecting listings from each oil company's locator one by one.
- Evidence from the run: counted naively, Delhi appears to have 21,939 pumps; after removing duplicate rows it has 419. The raw file also holds 22,343 duplicate rows (21.3%). If you skip the cleaning step, every state count is wrong.
- After cleaning, the per-capita view shows a clear spread: Bihar 2.7, West Bengal 2.8 and Jharkhand 3.4 pumps per 100,000 people, against Punjab 11.5 and Haryana 11.3.
What it is for
This repo collects Indian petrol, diesel and CNG outlet listings from public sources (the SSRI petrol-pump API, the BPCL dealership locator and CashAtPOS), with two small web apps for the map and a coverage gap-analysis heatmap.
The data is indicative, for planning and visualisation. It is not an official registry. Outlet records are public business listings.
Who it is for
- Energy and mobility analysts sizing pump or charger networks
- Students working on India fuel-retail geography
- Anyone who needs a raw outlet list to join with district or population data
- Regulatory or legal use; it is not an official registry (PPAC publishes the official totals)
- Using raw counts without removing duplicates first
- Real-time prices; the prices in the crawl are a snapshot
What you need
| Requirement | Why | How to get it |
|---|---|---|
| git and a terminal | To clone the repo | Terminal on macOS/Linux, WSL/Git Bash on Windows; or GitHub Codespaces |
| Python 3 (standard library only for the steps shown) | The sample reads a gzipped JSON-lines file | python.org, or brew install python |
| Internet only if you re-crawl | crawl_ssri.py calls the public API (about 6 minutes, per the repo notes). Not needed for the sample. | pip install requests, then python api-data-integration/crawl_ssri.py |
| API keys, accounts, licences | None needed for the steps shown | Nothing to sign up for; the sample commands read files already in the repo |
Get the code and an AI assistant
You do not have to be a programmer. Get the repository, give it to an AI assistant, and ask in plain language. Any of these routes works:
| Tool | What you need | Best for |
|---|---|---|
| GitHub | Free account to fork or star; git to clone, or the green Code button, then Download ZIP, or open in Codespaces | Getting the code and keeping up with updates |
| Claude Code | Claude subscription or API key; run claude inside the cloned folder | Letting the AI read and run the whole repo |
| Gemini CLI | Google account; run gemini inside the cloned folder | The same hands-on workflow with Gemini |
| Claude.ai, Gemini or ChatGPT in the browser | A chat account; upload README.md and the files you care about (or paste the output of git ls-files) | Understanding the project and asking questions without installing anything |
| Other tools (Copilot Chat, Cursor, Codex CLI) | Open the cloned folder in the tool and point it at README.md first | Editing and extending the code |
git clone https://github.com/herrrickshaw/fuel-retail-outlets.git
cd fuel-retail-outlets
claude # or: gemini
Install
- Clone the repository (needs git)
git clone https://github.com/herrrickshaw/fuel-retail-outlets.git cd fuel-retail-outlets - Nothing to install for the sample below. For the web apps, serve a folder with Python
cd fuel-station-gap-analysis && python3 -m http.server 8001
Quick start: commands and what you should see
Load the committed crawl and deduplicate it the way the repo's notes describe
python3 -I - <<'E'
import gzip,json,collections
p='api-data-integration/outlet_data_ssri_complete/ssri_pumps_raw_20261016.jsonl.gz'
rows=[json.loads(l) for l in gzip.open(p,'rt') if l.strip()]
k={}
for r in rows:
key=(r['name'],r['address'],r['company'],r['latitude'],r['longitude'])
if key not in k or r['id']>k[key]['id']: k[key]=r
u=list(k.values())
print(len(rows),len(u),len(rows)-len(u))
print(collections.Counter(r['company'] for r in u).most_common(5))
E
104945 82602 22343, then the company counts: BPCL 25,795, HPCL 23,543, IOCL 19,446, Nayara 9,007, Unknown 2,504.
Open the gap-analysis heatmap
cd fuel-station-gap-analysis && python3 -m http.server 8001
Visit http://localhost:8001 to see the state-level heatmap. The page loads its map tiles from the internet. I did not open it in this run.
Sample outputs
Real output from a run on the date shown in the sources line; trimmed to fit.
Why you must deduplicate: Delhi, raw versus cleaned
raw rows with state == 'Delhi' : 21,939
of which district 'New Delhi' : 21,572, all IOCL-heavy
sitting on only 57 distinct coordinates (3,986 identical rows on each of several points)
after dedup (name+address+company+lat+lon): 419
The repo's own notes (SSRI_REEXTRACTION_20260712.md) document this; the 16 Oct 2026 file is still raw, so you have to apply the step yourself. My dedup gives 82,602; the note's earlier snapshot gave 82,609.
Pumps per 100,000 people by state (cleaned; state populations from the repo's gap-analysis data.js)
state pumps per 100k people per 1000 km2
Uttar Pradesh 8,915 4.5 37.0
Maharashtra 7,317 6.5 23.8
Tamil Nadu 5,812 8.1 44.7
Madhya Pradesh 5,320 7.3 17.3
Karnataka 5,268 8.6 27.5
-- lowest (states with 100+ pumps) --
Delhi 419 2.5 282.5
Bihar 2,779 2.7 29.5
West Bengal 2,522 2.8 28.4
Jharkhand 1,109 3.4 13.9
Assam 1,108 3.6 14.1
-- highest --
Arunachal Pradesh 201 14.6 2.4
Punjab 3,204 11.5 63.6
Haryana 2,855 11.3 64.6
Telangana 3,609 10.3 32.2
Delhi's low per-capita number reflects a dense city counted against its whole population and is not a real gap; read the table as a starting screen, not a verdict.
Data-quality check on state names
state values in the raw file: 53 spellings
unmatched to the 35 states in data.js after dedup: 10,532 of 82,602 outlets
'unknown' (all Nayara): 9,007
'Jharkand': 593, 'Jammu And Kashmir': 333, 'Jammu & Kashmir': 230 ...
matched: 72,070
Only the matched outlets feed the table above, so the table understates states with spelling variants (I mapped Jharkand, Uttrakhand and Jammu variants) and cannot place Nayara's 9,007 outlets by state at all.
Ways to use it
| Method | How it works |
|---|---|
| Python / pandas | Read the .jsonl.gz, deduplicate, then group by state, district or company. |
| Web maps | Serve fuel-pump-locations-map or fuel-station-gap-analysis with python3 -m http.server. |
| Re-crawl | Run api-data-integration/crawl_ssri.py for a fresh snapshot (not run here). |
| Through an AI assistant | Open the folder in Claude Code or Gemini CLI and ask it to deduplicate the crawl and rank states; or upload README.md and REBUILD_NOTE.md to a chat assistant. |
Sample prompts for your AI assistant
Copy, paste and edit the parts in [brackets].
- Claude: Read REBUILD_NOTE.md and SSRI_REEXTRACTION_20260712.md, then write a script that deduplicates the crawl and prints pumps per state.
- Gemini: Using the crawl, find the ten districts with the most CNG pumps and explain how you handled spelling variants of state names.
- ChatGPT: Here is a table of pumps per 100,000 people by state. Which states look under-served and which numbers are probably artefacts?
- GitHub (Copilot Chat or Codespaces): Write a function that normalises the 53 state spellings in the crawl to one canonical name per state or UT.
- Claude: Compare the deduplicated total with the PPAC baseline described in PPAC_RETAIL_OUTLETS_MAY2026.md and explain the gap.
- Any assistant: Suggest how to join this outlet list with district population to find gaps for EV charging.
Limits and honest caveats
- Raw data contains about 21% duplicate rows; always deduplicate. In the 16 Oct 2026 file Delhi shows 21,939 rows before cleaning and 419 after.
- Even after cleaning, 82,602 outlets compares with a PPAC official baseline of 103,450 (May 2026) in the repo's notes, so coverage is roughly 80%.
- State names are inconsistent (53 spellings) and all 9,007 Nayara outlets have state 'unknown', so state tables miss them unless you geocode by coordinates.
- Population figures in the gap-analysis data.js are older census-based numbers; per-capita values are indicative.
- Not an official registry. Prices and timings are a snapshot.
- The README refers to files removed in the LFS-free rebuild (derived maps and unified DB); they must be regenerated by the scripts. I did not run the extractors, web apps or any network call; only the committed crawl was read.
Sources: Read the committed crawl api-data-integration/outlet_data_ssri_complete/ssri_pumps_raw_20261016.jsonl.gz and fuel-station-gap-analysis/data.js from github.com/herrrickshaw/fuel-retail-outlets (commit 266995b) with the Python standard library on 19 October 2026. Outlet names and addresses were not reproduced; only aggregates are shown. Extractors, web apps and network crawl not run.
- v1.0.0 — 29 October 2026 — first published.
About this article: Researched, written and edited by Umashankar Triplicane Dwarakanathan, with AI research assistance; every figure is meant to trace to the primary source cited. See the Editorial Policy for how sourcing, AI use and corrections work.