Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SpendMap

City-level ad performance scorer for quick commerce marketers.

Score cities by ROAS, CPA, conversion rate, and market size. Get a ranked list with recommended budget splits. Stop allocating ad spend by gut feel.

┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                         City Ad Performance Rankings                                     │
├──┬──────────────┬───────┬────────┬────────────┬────────┬─────────┬───────┬─────────────┤
│ #│ City         │ Score │ Status │ Quality    │  ROAS  │  CPA(₹) │ Conv% │ Budget%     │
├──┼──────────────┼───────┼────────┼────────────┼────────┼─────────┼───────┼─────────────┤
│ 1│ Mumbai       │  82.4 │ SCALE  │ SUFFICIENT │ 4.20x  │    ₹95  │ 2.02% │ 18.3%       │
│ 2│ Bengaluru    │  74.1 │ SCALE  │ SUFFICIENT │ 3.80x  │   ₹110  │ 1.77% │ 16.5%       │
│ 3│ Hyderabad    │  68.9 │  HOLD  │ SUFFICIENT │ 3.50x  │   ₹125  │ 1.82% │ 15.3%       │
│ 4│ Delhi        │  61.2 │  HOLD  │ SUFFICIENT │ 3.10x  │   ₹145  │ 1.54% │ 13.6%       │
│ 5│ Pune         │  54.7 │  HOLD  │ SUFFICIENT │ 2.90x  │   ₹160  │ 1.91% │ 12.2%       │
│ 6│ Chennai      │  43.8 │ REDUCE │ SUFFICIENT │ 2.70x  │   ₹175  │ 1.58% │  9.7%       │
│ 7│ Ahmedabad    │  37.1 │ REDUCE │ SUFFICIENT │ 2.40x  │   ₹190  │ 1.61% │  8.3%       │
│ 8│ Jaipur       │  28.6 │   LOW  │ SUFFICIENT │ 1.90x  │   ₹240  │ 1.32% │  6.1%       │
└──┴──────────────┴───────┴────────┴────────────┴────────┴─────────┴───────┴─────────────┘

Why city-first?

Quick commerce performance varies dramatically by city — demand density, dark store coverage, and user adoption differ 5-10x between Mumbai and a Tier-2 city. But most qcomm marketers allocate budgets platform-first (Meta vs Google), not city-first. The result: high-performing cities are under-invested, low-performing cities eat budget.

This tool is the missing layer between knowing city-first allocation is correct and actually doing it.

Install

pip install spendmap

Requires Python 3.9+.

Quickstart

Step 1: Export your ad data to CSV

Export from Meta Ads Manager (or any ad platform) with city-level breakdown. Save as a CSV with these columns:

city, roas, cpa, conversions, spend, clicks
Column Description Example
city City name (must be consistent across rows) Mumbai
roas Return on ad spend 4.2
cpa Cost per acquisition in INR (Indian Rupee) 95
conversions Total conversions in the date window 850
spend Total spend in the date window (INR) 380500
clicks Total clicks (used to derive conv rate) 42000

Your column names don't have to match exactly — rename them before running:

# Example: your export has "Cost per Result" instead of "cpa"
# Rename the column in your CSV before passing to spendmap

Step 2: Run

# Terminal table (default)
spendmap --input city_data.csv

# Save to CSV
spendmap --input city_data.csv --format csv --output report.csv

# Save to JSON (machine-readable)
spendmap --input city_data.csv --format json --output report.json

# With budget allocation (total budget in INR)
spendmap --input city_data.csv --total-budget 5000000

# Per-signal breakdown (for debugging / trust-building)
spendmap --input city_data.csv --verbose

# State-level (if city data is unavailable)
spendmap --input state_data.csv --granularity state

Scoring model

Each city gets a score from 0 to 100. Higher is better.

Signals and weights (configurable via config.yaml):

Signal Weight Direction Notes
ROAS 35% Higher is better Return on ad spend
CPA 30% Lower is better Inverted in scoring so lower CPA → higher score
Conversion rate 20% Higher is better Conversions / clicks
Spend vs TAM share 15% Match is better How well your spend share matches the city's Total Addressable Market size

All signals are min-max normalised across all cities in your dataset before weighting. This means scores are relative to your data, not absolute benchmarks.

Tier multiplier (applied after weighted sum):

City tier Multiplier Cities
Metro 1.00 Mumbai, Delhi, Bengaluru, Hyderabad, etc
T1 0.95 Pune, Surat, Jaipur, Lucknow, etc
T2 0.90 Dehradun, Kochi, Coimbatore, etc
T3 0.85 All other cities

Multipliers are arbitrary starting defaults. Override in config.yaml.

Status thresholds:

Status Score range Recommendation
SCALE ≥ 70 Increase budget
HOLD 50–69 Maintain current budget
REDUCE 30–49 Reduce budget, monitor
LOW < 30 Pause or move budget to SCALE cities

Data quality flags (independent of status):

Flag Conversions Meaning
SUFFICIENT ≥ 100 Reliable signal
LOW_SIGNAL 10–99 Included in ranking, but interpret with caution
INSUFFICIENT < 10 Excluded from ranking, listed separately

If a city has LOW_SIGNAL and LOW status, the tool warns you to run a test budget before reducing — there's not enough data to confirm the city is actually low-performing.

Budget allocation

Budget share = city_score / sum(all_city_scores) × 100%

Pass --total-budget in INR to see absolute amounts:

spendmap --input data.csv --total-budget 5000000

Known v1 limitation: single total budget input. Multi-campaign / multi-objective allocation (e.g., split by funnel stage) is not yet supported.

State-level fallback

If your ad platform only reports state-level data (common when pixel/CAPI — Conversions API — is not configured for city-level signals), use --granularity state:

spendmap --input state_data.csv --granularity state

State-level CSV uses state instead of city as the geo column. All other columns are the same. Tier multipliers are not applied in state mode.

Custom config

Create config.yaml in your working directory to override defaults:

scoring:
  weights:
    roas: 0.40        # Increase ROAS weight
    cpa: 0.30
    conversion_rate: 0.20
    tam_share: 0.10   # Reduce TAM weight
  tier_multipliers:
    Metro: 1.00
    T1: 0.97          # Custom T1 multiplier
    T2: 0.93
    T3: 0.88
  status_thresholds:
    SCALE: 75         # Raise the SCALE bar
    HOLD: 55
    REDUCE: 35

Development

git clone https://github.com/your-org/spendmap
cd spendmap
pip install -e ".[dev]"
pytest

Validating the model

Before trusting the rankings for budget decisions, run the model against 90 days of your actual ad data and check whether the top 5 cities match your team's manual ranking from experience. If correlation is < 0.7, adjust signal weights in config.yaml before acting on the output.

Roadmap

Feature Version Status
CSV-in scoring (this) v1.0 Shipped
Meta Ads API connector v1.1 Planned
Google Ads API connector v1.1 Planned
Movement tracking (--compare) v1.1 Planned
Slack webhook integration v1.1 Planned
Multi-platform score fusion v2 Planned
Real-time reallocation v2 Planned

Glossary

Term Meaning
ROAS Return on Ad Spend — revenue divided by ad spend
CPA Cost per Acquisition — spend divided by conversions
TAM Total Addressable Market — the estimated market size for a city, used to gauge spend share
INR Indian Rupee (₹) — all monetary values are in INR
CAPI Conversions API — server-side event integration for ad platforms
CSV Comma-Separated Values — the input/output file format used by this tool
JSON JavaScript Object Notation — machine-readable output format (--format json)
qcomm Quick commerce — same-day/rapid delivery e-commerce

License

Apache 2.0

About

Score your quick commerce cities by ad performance. Know where to scale, hold, or cut budget.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages