Planning billboards around where the leads are

A vendor’s billboard inventory arrived as a spreadsheet of sites described in words. On the map with AHA’s leads, every site is ranked by the leads within 2 km, and areas no billboard reaches stand out.

27 Oct 2026 3 min readCase study · Deals map

The problem

A billboard inventory listed sites and rates, but said nothing about where AHA’s leads are.

The solution

Geocode every site, then rank it by the leads within 2 km.

93sites geocoded from a spreadsheet
28flagged approximate, not guessed
2 kmreach every site is ranked on

A billboard vendor’s inventory is a spreadsheet: sites described in words, with sizes, formats and day rates. It tells you what you can book. It doesn’t tell you which sites stand near the people already enquiring with us. So the inventory went onto the deals map, over AHA’s own leads.

From words to points

A Python script reads the vendor’s spreadsheet and writes a small JSON file that the app loads the first time the Billboards tab opens. The hard part is location, because the inventory describes each site in words, not coordinates.

  • Each site belongs to a place: a landmark with a short map label written by hand. Each place is looked up on a small geocoding page that shows how sure it is of every result.
  • 65 of the 93 sites pin down to a named place: a junction, a station, a toll plaza.
  • The other 28 are known only to their road or area. They’re flagged “Approximate location”, get a dashed ring up close, and the camera stays at neighbourhood zoom on them. Flying to street level on a guess would be a lie.
  • When a new inventory brings new sites, the script lists them as “not on the map” until they’re given a place. Nothing drops off silently.

Leads under the billboards

Press ▼ and our leads join the billboards. Further out, each area is a circle sized by how many leads it holds; closer in, the buildings themselves. Far out, the billboards shrink to small squares so the circles and names have room. Google draws Mumbai’s area names in two scripts, so the app names 88 areas itself, in English.

Focus a billboard and a dashed 2 km ring frames it, the buildings inside light up, and the caption says what it reaches and which areas those leads are in.

Two lists that ask the question plainly

Ranked by leads puts all 93 sites in order: the most leads in buildings within 2 km first, the cheaper first on a tie. Its card on the rail is a bar chart of the top places.

// most leads within 2 km first; on a tie, the cheaper day rate
const reach = site => buildingsWithin(site, 2 /* km */).reduce((n, b) => n + b.leads, 0);
sites.sort((a, b) => reach(b) - reach(a) || a.dayRate - b.dayRate);

Leads by area turns the question round: every area with leads, most first, and how many billboards stand within 2 km of any of its buildings. Where none does, it says “No billboard near”. Those are the places where a new site would reach leads that no billboard reaches today, and that gap is as useful as the top of the ranking.

Money stays off the showroom screen

The same app runs on the showroom TV, so the billboards have two faces.

  • Showroom view shows each site’s size, format, location and which way it faces, with every marker drawn at one size. It counts AHA homes, not leads, so the list becomes “Ranked by AHA homes”.
  • Team view adds the day and half-day rates, the vendor’s availability and each site’s day rate per lead, and draws each billboard larger the more it costs a day. That is why Showroom view can’t: on a shared screen, even a marker’s size is money.
  • Team view switches itself off after 10 idle minutes or when the screen sleeps. The billboards stay up; the rates go.

Four versions in two days

Claude Code built it with me in four versions, v4.15 to v4.18, over 8 and 9 October. It doesn’t book anything. It turns “which billboard?” from a hunch into a ranked list, with its reasons drawn on the map.

What I’d reuse

  1. Ask the question in the data’s terms. Distance to leads, not a rate card.
  2. Flag uncertainty instead of hiding it. Approximate sites stay visibly approximate.
  3. A gap is a result. “No billboard near” earns a list of its own.
  4. On a shared screen, even a marker’s size can leak money.

More problems, more solutions.

All posts

Non-brand clicks are the SEO number that matters

+183% non-brand clicks

A path-traced showroom in a TV browser

22 renders, path-traced offline in about 2 hours