← Back to Skills Marketplace
nicemaths123

Google Maps B2B Lead Goldmine

by nicemaths123 · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ⚠ suspicious
97
Downloads
0
Stars
0
Active Installs
1
Versions
Install in OpenClaw
/install google-maps-extractor
Description
Extract, score, and export detailed local business leads from Google Maps by keyword and location with contact info, reviews, and personalized outreach messa...
README (SKILL.md)

Google Maps B2B Lead Goldmine: Extract, Score and Contact Local Business Leads in 5 Minutes

Display Name: Google Maps B2B Lead Goldmine
Version: 2.0.0 Author: @g4dr

Overview

Turn Google Maps into your personal lead generation machine. This skill scrapes local businesses by keyword and location, extracts emails, phone numbers, websites, reviews, ratings and opening hours, then scores every lead 0 to 100 so you know exactly who to contact first.

Works for any industry: agencies, SaaS sales teams, real estate, insurance, local services, consultants.

Powered by: Apify + Claude AI


What This Skill Does

  • Scrape up to 100 businesses per search from Google Maps with full contact details
  • Extract emails, phone numbers, websites, full addresses and opening hours
  • Pull review count, average rating and recent review text for each business
  • Score every lead 0 to 100 based on review gaps, rating weakness, website quality and response patterns
  • Generate a personalized outreach message for every high-scoring lead
  • Export everything as a CRM-ready CSV or JSON file
  • Run multi-location searches in parallel to build city-wide or national databases

Step 1: Set Up Your Scraping Engine

This skill uses Apify as its cloud scraping engine. Free tier includes $5/month of compute, enough for hundreds of leads.

  1. Create your free account at Apify
  2. Go to Settings > Integrations and copy your Personal API Token
  3. Store it securely:
    export APIFY_TOKEN=apify_api_xxxxxxxxxxxxxxxx
    

Step 2: Install Dependencies

npm install apify-client axios

Apify Actors Used

Actor What It Scrapes Data Extracted
Apify Google Maps Scraper Business listings by keyword + location Name, phone, email, website, address, hours, category
Apify Google Maps Reviews Scraper Customer reviews per business Review text, rating, date, reviewer name, response status
Apify Website Content Crawler Business websites Contact page emails, social links, tech stack
Apify Google Search Scraper Google search results Additional business info, news, ads running

Examples

Basic Lead Extraction by Keyword and City

import ApifyClient from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor("compass~crawler-google-places").call({
  searchStringsArray: ["dentists in Miami, FL"],
  maxCrawledPlacesPerSearch: 50,
  language: "en",
  includeWebResults: false
});

const { items } = await run.dataset().getData();

// Each item contains:
// { title, phone, website, address, totalScore, reviewsCount,
//   categoryName, openingHours, email, location }

console.log(`Found ${items.length} leads`);

Multi-Location Parallel Search

const locations = [
  "dentists in Miami, FL",
  "dentists in Fort Lauderdale, FL",
  "dentists in West Palm Beach, FL",
  "dentists in Tampa, FL",
  "dentists in Orlando, FL"
];

const runs = await Promise.all(
  locations.map(search =>
    client.actor("compass~crawler-google-places").call({
      searchStringsArray: [search],
      maxCrawledPlacesPerSearch: 50,
      language: "en"
    })
  )
);

const allLeads = [];
for (const run of runs) {
  const { items } = await run.dataset().getData();
  allLeads.push(...items);
}

// Deduplicate by phone number
const seen = new Set();
const unique = allLeads.filter(lead => {
  if (!lead.phone || seen.has(lead.phone)) return false;
  seen.add(lead.phone);
  return true;
});

console.log(`${unique.length} unique leads across ${locations.length} cities`);

Lead Scoring Algorithm

function scoreLead(lead) {
  let score = 50;

  // Review gap signal: few reviews = needs marketing help
  if (lead.reviewsCount \x3C 10) score += 20;
  else if (lead.reviewsCount \x3C 30) score += 10;

  // Low rating signal: needs reputation management
  if (lead.totalScore && lead.totalScore \x3C 4.0) score += 15;
  else if (lead.totalScore && lead.totalScore \x3C 4.5) score += 5;

  // No website = massive opportunity
  if (!lead.website || lead.website === '') score += 25;

  // Has website but no email listed = hard to reach
  if (lead.website && !lead.email) score -= 5;

  // Has phone = contactable
  if (lead.phone) score += 5;

  // Category bonus for high-value niches
  const highValue = ['lawyer', 'dentist', 'doctor', 'real estate', 'contractor', 'plumber'];
  if (highValue.some(k => (lead.categoryName || '').toLowerCase().includes(k))) {
    score += 10;
  }

  return Math.min(100, Math.max(0, score));
}

const scored = unique.map(lead => ({
  ...lead,
  leadScore: scoreLead(lead)
})).sort((a, b) => b.leadScore - a.leadScore);

console.log("Top 10 leads:");
scored.slice(0, 10).forEach((lead, i) => {
  console.log(`${i + 1}. [${lead.leadScore}/100] ${lead.title} | ${lead.phone} | ${lead.website || 'NO WEBSITE'}`);
});

Deep Email Extraction from Business Websites

async function extractEmails(leads) {
  const withWebsites = leads.filter(l => l.website);

  const run = await client.actor("apify/website-content-crawler").call({
    startUrls: withWebsites.slice(0, 20).map(l => ({ url: l.website })),
    maxCrawlPages: 3,
    crawlerType: "cheerio"
  });

  const { items } = await run.dataset().getData();

  const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;

  const enriched = items.map(page => {
    const emails = [...new Set((page.text || '').match(emailRegex) || [])];
    return { url: page.url, emails };
  });

  return enriched;
}

Generate Personalized Outreach per Lead

import axios from 'axios';

async function generateOutreach(lead) {
  const prompt = `Write a short cold email (under 80 words) for this local business.

LEAD:
- Business: ${lead.title}
- Category: ${lead.categoryName}
- Location: ${lead.address}
- Rating: ${lead.totalScore}/5 (${lead.reviewsCount} reviews)
- Website: ${lead.website || 'None'}
- Lead Score: ${lead.leadScore}/100

RULES:
- Reference something specific about their business
- If they have few reviews, mention you can help them get more
- If they have no website, mention you can build one
- If their rating is below 4.5, mention reputation management
- Keep it conversational, no corporate speak
- End with a soft question, not a hard CTA
- Include [YOUR_NAME] and [YOUR_COMPANY] placeholders

Return subject line and body only.`;

  const { data } = await axios.post('https://api.anthropic.com/v1/messages', {
    model: "claude-sonnet-4-20250514",
    max_tokens: 250,
    messages: [{ role: "user", content: prompt }]
  }, {
    headers: {
      'x-api-key': process.env.CLAUDE_API_KEY,
      'anthropic-version': '2023-06-01'
    }
  });

  return data.content[0].text;
}

// Generate outreach for top 10 leads
for (const lead of scored.slice(0, 10)) {
  lead.outreachEmail = await generateOutreach(lead);
  await new Promise(r => setTimeout(r, 500));
}

Full Pipeline: Search, Score, Enrich, Outreach, Export

import { writeFileSync } from 'fs';

async function fullLeadPipeline(keyword, locations, maxPerLocation = 50) {
  console.log(`Starting pipeline for: ${keyword}`);

  // STEP 1: Scrape all locations in parallel
  const searches = locations.map(loc => `${keyword} in ${loc}`);
  const runs = await Promise.all(
    searches.map(s =>
      client.actor("compass~crawler-google-places").call({
        searchStringsArray: [s],
        maxCrawledPlacesPerSearch: maxPerLocation,
        language: "en"
      })
    )
  );

  let allLeads = [];
  for (const run of runs) {
    const { items } = await run.dataset().getData();
    allLeads.push(...items);
  }

  // STEP 2: Deduplicate
  const seen = new Set();
  const unique = allLeads.filter(l => {
    const key = l.phone || l.title;
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });

  // STEP 3: Score
  const scored = unique.map(l => ({ ...l, leadScore: scoreLead(l) }))
    .sort((a, b) => b.leadScore - a.leadScore);

  // STEP 4: Generate outreach for top 20
  for (const lead of scored.slice(0, 20)) {
    lead.outreachEmail = await generateOutreach(lead);
    await new Promise(r => setTimeout(r, 500));
  }

  // STEP 5: Export to CSV
  const headers = ["title","phone","email","website","address","totalScore","reviewsCount","categoryName","leadScore","outreachEmail"];
  const csv = [
    headers.join(","),
    ...scored.map(l => headers.map(h => `"${(l[h] || '').toString().replace(/"/g, '""')}"`).join(","))
  ].join("\
");

  const filename = `leads-${keyword.replace(/\s+/g, '_')}-${Date.now()}.csv`;
  writeFileSync(filename, csv);
  console.log(`Exported ${scored.length} scored leads to ${filename}`);

  return scored;
}

// Usage
await fullLeadPipeline("plumbers", ["Miami, FL", "Fort Lauderdale, FL", "Tampa, FL"]);

Lead Score Breakdown

Score Range Meaning Action
80 to 100 Hot lead, multiple pain points visible Contact immediately
60 to 79 Warm lead, clear opportunity Add to outreach queue
40 to 59 Decent lead, needs more research Enrich before contact
0 to 39 Cold lead, low immediate opportunity Add to nurture list

What Makes This Different

Feature Basic Scraper This Skill
Contact extraction Name + phone only Phone + email + website + hours + category
Lead scoring None 0 to 100 scoring with 6 weighted signals
Outreach generation None AI-personalized email per lead
Multi-location One city at a time Parallel search across unlimited cities
Email enrichment None Deep crawl of business websites for emails
Export format Raw JSON dump CRM-ready CSV with all fields

Pro Tips

  1. Search narrow, not broad. "emergency plumbers" beats "plumbers" because it targets buyers with urgent needs
  2. Stack 3 to 5 cities in one run to build a regional database in minutes
  3. Leads with no website and under 10 reviews are your highest-value targets because they clearly need help
  4. Run the same search weekly to catch new businesses that just opened
  5. Cross-reference with Apify Google Search Scraper to check if they run Google Ads (if yes, they spend money on marketing = qualified buyer)
  6. Export to your CRM and tag leads by score tier for segmented follow-up sequences

Cost Estimate

Action Apify Compute Units Approximate Cost
50 leads from 1 city ~0.05 CU ~$0.02
250 leads from 5 cities ~0.25 CU ~$0.10
1,000 leads from 20 cities ~1.0 CU ~$0.40
Email enrichment (20 websites) ~0.10 CU ~$0.04

Scale your Apify plan as you grow. Free tier covers hundreds of leads per month.


Error Handling

try {
  const run = await client.actor("compass~crawler-google-places").call(input);
  const dataset = await run.dataset().getData();
  return dataset.items;
} catch (error) {
  if (error.statusCode === 401) throw new Error("Invalid Apify token. Sign up at https://www.apify.com?fpr=dx06p");
  if (error.statusCode === 429) throw new Error("Rate limit. Reduce batch size or upgrade your plan.");
  if (error.statusCode === 404) throw new Error("Actor not found. Check the actor ID.");
  throw error;
}

Requirements

  • An Apify account with API token
  • Node.js 18+ with apify-client and axios
  • Claude API key for outreach generation (optional but recommended)
  • A CRM or spreadsheet to manage your pipeline (HubSpot, Airtable, Google Sheets)
Usage Guidance
This skill appears to do what it says (use Apify to scrape Google Maps and enrich leads), but there are two practical issues to weigh before installing/using it: - Missing credential declaration: The registry metadata lists no required env vars, yet SKILL.md requires you to export an APIFY_TOKEN and hints at using Claude AI. Treat that as a red flag — ask the publisher to update metadata so you know exactly what secrets you'll need to provide. - Privacy, legality and terms-of-service: Scraping Google Maps and extracting contact details and emails can violate Google/website terms of service and may involve personal data. Confirm you have the right to collect and use this data, and check Apify and Google terms and any regional privacy rules (e.g., GDPR). - Operational safety: The README recommends installing npm packages and invoking third-party Apify actors. Only install dependencies you trust, verify the actor IDs/owners (e.g., 'compass~crawler-google-places' vs 'apify/website-content-crawler') to ensure you are calling legitimate actors, and monitor billing/usage on your Apify account. - Mitigations: Use a dedicated Apify account and a token with limited permissions; do not reuse high-value credentials. Ask the skill author for an explicit list of required env vars and any external endpoints the skill will contact (including where personalization via 'Claude AI' runs and what credentials it needs). If the author cannot or does not provide clear metadata and source, treat the skill as higher risk and avoid providing long-lived or privileged secrets.
Capability Analysis
Type: OpenClaw Skill Name: google-maps-extractor Version: 1.0.0 The skill is a lead generation tool designed to scrape business data from Google Maps using Apify and generate outreach messages via Claude AI. The provided code snippets in SKILL.md are functional, align with the stated purpose, and use legitimate libraries (apify-client, axios). While the documentation contains affiliate links to Apify (e.g., fpr=dx06p), there is no evidence of malicious intent, data exfiltration, or unauthorized command execution.
Capability Assessment
Purpose & Capability
The skill's name/description (scraping Google Maps, extracting contact details, scoring leads) aligns with the runtime instructions which call Apify actors and crawl business websites. Using Apify actors and a lead-scoring function is coherent with the advertised capability.
Instruction Scope
SKILL.md explicitly instructs the agent/operator to create an Apify account, export APIFY_TOKEN, install npm packages, and run Apify actors to scrape data and crawl websites. Those steps stay within the stated purpose (scraping, enrichment, outreach generation). However the doc also references 'Claude AI' for personalization without specifying how to provide Claude credentials or exactly when/where Claude is invoked — that is an ambiguous scope expansion.
Install Mechanism
This is an instruction-only skill (no install spec, no code files). The README recommends running 'npm install apify-client axios' locally — a normal, low-risk developer instruction. There is no packaged install that would download arbitrary archives or create persistent binaries.
Credentials
Registry metadata declares no required env vars or primary credential, but SKILL.md instructs the user to set APIFY_TOKEN (and mentions Claude AI). The skill therefore requires credentials that are not declared in the metadata. That mismatch is a proportionality / transparency problem: an Apify token is required for core functionality and should be listed; any AI service credentials used for personalization should also be declared.
Persistence & Privilege
The skill does not request 'always: true' and is user-invocable only. It is instruction-only and does not declare actions that modify other skills or system-wide settings. Autonomous invocation is allowed by default but not a new privilege here.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install google-maps-extractor
  3. After installation, invoke the skill by name or use /google-maps-extractor
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.0
**Major upgrade with advanced lead extraction, scoring, and outreach automation** - Scrape up to 100 Google Maps business leads per search, including full contact details, ratings, reviews, and opening hours. - Built-in lead scoring algorithm rates each business 0–100 based on review count, ratings, website presence, and more. - Integrated personalized outreach email generator for high-scoring leads. - Supports multi-location batch searches and CRM-friendly data export. - Full documentation and working code samples included for setup, scraping, scoring, enrichment, and outreach in one pipeline.
Metadata
Slug google-maps-extractor
Version 1.0.0
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 1
Frequently Asked Questions

What is Google Maps B2B Lead Goldmine?

Extract, score, and export detailed local business leads from Google Maps by keyword and location with contact info, reviews, and personalized outreach messa... It is an AI Agent Skill for Claude Code / OpenClaw, with 97 downloads so far.

How do I install Google Maps B2B Lead Goldmine?

Run "/install google-maps-extractor" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Google Maps B2B Lead Goldmine free?

Yes, Google Maps B2B Lead Goldmine is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Google Maps B2B Lead Goldmine support?

Google Maps B2B Lead Goldmine is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Google Maps B2B Lead Goldmine?

It is built and maintained by nicemaths123 (@nicemaths123); the current version is v1.0.0.

💬 Comments