M09 · Grid Ranking geo-grid SEO heatmap for restaurant chains

The decision, in one line

Decodo Scraper API · target=google_maps + custom DOM parse, anchored on Places-API-geocoded outlet lat/lng. $0.001 per pin, 5-8 s, returns 1-20 rank depth with 13 per-place fields (rating, reviews, category, address, hours). 5× the brand-visibility coverage of the Search local-pack 3-pack at the same cost.

12case studies
4brands
3cities
1,549Decodo queries
$1.55total spend
54%avg pin coverage

Case studies 14

Live Decodo Scraper API runs on real outlets. Each card has a thumbnail of the area (Google Static Maps) and links to the interactive heatmap. Hover any pin on the heatmaps to see the top-10 ranked competitors with ratings.

dominance Method C

Toit

Indiranagar · Method C (Maps top-20) · Bangalore

5×5 · 1 km · 25 pins

Toit dominates craft-beer queries across Bangalore. Hover pins to see the full Bier Library/BLR Brewing/Indian Biere House landscape Toit is competing in.

keywordcoverageSoLVAGR
best brewery bangalore88%56%2.95
craft beer bangalore96%96%1.00
drop-off Method A

Toit

Indiranagar (extended) · Bangalore

11×11 · 1.5 km · 121 pins

11×11 1.5 km — Toit's brand catchment across the city for craft-beer queries.

keywordcoverageSoLVAGR
best brewery bangalore98%3%8.83
craft beer bangalore43%42%2.17
variation Method A

Toit

Indiranagar (flagship brewpub) · Bangalore

7×7 · 1 km · 49 pins

Even branded queries return rank 2-4 here — useful demo of yellow/green mixing across pins.

keywordcoverageSoLVAGR
toit indiranagar100%0%4.00
best brewery bangalore100%18%7.82
craft beer indiranagar100%100%2.29
dominance Method C

Anardana

Sangam Courtyard · Method C (Maps top-20, geocoded) · Delhi NCR

5×5 · 0.5 km · 25 pins

5×5 / 0.5 km. Outlet coords resolved via Google Places API (place_id ChIJbZCrwQQdDTkRC7ARXvyMSsY). Previous coord guess was 1.4 km off — corrected version shows 72% SoLV for category queries.

keywordcoverageSoLVAGR
best indian restaurant100%72%3.00
best north indian restaurant88%0%5.23
drop-off Method C

Anardana

Vasant Kunj · Method C (Maps top-20) · Delhi NCR

5×5 · 1 km · 25 pins

5×5 grid via Method C. Hover any pin: side panel shows top 10 actual competitors at that lat/lng — Dilli Kanteen, Mala-Akbari, AnnaMaya, etc. Anardana row is highlighted blue when present.

keywordcoverageSoLVAGR
best indian restaurant88%8%6.55
best north indian restaurant68%4%6.41
dominance Method A

Anardana

Sangam Courtyard, RK Puram · Delhi NCR

5×5 · 0.3 km · 25 pins

Tight 5×5 at 0.3 km — the outlet owns its block on category keywords, not just brand.

keywordcoverageSoLVAGR
anardana100%100%1.00
best indian restaurant100%100%1.88
fine dining0%0%
drop-off Method A

Anardana

Ambience Mall, Vasant Kunj · Delhi NCR

11×11 · 1.5 km · 121 pins

11×11 grid spanning ~15 km — Anardana's catchment ring vs the rest of South Delhi.

keywordcoverageSoLVAGR
best indian restaurant21%21%2.04
best north indian restaurant12%12%2.29
drop-off Method A

Anardana

Ambience Mall, Vasant Kunj · Delhi NCR

7×7 · 1 km · 49 pins

Branded queries dominate; category queries show clear geographic drop-off past ~2 km.

keywordcoverageSoLVAGR
anardana100%100%1.00
best indian restaurant39%39%2.05
best north indian restaurant18%18%2.78
drop-off Method A

Anardana

Ambience Mall, Vasant Kunj · Delhi NCR

9×9 · 1 km · 81 pins

Same outlet, wider grid — the circular fade-out around the mall becomes obvious.

keywordcoverageSoLVAGR
anardana100%100%1.00
best indian restaurant40%40%1.72
dominance Method A

Karim's

Jama Masjid, Old Delhi · Delhi NCR

9×9 · 1.2 km · 81 pins

Iconic single-outlet brand in dense urban core — 9×9 1.2 km shows how it owns Old Delhi.

keywordcoverageSoLVAGR
karims100%100%1.00
best mughlai food old delhi0%0%
absent Method A

Anardana

Bandra coords (no outlet) · Mumbai

7×7 · 1 km · 49 pins

Negative reference — the brand doesn't operate in Mumbai. Honest all-grey heatmap.

keywordcoverageSoLVAGR
best italian restaurant0%0%
italian food0%0%
best pasta0%0%
branded-only Method A

Theobroma

Pali Hill, Bandra · Mumbai

5×5 · 0.5 km · 25 pins

Bakery chain — branded query is uniform #1, generic 'best bakery' doesn't surface them.

keywordcoverageSoLVAGR
theobroma bandra100%100%1.00
best bakery mumbai0%0%
brownies bandra0%0%
A vs C comparison

Anardana · A vs C

Vasant Kunj · same 25 pins, both methods · Delhi NCR

25 pins · 2 methods overlaid

5.5× brand visibility (C vs A)

methodcoveragedepth
A · Search local-pack16% (4/25)top 3
C · Maps top-2088% (22/25)top 20
A vs C comparison

Toit · A vs C

Indiranagar · same 25 pins, both methods · Bangalore

25 pins · 2 methods overlaid

0.9× brand visibility (C vs A)

methodcoveragedepth
A · Search local-pack100% (25/25)top 3
C · Maps top-2088% (22/25)top 20

Methods compared

Four delivery paths for geo-anchored Google ranking data — all tested empirically. Same lat/lng went into every method (verified across a 7-variant config probe).

methodA · Search local-packB · Camoufox + IN proxyC · google_maps + parse
endpointScraper API google_search · parse=trueCamoufox over Decodo ISP proxy → Maps DOMScraper API google_maps · custom regex parse
cost / query$0.001~$0 (proxy bandwidth only)$0.001
speed / query2-4 s15-30 s5-8 s
rank depth1-3 (local-pack only)1-201-20
per-place fieldsname + positionname (DOM scrape)13 fields incl. rating, reviews, category, address, hours
infrastructurenoneheadless worker pool + proxy mgmtnone
geo-anchoringserver-spoofed to lat/lng/radiusreal proxy IP + Maps viewport URLserver-spoofed to lat/lng/radius
elapsed (9 pins)5sn/a24s
matched in (9 pins)7/9n/a5/9
verdictmisses 80% of brands ranking 4-20backup / verification only← V1 primary

5× coverage finding (Anardana Vasant Kunj, 25 pins): Method A found the brand at 4/25 pins (16%); Method C found it at 21/25 (84%) — anywhere in top-20. Same cost, same lat/lng, same Decodo plan. Method A is structurally blind to ranks 4-20 because the Search local-pack only shows 3.

Why same lat/lng disagreed earlier: we were comparing Search rad: 1000m against Maps viewport zoom=14z — different geo-scope conventions, not different rankings. A 7-variant controlled probe showed that locale, domain, and radius barely affect Scraper API output; lat/lng is the only knob that moves the local pack.

Accuracy benchmark

72 observations · 4 methods × 3 outlets × 6 queries × 3 repeats · cost $0.04. Empirical answer to "how much do these methods actually agree, and how stable is each?" Full report: docs/accuracy-benchmark.md.

Cross-method agreement — top 3 Jaccard, top 10 Spearman

Same outlet, same lat/lng, same keyword, different method. Green: the two Decodo methods (A vs C) agree at 0.83 — same backend. Amber: vendor (Decodo) vs self-scrape (Camoufox + IN proxy) disagree on 50–60% of top-3 — *they see different subsets of Google's stochastic output*.

method pairJaccard top-3Spearman top-10
A · Decodo Search vs B · Camoufox desktop0.230.833
A · Decodo Search vs B · Camoufox mobile0.321.0
A · Decodo Search vs C · Decodo Maps0.830.9
B · Camoufox desktop vs B · Camoufox mobile0.530.54
B · Camoufox desktop vs C · Decodo Maps0.400.949
B · Camoufox mobile vs C · Decodo Maps0.480.989

Intra-method stability — how much does the SAME method change between repeats?

Each query was run 3 times, ~minutes apart. Even the best method changes its top-3 ~17% of the time. This is Google's own A/B-testing leaking through, not method noise. Any rank time-series needs a noise floor; a 1-shot rank is signal-or-noise indistinguishable.

methodJaccard top-3 across repeatslatency avg / p95
A · Decodo Search0.834.3s / 8.0s
C · Decodo Maps0.7647.4s / 132.2s
B · Camoufox desktop0.669.0s / 19.3s
B · Camoufox mobile0.6918.5s / 113.4s

What this changes about the build:

  1. No method is ground truth — including Google itself. Customers need confidence intervals, not point ranks.
  2. Vendor and own scraping see DIFFERENT subsets of Google. The case for dual-track (vendor + own in parallel) strengthens; multi-source consensus is the only ≥95% fidelity path.
  3. Mobile UA returns a meaningfully different SERP than desktop (Jaccard 0.53). Restaurants care about phone users. Vendors don't separate this. We can.
  4. Rank = 7-day median, not 1-shot. Intra-method churn is 17–34%; treating one query as truth is over-confident.
  5. Field truth is the only oracle. Build a 5-outlet panel we physically visit and screenshot monthly; validate all methods against that.

Method × IP factorial — does IP matter, render matter, or both?

36 observations · 6 methods × 3 outlets × 2 repeats. Isolates whether the disagreement between methods comes from the IP source (Decodo Mumbai vs Airtel home Delhi) or the render surface (Scraper API vs web browser vs native Maps app). Full report: docs/comparison-v2.md.

Pairwise Jaccard (top-3) along the strategic axes

axis testedmethod pairJaccard top-3
same-vendor sanity (A vs B)A_decodo_api_search vs B_decodo_api_maps1.00
Decodo IN vs Airtel home (browser)C_camoufox_web_decodo vs D_camoufox_web_direct1.00
Decodo IN vs Airtel home (native app)E_emulator_app_direct vs F_emulator_app_decodo0.08
browser vs native (same Airtel IP)D_camoufox_web_direct vs E_emulator_app_direct0.00
browser vs native (same Decodo IP)C_camoufox_web_decodo vs F_emulator_app_decodo0.00
vendor vs self-scrape (same coords)B_decodo_api_maps vs C_camoufox_web_decodo0.13
vendor vs self-scrape (same coords)B_decodo_api_maps vs E_emulator_app_direct0.08

How to read this: 1.0 = perfect agreement, 0 = totally different. If "Decodo IN vs Airtel home (browser)" ≈ 0.9 → IP source doesn't change Google's response. If it's < 0.5 → IP source matters significantly. Same logic for the native-app axis.

Method D — phone-as-truth-oracle (Phase 1 framework shipped + validated)

Built and tested end-to-end against an Android 15 emulator with Pixel 7a profile + Google Play Store image. ADB orchestration over a stock unrooted Android phone: mock GPS → launch native Maps with search intent → dismiss first-run intro if present → dump UI tree via uiautomator → swipe to expose list → parse ranked places. Real-phone setup is one runbook (PHONE-SETUP.md).

Why this is the highest-fidelity method available

Vendors (Decodo) and self-scrape (Camoufox) both render Google's web Maps. Method D renders the native Maps Android app — the actual surface most consumers use. It also uses real device fingerprint + real cellular IP, eliminating the geo-spoofing fidelity gap our accuracy benchmark exposed.

componentfilestatus
ADB wrapper (devices, shell, info)src/phone/adb.py✓ shipped + tested on Android 15 emulator
Mock GPS injection (auto: emu vs real-phone)src/phone/mock_location.pyemu geo fix validated, SetLocation broadcast wired for real phones
Maps driver (geo: intent + auto-dismiss intro)src/phone/maps_app.py✓ comma-encoded URI, idempotent first-run dismissal
UI tree dumper + dual-pattern parsersrc/phone/ui_dump.py✓ 5/5 unit tests + live-extracted real Vasant Kunj results
Grid orchestrator (CLI, Method D output)run_phone_grid.py✓ same schema as Method C → visualizer + gallery compatible
Setup runbook for real phone arrivalPHONE-SETUP.md✓ 7-step ~30 min
Phase 2 (mitmproxy + Frida + protobuf)not built · only build if Phase 1 fidelity insufficient

Empirical validation on Android 15 emulator (Vasant Kunj)

Same lat/lng (28.5405, 77.1548), same keyword ("best indian restaurant"), 3 methods, captured live this session:

methodrank #1rank #2rank #3
A · Decodo Search local-packDilli Kanteen KitchenMala-Akbari Ambience MallAnnaMaya FoodHall
C · Decodo Maps DOMDilli Kanteen KitchenKarnataka Food CentreMala-Akbari Ambience Mall
D · Native Maps app (phone)Anardana Sangam CourtyardDana Choga

The moat-shaped finding the accuracy benchmark predicted is real. Native Maps app returns completely different top results than what the Decodo Scraper API (with the same lat/lng + keyword) sees. Method D captures Anardana at rank #1 for this query at this pin — Methods A and C return it nowhere in the top 3. This is the data vendor pipelines can't see.

Plug-and-play. Setup time when your Cashify Pixel 7a arrives: ~30 min (USB debugging on + install SetLocation + 1 ADB authorization + sign into Google account on Maps). On a signed-in phone the welcome-screen auto-dismiss is a no-op; results land in 5-8 s per pin instead of the 15-20 s emulator overhead.

Data sources surveyed

Subagent verified pricing live on 2026-05-27 across 12 providers. Full brief in docs/google-data-sources-brief.md.

provider$/1M queriesdepthlat/lng?verdict
DIY · Camoufox + Webshare/Decodo proxy$300-800100via headless URLbrittle, ops-heavy
Serper.dev (est.)$300100yesfastest 1-2s; "scan now" demos
DataForSEO Standard (Search)$600100yesV1.5 — Search-side cost cut
Decodo Scraper API (Search + Maps)$1,000100yesV1 primary (what we ship)
ValueSERP top tier$1,000100yesTier 2 fallback
Oxylabs SERP$1,000-1,350100yesenterprise alt
Bright Data SERP (est.)$1,500100yespremium fallback
Apify Google Maps$2,100120+yestoo slow daily
SerpApi$9,000100yes10× our cost — hard pass
ScraperAPI~$12,500DIYDIYhard pass
ScrapingBee$14,700DIYDIYhard pass
Google Places APIvariesn/an/anot a ranking API · used for outlet geocoding only
Ahrefs APIper-unittheir indexcity onlykeyword research only

Sprint roadmap

Each sprint compounds raw-data depth on the same $0.001 Decodo query — no new spend, just better extraction + compute.

Sprint 1 · shipped

Rich place extraction

Two-surface parser (DOM regex + "Suggest an edit" data blob) emits 13 fields/place: name, KG_ID, ChIJ_ID, rating, review_count, category, full address, hours, phone, website, operating status, price tier, photo, review snippet.

research doc →

Sprint 2 · pending

New metrics from rich data

Review-Weighted Visibility (RWV = Σ rank_weight × log(review_count)), competitor density per pin, category-mix donut, open-now coverage, rating-gap analysis. All from Sprint-1 data — zero new queries.

est. 1 day · differentiates from BrightLocal/Local Falcon

Sprint 3 · researched

Time series + diff playback

Postgres 16 + Timescale-compatible schema (hypertable at 10M rows). Leaflet TimeDimension for weekly playback, custom Canvas delta-arrows. Risk flagged: alert fatigue — needs per-customer threshold tuning before rollout.

research doc →

Ahrefs cross-check

Pulled live via Ahrefs MCP to validate which keywords Anardana actually owns organically (India, May 2026).

Every one of Anardana's top organic keywords is branded. That's why the category-keyword layers in our heatmaps (e.g. "best indian restaurant") reveal real geographic variation — Anardana doesn't own those queries at scale.

keywordvolume / mo (IN)best postraffic / moflags
anardana restaurant3,80011,211branded
anardana chandigarh5,8002846branded · local
anardana ranchi2,3004213branded · local
anardana gurgaon2,0004191branded · local
anardana restaurant delhi8002138branded · local
anardana sangam courtyard1,2004108branded · local
anardana karkardooma450441branded · local
anardana menu100138branded