
Automatizar leads de Google Maps con n8n: guía práctica
Sí, n8n puede automatizar la captación de leads desde Google Maps sin repetir clics ni mantener un script propio. El flujo inicia un trabajo de BasedOnB mediante la API REST, consulta su estado con una frecuencia limitada, recupera todas las páginas y envía los negocios a Google Sheets o a un CRM.
La primera petición POST no es la parte difícil. Un flujo fiable también debe evitar trabajos duplicados al reintentarse, cortar el polling, separar los fallos, seguir el cursor de resultados y hacer escrituras seguras en el destino. El ejemplo de esta guía busca clínicas dentales en Valencia y deja cada decisión visible dentro de n8n.
Si aún no has definido las columnas o la segmentación, consulta primero la guía para crear una lista de leads con Google Maps. A partir de aquí damos por elegidos la categoría, la ciudad, el volumen y el sistema de destino.
Qué necesitas
- Una instancia de n8n capaz de enviar solicitudes HTTPS.
- Una clave API de BasedOnB con permisos de lectura y escritura de scrapes. Empieza por
bdb_live_. - Una hoja, lista de CRM o tabla con una columna de identificador externo.
- Un identificador estable de campaña o evento para la idempotencia.
- Consulta, país, provincia o estado, ciudad y número objetivo de leads.
Crea la clave en el panel y guárdala como credencial Header Auth de n8n. No pongas una clave real en Edit Fields, en un archivo exportado, en una captura ni en un mensaje de soporte. Los endpoints y campos actuales están en la documentación de la API de BasedOnB.
Respeta también los límites. Un trabajo admite hasta 10 consultas. Una cuenta puede tener como máximo 2 trabajos abiertos y 5.000 leads objetivo entre todos ellos. Los estados pending, submitted y running cuentan como abiertos. Una solicitud que supera estos límites recibe una respuesta de capacidad 429.
Resumen del flujo
- Schedule Trigger o Webhook recibe la campaña.
- Edit Fields normaliza los valores y crea la clave estable.
- HTTP Request envía
POST /api/v1/scrapes. - IF comprueba
statusCode; una respuesta correcta crea un estado de polling de un elemento. - Wait y Edit Fields incrementan
attempten esa rama de estado. - HTTP Request llama a
GET /api/v1/scrapes/:id; Merge combina la respuesta con el estado. - Switch separa errores HTTP,
done,failed,cancelledy estados abiertos. - Después de
done, HTTP Request carga páginas y comprueba primerostatusCode. - Cada página se divide una vez:
body.resultsva a Split Out y un elemento de control revisabody.page. - La rama de control pide el siguiente cursor una sola vez y devuelve la respuesta al mismo punto de división.
La documentación oficial del nodo HTTP Request explica autenticación, cabeceras, parámetros y respuestas. La del nodo Wait cubre la pausa y la reanudación.
1. Preparar una solicitud estable
Añade Edit Fields justo después del disparador. Para Valencia puedes usar este cuerpo:
{
"query": "dental clinics",
"country": "ES",
"state": "ES.60",
"city": "Valencia",
"target_leads": 250
}
query define la actividad. Los campos de ubicación acotan la zona. target_leads indica cuántas fichas quieres y debe encajar con los créditos y trabajos abiertos de la cuenta.
Añade idempotency_key, por ejemplo valencia-dentistas-2026-08-lote-01. Es mejor usar el código guardado de una campaña del CRM o el ID del evento que activó el flujo. No uses una marca de tiempo. Si n8n se repite con otra hora, el servidor puede interpretarlo como una solicitud nueva.
2. Iniciar el trabajo
Configura HTTP Request de este modo:
- Method:
POST - URL:
https://www.basedonb.com/api/v1/scrapes - Authentication: Header Auth con
Authorization: Bearer bdb_live_... - Header:
Idempotency-Keytomado de Edit Fields - Body Content Type: JSON
- Body: los cinco campos del ejemplo
- Options > Response > Include Response Headers and Status: activado
- Options > Response > Never Error: activado
- Options > Response > Response Format: JSON
Estas opciones hacen que n8n entregue también las respuestas no 2xx como output. El elemento completo contiene statusCode, headers y body. Divide primero por $json.statusCode. Solo una respuesta 2xx continúa hacia la lógica del trabajo. Para ella, crea un elemento Poll State con Edit Fields: job_id = {{$json.body.id}}, job_status = {{$json.body.status}} y attempt = 0. Los demás códigos van a la rama común de error HTTP.
Un trabajo nuevo suele devolver submitted, pero un resultado ya disponible puede devolver done de inmediato. Después de comprobar 2xx, revisa $json.body.status antes de pasar a Wait.
La misma clave con el mismo cuerpo devuelve el trabajo original. La misma clave con otra ciudad, consulta o cantidad produce un conflicto. Guarda juntos la clave y el cuerpo al que pertenece.
3. Hacer polling con límite
Usa el elemento Poll State creado tras el POST correcto. Divide su campo job_status:
done: pasa a resultados.failedocancelled: pasa a la rama final de error.pending,submittedorunning: pasa a Wait.
Puedes configurar Wait a 15 segundos. Después, usa Edit Fields para conservar job_id y definir attempt = {{$json.attempt + 1}}. Conecta ese único elemento de estado a dos ramas. El Input 1 de un nodo Merge lo recibe directamente. La otra rama llama a:
GET https://www.basedonb.com/api/v1/scrapes/{{$json.job_id}}
Usa la misma credencial Header Auth y las tres opciones Response del POST. Conecta la respuesta HTTP de estado al Input 2 de Merge. Configura Merge como Mode: Combine y Combine By: Position. El elemento combinado conserva job_id y attempt junto a statusCode y body, por lo que la respuesta GET no borra el contador.
Después de Merge, comprueba $json.statusCode antes de leer el cuerpo. Las respuestas no 2xx van a la rama común de error HTTP. Para 2xx, Switch lee $json.body.status y separa done, failed, cancelled o un estado abierto. Un IF independiente en la rama abierta revisa $json.attempt antes de volver a Wait.
Antes de regresar a Wait, añade un IF para el número de intentos. Al llegar al máximo, detén las consultas y manda un aviso con el ID del trabajo. Por ejemplo, 40 intentos separados por 15 segundos limitan esta ejecución de n8n. No prometen que cualquier trabajo termine en diez minutos. Tampoco canceles el trabajo del servidor de forma automática. Puede finalizar más tarde.
Las ramas failed y cancelled nunca deben volver al bucle. Guarda estado, ID del trabajo, campaña y, si existe, ID de la solicitud. Revisa la causa antes de decidir un nuevo envío.
4. Paginar todos los resultados
Solicita resultados solo después de done:
GET https://www.basedonb.com/api/v1/scrapes/{{$json.id}}/results
Añade el parámetro limit=500. Activa Include Response Headers and Status y Never Error, y elige JSON como Response Format, igual que en los otros nodos HTTP Request. Comprueba primero $json.statusCode; las respuestas no 2xx van a la rama común de error. Una respuesta completa correcta tiene esta forma:
{
"statusCode": 200,
"body": {
"id": "scrape-job-id",
"status": "done",
"results": [],
"page": {
"limit": 500,
"next_cursor": "next-page-token",
"has_more": true,
"total": 1250
}
}
}
Conserva la respuesta correcta de la página como un elemento y conéctala a dos ramas. La rama de datos aplica Split Out a body.results, luego mapea y hace upsert de las filas. La rama de control no pasa por Split Out. Su IF lee $json.body.page.has_more, así que se ejecuta una vez por página y no una vez por negocio.
En la rama true, Edit Fields define job_id = {{$json.body.id}} y cursor = {{$json.body.page.next_cursor}}. Un HTTP Request llamado Next Results vuelve a llamar al endpoint con limit=500, ese cursor y las mismas opciones Response. Conecta su respuesta al mismo control de statusCode y al mismo punto de división de la primera página. La rama false termina la paginación. Con un máximo de 500 filas, 1.250 resultados necesitan tres solicitudes.
No inventes números de página ni confundas total con la primera tanda. Sigue el cursor que devuelve el servidor. Escribe cada página antes de pedir la siguiente para tener un punto claro desde el que reanudar.
5. Mapear Google Sheets o el CRM
En la rama de datos, Split Out convierte body.results en elementos. Edit Fields deja clara la correspondencia:
| Campo BasedOnB | Campo de destino |
|---|---|
place_id | external_id |
title | company_name |
category | category |
address | address |
phone | phone |
website | website |
rating | google_rating |
reviews_count | google_review_count |
Usa place_id para controlar duplicados. En el CRM elige upsert en lugar de create sin comprobación. En Google Sheets busca primero esa clave y después actualiza o añade la fila. Un append simple duplica empresas cuando se vuelve a ejecutar el flujo.
Usa upserts y conserva el ID del trabajo y el cursor de cada página. La rama de control con un solo elemento puede cargar la página siguiente mientras la rama de datos escribe. Si necesitas un orden estricto, bloquea el control con una única señal de página terminada desde el destino. No conectes el IF de página siguiente después de Split Out, porque llamaría al mismo cursor una vez por resultado.
Después de importar, la tarjeta de calidad para listas ayuda a revisar campos, duplicados, fecha y procedencia. Si un asistente analizará la lista, la guía de generación de leads con IA separa las tareas del modelo de las de la fuente de datos.
Errores comunes
Como Never Error está activado, cada nodo HTTP debe dividir primero por $json.statusCode. Para respuestas no 2xx, revisa $json.body.error.code y $json.body.error.details; el cuerpo sigue disponible en esa rama de error intencional.
401 Unauthorized: falta la clave, no es válida o fue revocada. Revisa la credencial sin imprimir el secreto en los logs.
403 Forbidden: la clave existe, pero no tiene el permiso necesario. Usa los permisos mínimos de lectura y escritura de scrapes.
402 Payment Required: hay que revisar créditos, suscripción o pago. Detén la rama y avisa a quien administra la cuenta.
409 Conflict: la clave de idempotencia se usó con otro cuerpo. Compara la clave y el cuerpo guardados. Repite con la misma clave solo tras restaurar el cuerpo original. Para un trabajo nuevo deliberado, usa una clave estable nueva.
429 Too Many Requests: revisa $json.body.error.details.reason. too_many_open_scrapes exige esperar a que termine uno de los 2 trabajos abiertos. open_leads_limit exige esperar o reducir el nuevo objetivo para que los trabajos abiertos sumen como máximo 5.000 leads. Si falta reason, trátalo como límite de frecuencia y usa la cabecera Retry-After o $json.body.error.details.retry_after_seconds en una rama Wait limitada.
Resultados vacíos: consulta el estado. Mientras el trabajo está activo, el endpoint de resultados puede devolver una página vacía.
La guía de automatización con Zapier y Make muestra otros flujos por eventos. La identidad estable, los estados finales y las escrituras sin duplicados siguen siendo esenciales.
¿Polling o webhook?
El polling es fácil de montar y revisar. Sirve para trabajos puntuales y horarios poco frecuentes. A cambio, hace llamadas de estado repetidas y obliga a la ejecución a conservar el contador.
El webhook encaja mejor cuando los trabajos son frecuentes o duran tiempos distintos. n8n recibe el evento final, verifica la firma y comienza la paginación. Los errores, cursors y upserts siguen siendo necesarios. Solo cambia la forma de detectar el final.
Empieza con polling limitado si ayuda a entender los estados. Cambia a webhook cuando las comprobaciones repetidas se conviertan en ruido operativo.
Preguntas frecuentes
¿Puede n8n recoger leads de Google Maps automáticamente?
Sí. n8n puede llamar a la API REST de BasedOnB, iniciar una búsqueda de negocios, esperar mientras se procesa, recuperar todas las páginas y enviar las filas a Google Sheets o a un CRM. Guarda la clave API en una credencial de n8n, no en un campo del flujo.
¿Qué nodos de n8n necesita este flujo?
Usa un disparador, Edit Fields, HTTP Request, Wait, IF o Switch, Merge, Split Out y el nodo de destino. Merge conserva el contador de polling junto a la respuesta de estado. Split Out queda solo en la rama de datos para que el control de paginación mantenga un único elemento.
¿Por qué debo enviar un Idempotency-Key?
Hace segura una repetición del POST. La misma clave con la misma solicitud devuelve el trabajo original en vez de crear otro. Usa un identificador guardado de campaña o evento de origen, nunca la hora actual.
¿Cada cuánto debe n8n consultar el estado?
Coloca un nodo Wait entre consultas y fija un máximo de intentos. Un intervalo estable de 10 a 20 segundos es un punto de partida práctico, no una promesa de finalización. Al llegar al límite, detén el bucle y avisa a una persona responsable.
¿Cómo recupero más de 500 resultados?
Pide como máximo 500 filas y lee body.page.has_more y body.page.next_cursor en la respuesta HTTP completa. Mantén la paginación en una rama de control con un único elemento y continúa hasta que has_more sea false.
¿Conviene usar polling o webhook en n8n?
El polling es más sencillo para el primer flujo y los trabajos ocasionales. Un webhook firmado encaja mejor con procesos frecuentes o largos, porque n8n espera el evento de finalización. Ambos métodos necesitan paginar los resultados con cursor.
¿Qué hago si el trabajo queda failed o cancelled?
Trata failed y cancelled como estados finales. No pidas resultados ni devuelvas esa rama al nodo Wait. Guarda el identificador y el estado, avisa a la persona responsable y decide aparte si corresponde enviar un trabajo nuevo.
Empieza con un trabajo pequeño
Elige una categoría, una ciudad y una tabla que puedas revisar. Una cuenta nueva de BasedOnB recibe una sola vez 50 créditos de exportación sin tarjeta. Úsalos para comprobar el mapeo, la idempotencia, la rama de error y el upsert antes de subir el volumen.
Guarda el ID del trabajo junto a cada fila importada. Ese dato sencillo hace mucho más fácil revisar y reparar la automatización.