DEV Community

Cover image for Building a Finance Lead Pipeline with the Google Maps Lead Scraper API
Techforce Global
Techforce Global

Posted on

Building a Finance Lead Pipeline with the Google Maps Lead Scraper API

This actor covers 28 finance business types, five optional intelligence blocks, and MCP delivery into six different destination apps enough surface area that a proper API walkthrough is worth more than the standard input/output table. This post covers a real Python integration, the MCP connector delivery modes, and the specific execution rules worth knowing before you build a production pipeline on top of it.

The gap between reading the README and building a working pipeline usually comes down to a handful of quiet behaviours that don't show up until a run returns something unexpected a silent fallback here, an omitted field there. This post front-loads those specifically, since they're the difference between a pipeline that works the first time and one that needs a debugging session to figure out why results look wrong.

Authentication

Standard Apify bearer token auth applies for direct API calls available from Settings → Integrations in your Apify account. No target-site credentials are needed at all; the actor reads only public Google Maps listings and public website content, so there's no separate authentication layer for the data source itself, unlike the official Google Places API, which requires a GCP project and a billing-enabled key.

Input configuration the essentials

Error handling the codes worth checking for explicitly

This actor documents its own error/condition matrix in unusual detail, which is worth taking advantage of directly in your integration code rather than treating every non-success as a generic failure.

  • SILENT_DEFAULT - results are CA Firms in London you never asked for, because no field is required and both defaulted. Always pass subcategories and location explicitly to avoid this entirely.
  • CAP_REACHED - itemCount equals maxResults equals 100, meaning the per-run ceiling truncated results. Partition larger jobs across sequential runs.
  • FREE_PLAN_CAP - itemCount caps at 10 with an upgrade banner in the log. This is a successful run, not a failure worth distinguishing in your monitoring so it doesn't trigger a false alert.
  • EMPTY_RESULTS - status SUCCEEDED with itemCount 0. Also not a failure it means the business type and location combination genuinely had no Google Maps matches.
  • DELIVERY_SKIPPED an MCP connector was set but mcpTool was left empty, so the delivery step is skipped with a warning while the dataset is still written in full.

Running it Python

import os
from apify_client import ApifyClient

client = ApifyClient(os.getenv('APIFY_TOKEN'))

run = client.actor('techforce.global/finance-google-maps-lead-scraper').call(run_input={
    'subcategories': ['CA Firm', 'Accounting Firm', 'Tax Consultant'],
    'location': 'London',
    'maxResults': 90,
    'includeLeadOverview': True,
    'includeWebsiteHealthScorecard': True,
    'includeServiceRecommendations': True,
    'includeTechnicalIntel': False,
    'deliveryMode': 'none',
})

items = client.dataset(run['defaultDatasetId']).list_items().items
firms = [i for i in items if i.get('businessName')]

weak_sites = [
    i for i in firms
    if i.get('WEBSITE_HEALTH_SCORECARD', {}).get('finalGrade') in {'C', 'D', 'F'}
]
print(f'{len(weak_sites)} firms with a weak website — best prospects')

Enter fullscreen mode Exit fullscreen mode

Execution rules that will bite you if skipped

  • Nothing is required. An empty input {} silently scrapes 'CA Firm in London' rather than raising an error — always pass subcategories, location, and maxResults explicitly from API or MCP calls
  • subcategories values must match the 28-item enum exactly — 'ca firm' (lowercase) or an unlisted type like 'Hedge Fund' gets logged as a warning and skipped; if every value is invalid, the actor silently falls back to 'CA Firm'
  • Empty fields are omitted from each item, not set to null — always check key presence ("website" in item), never compare to None
  • A missing email is the literal string "NA", not an empty value — check emailStatus first (ok / no_email_found / failed / no_website)
  • maxResults is split evenly across every selected business type — 10 types with maxResults: 100 gives roughly 10 practices each, not 100 each

Finance lead scraper API output example

MCP connector delivery pushing straight to Slack

This actor supports four delivery modes: summary (one digest call), chunked (split across calls for long lists), perLead (one call per practice), or none. Setting up a Slack digest for every run looks like this:

{
  "subcategories": ["Insurance Broker", "Life Insurance Agency"],
  "location": "Manchester",
  "maxResults": 60,
  "mcpConnector": "<your-authorized-slack-connector>",
  "deliveryMode": "summary",
  "mcpTool": "send_message",
  "mcpArguments": { "channel": "#finance-leads", "text": "{message}" },
  "mcpMessageTemplate": "{leadCount} {subcategories} leads in {location}:\n\n{leads}"
}

Enter fullscreen mode Exit fullscreen mode

For a long lead list going into Notion specifically, chunked mode groups lead lines into parts under roughly 72,000 characters each, so services with per-request size limits Notion in particular never reject the call.

Choosing a delivery mode for the right use case

Summary mode makes sense for a scheduled digest one message per run, listing every lead found. Chunked mode exists specifically for services with strict per-request size limits, splitting a long lead list into numbered parts. PerLead mode fires one connector call per individual practice, which is the right choice for pushing directly into CRM records but risks connector rate limits on a large batch a 100-practice run in perLead mode against a rate-limited service is a common source of dropped calls, worth testing on a small batch before scaling up.

Frequently asked

What's the fastest way to get a contacts-only run?
Set all five include* toggles to false this skips the website crawl and audit entirely and returns just the base practice profile.

How do I avoid overspending on a large automated run?
Pass maxTotalChargeUsd as a query parameter on the run endpoint for a hard per-execution spend ceiling important for any pipeline running unattended.

Why did my run return fewer items than maxResults?
This is expected the budget splits across business types, duplicate listings are removed, and Google may simply have fewer matches for that type/location combination than requested.

Can I search more than 100 practices in one call?
No 100 is a hard per-run ceiling. Partition by city or business-type group across sequential runs and merge on googleMapsUrl

Getting started

Full documentation and the interactive input schema:
Finance Google Maps Lead Intelligence Scraper

Top comments (0)