Generación de leads con Google Maps: una guía práctica
Una categoría y una lista de ciudades, convertidas en un CSV de leads filtrado y enriquecido. Bucle en Python y el coste de una campaña de 100 ciudades.

Toda lista de leads locales empieza igual: una categoría, un conjunto de ciudades, y un filtro que te dice quién merece de verdad una llamada. Este es el flujo completo de ese proceso, de la consulta al CSV, con el coste en créditos calculado para el tamaño de una campaña real.
Si quieres la referencia del endpoint en sí, parámetros, campos de la respuesta, lo que cuesta una sola búsqueda, eso está cubierto en cómo raspar resultados de Google Maps con Python. Este post es la guía construida encima: cómo convertir resultados de Maps en una lista que le entregarías a un comercial.
Paso 1: define el ICP antes de escribir una consulta
“Negocios en Austin” no es un filtro. Un ICP utilizable para outreach local necesita tres cosas fijadas antes de lanzar una sola solicitud:
- Categoría. El término de búsqueda que emparejarás con cada ciudad: “fontanero”, “dentista”, “instalador de climatización”. Pruébalo a mano en Maps primero y comprueba que no arrastra categorías adyacentes que no quieres.
- Un suelo de tracción. Un número mínimo de reseñas (
reviews) te dice que el negocio está lo bastante consolidado como para merecer un contacto, no un listado que abrió el mes pasado. - Una señal de dolor. Para una agencia web, eso es un campo
websiteausente. Para un pitch de herramienta de reservas, podría ser untypeque implique trabajo con cita previa. La señal es lo que sea que tu producto resuelva.
Todo lo que viene después es solo ejecutar esa definición a escala.
Paso 2: consulta categoría y ciudad, paginado
Recorre la categoría en tu lista de ciudades, y trata cada página como una solicitud facturable aparte:
import requests
API_KEY = "faf_live_..." # tu clave de FastAF
def maps_search(query, page=0):
resp = requests.get(
"https://api.fastaf.co/v1/maps",
params={"query": query, "page": page},
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=60,
)
resp.raise_for_status()
return resp.json().get("search_results", [])
Dos páginas por ciudad (unos 40 lugares, ya que una página de Maps ronda los 20 resultados) suele bastar para ciudades medianas. Las áreas metropolitanas densas pueden necesitar tres o cuatro antes de que los rendimientos empiecen a decrecer.
Paso 3: filtra por campos, no por criterio manual
Aquí es donde el ICP del paso 1 se convierte en código. Sin revisión manual de la lista en bruto:
CATEGORY = "plumber"
CITIES = ["Austin TX", "Tampa FL", "Boise ID"] # tu lista de 100 ciudades
MIN_REVIEWS = 25
MIN_RATING = 4.0
PAGES_PER_CITY = 2
leads = []
for city in CITIES:
for page in range(PAGES_PER_CITY):
for place in maps_search(f"{CATEGORY} in {city}", page=page):
if place.get("reviews", 0) < MIN_REVIEWS:
continue
if place.get("rating", 0) < MIN_RATING:
continue
if place.get("website"):
continue # ya tiene sitio web, no es el ICP para un pitch de agencia web
leads.append(place)
print(f"{len(leads)} leads en bruto de {len(CITIES)} ciudades")
Invierte la lógica para un pitch distinto: rating < 4.0 y reviews > 50 encuentra negocios con tráfico real y un problema de reputación, un ICP distinto pero igual de común.
Paso 4: enriquece la preselección, no todo el volcado
No vuelvas a consultar cada lugar que raspaste, solo los que sobrevivieron al filtro. Cada resultado lleva un place_id, que puedes volver a consultar justo antes de que un lead llegue a un comercial, así el registro está actualizado en vez de tener los días de antigüedad que tenía el volcado masivo:
def maps_lookup(place_id):
resp = requests.get(
"https://api.fastaf.co/v1/maps",
params={"place_id": place_id},
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=60,
)
resp.raise_for_status()
results = resp.json().get("search_results", [])
return results[0] if results else {}
enriched = [maps_lookup(lead["place_id"]) if lead.get("place_id") else lead for lead in leads]
Este es también el orden de operaciones más barato: filtrar primero significa que solo pagas el coste de enriquecimiento en leads que de verdad vas a usar, no en cada lugar de cada ciudad.
Paso 5: exporta el CSV
import csv
with open("leads.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["title", "phone", "address", "rating", "reviews", "type"])
writer.writeheader()
for lead in enriched:
writer.writerow({k: lead.get(k, "") for k in writer.fieldnames})
Eso es un archivo que puedes soltar directamente en una importación a CRM o en una herramienta de outreach en frío.
¿Cuánto cuesta una campaña de 100 ciudades?
Una solicitud /maps cuesta 5 créditos sin importar la consulta. A 2 páginas por ciudad:
| Paso | Solicitudes | Créditos |
|---|---|---|
| Descubrimiento: 100 ciudades x 2 páginas | 200 | 1.000 |
| Enriquecimiento: ~150 leads preseleccionados | 150 | 750 |
| Total | 350 | 1.750 |
En el pack Growth (29 $ por 75.000 créditos), 1.750 créditos son aproximadamente 0,68 $ del pack. Si primero estás probando la categoría y el filtro, el nivel gratuito son 500 créditos sin tarjeta, suficiente para correr el descubrimiento y el enriquecimiento en 20 a 25 ciudades antes de decidir si el ICP es el correcto. Las solicitudes fallidas no se facturan, los créditos se reservan cuando empieza una solicitud y se devuelven si no vuelve nada, así que una consulta de ciudad mala no te cuesta nada más allá de la llamada desperdiciada.
La versión corta
Fija el ICP a una categoría, un suelo de tracción y una señal de dolor antes de escribir código. Consulta ancho, filtra duro, y gasta créditos de enriquecimiento solo en los leads que ya pasaron el filtro. Un barrido completo de 100 ciudades con enriquecimiento se queda por debajo de 2.000 créditos, lo bastante pequeño como para que la limitación en una campaña así nunca sea la factura de la API, sino lo buena que sea tu filtro.