lacspace-leads

Find local-business leads from Google Maps — free, no API keys.

● Live · v1.8.0npm ↗Source ↗
terminal
npx lacspace-leads restaurants --city Kathmandu --area Baneshwor -f xlsx
What it does

Everything, in one command

lacspace-leads is a complete, keyless lead-generation tool. It sweeps whole cities neighbourhood-by-neighbourhood, verifies emails by MX lookup, normalises phones to E.164, and de-duplicates as it accumulates a master list across runs — everything a real prospecting workflow needs, from the terminal or as a typed library. Every lead lands in your file the moment it's found (CSV, NDJSON, JSON or Excel), so you can watch it grow and Ctrl-C never loses a row; --resume carries on from the file. It captures opening hours, price level, ratings, business status and open-now, filters on all of them, prints run-summary stats, and can pipe straight into lacspace-enrich.

Runs locally, not as a hosted button

lacspace-leads drives a real browser over Google Maps, so it runs on your machine — not as a hosted button here (that would break Google's Terms and can't run in a serverless function). It's one command to try locally, no setup.

Features

What's inside

Live file, row by row

Each lead is written to your CSV / NDJSON / JSON / Excel file the moment it's found — open it mid-run; Ctrl-C never loses what was collected.

~4 s per listing

Finished leads stream out while the browser opens the next one; website enrichment runs in the background.

Ask for a number

--target 500 keeps searching until it has 500 unique leads. One Google search stops near 120; this sweeps past it.

Map tiling

Re-centres the same query on a grid across the city, walking outwards — no geocoding service, no API key.

City sweep

Comma-separate cities/areas/types and it runs each search, then merges and de-duplicates into one list.

Split by place

--split city writes one file per city or area alongside the master export.

No-website list

--no-website keeps only businesses missing a site — an instant pitch list for web work.

Verified emails

Visit each website to find an email, then MX-verify the domain — keep only deliverable contacts.

8 social networks

Facebook, Instagram, WhatsApp, LinkedIn, X, YouTube, TikTok and Telegram from the business site.

E.164 phones

Normalise every phone to +CC… with one flag — CRM-ready out of the box.

Radius search

Centre on a coordinate and keep only what's within range, sorted nearest-first.

Master list

--append merges each run into your file and de-duplicates, so daily runs build one clean database.

Saved campaigns

Describe repeatable searches + shared options in one --config JSON file; run them on a schedule.

Deep controls

Presets, filters (incl. has-contact / name-exclude), sort, proxy, retries, jitter, concurrency and callbacks.

Any format

JSON, NDJSON, CSV or Excel — plus a built-in converter between all four, both ways.

Resume anything

--resume continues from the rows already in your file (or a sweep's checkpoint) and fills up to --target — nothing re-scraped.

Rich filters

--min-rating / --min-reviews / --open-now / --price / --category / --business-status narrow the list on the spot.

Run summary

--summary prints per-run stats — totals, with-phone/email, average rating, dedupe hits.

Walkthrough

How to use it

From your first command to a repeatable workflow.

Your first list, in two minutes

Nothing to install and no account anywhere. You need Node 18+ and a few minutes of a real browser running on your machine.

  1. Run it with no arguments and answer the questions

    The walkthrough asks for a business type, the city, the areas, how many you want and the file format. Every answer has a sensible default, so you can press Enter through it.

    terminal
    npx lacspace-leads

    Prefer flags? Everything the walkthrough asks can be passed directly, as in the steps below.

  2. Or say it in one line

    A business type, where to look, and the format you want out. The file lands in the folder you ran it from.

    terminal
    npx lacspace-leads restaurants --city Kathmandu --area Baneshwor -f xlsx
  3. Watch the browser do the work

    A real Chromium window opens and walks the map, which is how it works without an API key. Add --headless once you trust it and it runs invisibly.

    terminal
    npx lacspace-leads dentists --city Pokhara --headless -f csv

Getting the number of leads you actually asked for

One Google Maps search stops serving results at roughly 120, so a big --limit quietly returns about 114. --target is the flag that goes past that.

  1. Ask for a total, not a per-search limit

    --target keeps searching until it has that many unique businesses: first every place you named, then tiles of the map around the city, de-duplicating the whole way.

    terminal
    npx lacspace-leads restaurants --city Kathmandu --target 500 -f xlsx

    -n / --limit still exists and still means listings per single search. Use --target whenever you want more than ~120.

  2. Name the neighbourhoods you care about

    Each area becomes its own search before any tiling happens, so naming them puts your priorities first and usually finishes sooner.

    terminal
    npx lacspace-leads restaurants --city Kathmandu \
      --areas "Baneshwor, Thamel, Patan, Lazimpat" --target 400
  3. Tune how the map is tiled

    --step sets the spacing between tiles and --tiles caps how many are tried. Tighter steps find more in a dense city and take longer.

    terminal
    npx lacspace-leads cafes --city Lalitpur --target 600 --step 1.5km --tiles 60

    If the map genuinely runs out, the tool says so and suggests widening rather than pretending the target was reachable.

Several cities at once

  1. Cross cities with areas and business types

    Comma-separate any of them. Every combination runs as its own search and the results merge into one de-duplicated list.

    terminal
    npx lacspace-leads \
      --type "restaurant, cafe" \
      --cities "Kathmandu, Lalitpur, Bhaktapur" \
      --areas "Baneshwor, Thamel" \
      --target 600 -f xlsx
  2. Write one file per city

    --split gives each city, area or category its own file next to the master export, which is what you want when handing lists to different people.

    terminal
    npx lacspace-leads gyms --cities "Kathmandu, Pokhara" --target 300 --split city -f xlsx
  3. Pick the run back up if it stops

    --resume writes a checkpoint next to the output, so an interrupted sweep continues from the next search instead of re-scraping.

    terminal
    npx lacspace-leads salons --city Kathmandu --areas "Thamel,Patan,Baneshwor" --resume -o salons.csv

Turning listings into a contact list

  1. Add emails and social profiles

    --enrich visits each business website to find an email address and links to eight social networks. It is slower, so it is opt-in.

    terminal
    npx lacspace-leads clinics --city Pokhara --target 200 --enrich -f xlsx
  2. Keep only contacts that can actually receive mail

    --verify-emails checks each domain has MX records, and --has-valid-email drops everything that fails.

    terminal
    npx lacspace-leads hotels --city Kathmandu --target 150 \
      --enrich --verify-emails --has-valid-email -f csv
  3. Normalise the phone numbers

    --country rewrites every phone into international format, which is what a CRM or bulk-SMS tool expects.

    terminal
    npx lacspace-leads pharmacies --city Biratnagar --target 200 --country NP --has-phone

Narrowing to the right prospects

  1. Find the businesses that need what you sell

    --no-website keeps only businesses with no website at all. Pair it with --has-phone and you have a call list for web work.

    terminal
    npx lacspace-leads "beauty salon" --city Pokhara --target 200 \
      --no-website --has-phone -f csv
  2. Filter on quality and status

    Rating, review count, price tier, category, open-now and business status all filter the list before it is written.

    terminal
    npx lacspace-leads restaurants --city Kathmandu --target 300 \
      --min-rating 4 --min-reviews 50 --sort reviews --desc
  3. Choose the columns

    A preset picks a sensible bundle, or name exactly the fields you want. Fewer columns means a faster run.

    terminal
    npx lacspace-leads cafes --city Lalitpur --target 200 --preset outreach

Making it a repeatable workflow

  1. Build one master file that grows

    --append merges each run into the same file and de-duplicates, so running weekly builds a single clean database instead of twelve overlapping exports.

    terminal
    npx lacspace-leads restaurants --city Kathmandu --target 300 \
      --append -o master.csv
  2. Export only what is new

    --dedupe-across drops anything already present in your master file, so the new export contains only businesses you have not seen before.

    terminal
    npx lacspace-leads restaurants --city Kathmandu --target 300 \
      --dedupe-across master.csv -o new-this-week.csv
  3. Save the whole campaign in a file

    A --config JSON holds the searches and shared options, so the same campaign runs identically every time and can go on a schedule.

    terminal
    npx lacspace-leads --config campaign.json
  4. Use it as a typed library

    Everything the CLI does is exported, including the sweep engine, so you can build it into your own tooling.

    typescript
    import { sweepLeads, serialize } from "lacspace-leads";
    
    const { leads, stats } = await sweepLeads({
      type: "restaurants",
      city: "Kathmandu",
      target: 500,
      headless: true,
      country: "NP",
    });
    console.log(stats); // { searches, tiles, unique, saturated }
    const { data } = serialize(leads, "csv");

When something looks wrong

  1. It returned far fewer than you asked for

    That is the map running out, and the tool says so. Widen it: more areas, more cities, related business types, or a bigger --step so the tiles cover more ground.

    terminal
    npx lacspace-leads --type "restaurant, cafe, bakery" \
      --cities "Kathmandu, Lalitpur" --target 800 --step 3km
  2. It found nothing at all

    Usually a CAPTCHA or a changed page. Run without --headless to see the window, slow it down with --delay, and try again in a few minutes.

    terminal
    npx lacspace-leads restaurants --city Kathmandu --delay 1500
  3. Addresses or websites are missing

    --no-details skips opening each listing, so only names and map links come back. Filters like --no-website and --split need those details, and will turn them back on for you.

How to use

Copy, paste, done

Real commands and snippets — from a one-liner to the typed library.

500 leads, not 114
terminal
npx lacspace-leads restaurants --city Kathmandu \
  --target 500 -f xlsx

Sweeps every area you name, then tiles the map, until it has 500 unique businesses.

Many cities, one file each
terminal
npx lacspace-leads restaurants \
  --cities "Kathmandu, Lalitpur, Bhaktapur" \
  --areas "Baneshwor, Thamel" --target 400 --split city

Cross-product of cities x areas, de-duplicated, then written out one Excel file per city.

Businesses with no website
terminal
npx lacspace-leads "beauty salon" --city Pokhara \
  --target 200 --no-website --has-phone -f csv

Every salon in town missing a website, with a phone number to call.

Open-now + price tier, with stats
terminal
npx lacspace-leads bars --city Pokhara \
  --open-now --price 2 --summary

Keeps places open right now at price level $$, then prints run-summary stats.

Resumable city sweep
terminal
npx lacspace-leads cafes --city Kathmandu \
  --area "Thamel,Patan,Baneshwor" --resume -o sweep.csv

Interrupt it and re-run — --resume continues from the next area, nothing re-scraped.

Dedupe against a master file
terminal
npx lacspace-leads gyms --city Lalitpur \
  --dedupe-across master.csv --append -o new.csv

Drops anything already in master.csv, appends only the genuinely new leads.

Pipe straight into lacspace-enrich
terminal
npx lacspace-leads clinics --city Pokhara \
  --enrich-out sites.ndjson -o clinics.csv

Writes an NDJSON of sites ready for `lacspace-enrich --input`.

Use it as a library
typescript
import { searchLeads, serialize } from "lacspace-leads";

const leads = await searchLeads({
  city: "Kathmandu", type: "restaurants", limit: 40,
  enrich: true, country: "NP", headless: true,
});
const { data } = serialize(leads, "csv");
Good for

What people build with it

✓ Build a prospect list for cold outreach or field sales

✓ Map every business of a type across a city

✓ Enrich an existing list with phones, emails and socials

✓ Keep a living, de-duplicated master database updated daily

Start now

Run lacspace-leads today

Free, open-source, no API keys. It's a CLI and a typed library.

terminal
npx lacspace-leads restaurants --city Kathmandu --area Baneshwor -f xlsx