CRM en Google Sheets y Google Apps Script: Automatización de Leads, Cotizaciones en PDF y Alertas en Gmail

Para pequeñas y medianas empresas, contratar licencias mensuales costosas de CRMs corporativos como Salesforce o HubSpot suele representar un gasto desproporcionado e innecesario. Con el ecosistema de Google Workspace, Google Sheets y Google Apps Script, es posible estructurar un CRM a medida, ligero, colaborativo y 100% automatizado que centralice prospectos, genere presupuestos comerciales en PDF y dispare alertas en tiempo real vía Gmail sin pagar suscripciones recurrentes.

¿Por qué implementar un CRM en Google Sheets con Apps Script?#
Google Sheets ofrece una base de datos tabular accesible desde cualquier dispositivo, con historial de versiones, permisos granulares y respaldo continuo en la nube de Google Drive. Al extenderlo mediante Google Apps Script (un entorno de ejecución basado en JavaScript ejecutado en los servidores de Google), eliminamos las limitaciones manuales de las hojas de cálculo tradicionales:
- Cero coste en licencias SaaS: Funciona directamente sobre cuentas de Google Workspace o Gmail gratuitas.
- Generación dinámica de documentos: Conversión de plantillas de Google Docs en cotizaciones PDF profesionales con el logotipo de la empresa y desglose de precios.
- Despacho transaccional por Gmail: Envío automático de presupuestos con archivos adjuntos personalizados y firmas corporativas.
- Integración con formularios web: Captura de prospectos en tiempo real mediante Webhooks o Google Forms.
+-------------------+ (POST Webhook) +--------------------------------+
| Formulario Web / | -----------------------> | Google Apps Script (doPost) |
| Landing Page | +--------------------------------+
+-------------------+ |
v
+-------------------+ (Genera Cotización) +--------------------------------+
| Plantilla Docs / | <----------------------- | Google Sheets Database |
| Google Drive PDF | | (Leads, Cotizaciones, Pipeline)|
+-------------------+ +--------------------------------+
| |
v v
+-------------------+ (Alerta de Venta) +--------------------------------+
| PDF Adjunto | -----------------------> | Gmail Service (MailApp) |
+-------------------+ +--------------------------------+
|
v
[Cliente / Ejecutivo]
Arquitectura de la Base de Datos en Google Sheets#
Para garantizar escalabilidad y evitar inconsistencias, dividimos el libro de trabajo en 3 hojas relacionales:
Leads: Registro de prospectos con columnas:ID,Fecha,Nombre,Empresa,Email,WhatsApp,Estado(Nuevo,Cotizado,Ganado,Perdido),Monto Estimado.Plantilla_Items: Catálogo de productos y servicios con sus precios unitarios, SKUs y descripciones técnicas.Cotizaciones_Emitidas: Historial de presupuestos generados con enlace directo al PDF en Google Drive.
Código en Google Apps Script: Captura de Leads y Generación de PDF#
A continuación se muestra la implementación completa del script en Código.gs dentro del editor de extensiones de Google Sheets:
// Configuración de constantes globales
const SPREADSHEET_ID = SpreadsheetApp.getActiveSpreadsheet().getId();
const DOC_TEMPLATE_ID = '1AbCdEfGhIjKlMnOpQrStUvWxYz_TEMPLATE_ID'; // ID del Google Doc plantilla
const PDF_FOLDER_ID = '1XyZ_FOLDER_ID_EN_DRIVE'; // ID de la carpeta en Google Drive
/**
* Webhook para recibir prospectos desde la Web o Webhooks externos (POST)
*/
function doPost(e) {
try {
const data = JSON.parse(e.postData.contents);
const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName('Leads');
const leadId = 'LEAD-' + Utilities.formatDate(new Date(), 'GMT-5', 'yyyyMMdd-HHmmss');
const timestamp = new Date();
// Insertar nueva fila de prospecto
sheet.appendRow([
leadId,
timestamp,
data.nombre || 'Sin nombre',
data.empresa || 'Independiente',
data.email,
data.whatsapp || '',
data.servicioInteres || 'Consultoría General',
'Nuevo',
data.presupuestoEstimado || 0
]);
// Notificar al equipo comercial por Gmail
notificarEquipoNuevoLead(data);
return ContentService
.createTextOutput(JSON.stringify({ status: 'success', leadId: leadId }))
.setMimeType(ContentService.MimeType.JSON);
} catch (error) {
return ContentService
.createTextOutput(JSON.stringify({ status: 'error', message: error.toString() }))
.setMimeType(ContentService.MimeType.JSON);
}
}
/**
* Función para generar cotización PDF y enviarla por correo al cliente
*/
function generarYEnviarCotizacion(leadId, clienteEmail, clienteNombre, itemsArray, totalMonto) {
const folder = DriveApp.getFolderById(PDF_FOLDER_ID);
const templateFile = DriveApp.getFileById(DOC_TEMPLATE_ID);
// 1. Crear copia temporal de la plantilla de Google Docs
const tempDocName = `Cotizacion_${leadId}_${clienteNombre}`;
const copyDoc = templateFile.makeCopy(tempDocName, folder);
const doc = DocumentApp.openById(copyDoc.getId());
const body = doc.getBody();
// 2. Reemplazar variables en el documento
const fechaHoy = Utilities.formatDate(new Date(), 'GMT-5', 'dd/MM/yyyy');
body.replaceText('{{FECHA}}', fechaHoy);
body.replaceText('{{CODIGO}}', leadId);
body.replaceText('{{CLIENTE}}', clienteNombre);
body.replaceText('{{TOTAL}}', `$${totalMonto.toFixed(2)} USD`);
// 3. Insertar tabla de ítems cotizados
const tablePlaceholder = body.findText('{{TABLA_ITEMS}}');
if (tablePlaceholder) {
const element = tablePlaceholder.getElement();
const parent = element.getParent();
const tableIndex = parent.getChildIndex(element);
const table = body.insertTable(tableIndex);
const headerRow = table.appendTableRow();
headerRow.appendTableCell('Descripción del Servicio').setBold(true);
headerRow.appendTableCell('Cant.').setBold(true);
headerRow.appendTableCell('Precio Unit.').setBold(true);
headerRow.appendTableCell('Subtotal').setBold(true);
itemsArray.forEach(item => {
const row = table.appendTableRow();
row.appendTableCell(item.descripcion);
row.appendTableCell(item.cantidad.toString());
row.appendTableCell(`$${item.precio.toFixed(2)}`);
row.appendTableCell(`$${(item.cantidad * item.precio).toFixed(2)}`);
});
body.removeChild(parent);
}
doc.saveAndClose();
// 4. Exportar el documento como archivo PDF
const pdfBlob = copyDoc.getAs('application/pdf').setName(`${tempDocName}.pdf`);
const pdfFile = folder.createFile(pdfBlob);
// Eliminar el Google Doc temporal para ahorrar espacio
copyDoc.setTrashed(true);
// 5. Enviar el correo con GmailApp
GmailApp.sendEmail(
clienteEmail,
`Presupuesto Comercial - ${leadId} | Brayan Developer`,
`Estimado/a ${clienteNombre},
Adjuntamos la propuesta técnica y cotización solicitada para su proyecto.
Quedamos a su disposición para resolver cualquier consulta.
Saludos cordiales,
Equipo Comercial`,
{
attachments: [pdfBlob],
name: 'Brayan Developer - Soluciones Digitales'
}
);
// 6. Registrar en la hoja de cotizaciones
const logSheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName('Cotizaciones_Emitidas');
logSheet.appendRow([leadId, clienteEmail, totalMonto, new Date(), pdfFile.getUrl()]);
}
/**
* Notificación interna de nuevo prospecto
*/
function notificarEquipoNuevoLead(data) {
const adminEmail = '[email protected]';
const asunto = `🚨 Nuevo Lead Registrado: ${data.empresa} (${data.nombre})`;
const mensaje = `Se ha recibido un nuevo prospecto:
- Nombre: ${data.nombre}
- Empresa: ${data.empresa}
- Email: ${data.email}
- WhatsApp: ${data.whatsapp}
- Servicio: ${data.servicioInteres}
- Presupuesto: ${data.presupuestoEstimado}
Revisar en Google Sheets.`;
GmailApp.sendEmail(adminEmail, asunto, mensaje);
}
Automatización con Disparadores (Triggers) de Google Sheets#
Para automatizar la ejecución sin intervención manual:
- Disparador
onEdit: Detecta cuando el estado del lead cambia a"Cotizar"y dispara automáticamente la funcióngenerarYEnviarCotizacion. - Disparador de Tiempo (Time-Driven Trigger): Ejecuta una rutina diaria a las 09:00 AM que revisa leads con más de 48 horas sin seguimiento y envía un recordatorio por correo al equipo de ventas.
Ventajas Competitivas para tu Empresa#
| Característica | CRM Tradicional (SaaS) | CRM en Google Sheets + Apps Script |
|---|---|---|
| Costo Mensual | - USD / usuario / mes | zsh USD (100% Gratuito en Workspace) |
| Curva de Aprendizaje | Alta (interfaces complejas) | Nula (Interfaz familiar de Excel/Sheets) |
| Generación de PDFs | Plantillas rígidas y limitadas | Totalmente personalizada en Google Docs |
| Propiedad de los Datos | Servidores de terceros | Propiedad 100% de tu cuenta de Google |
| Integraciones | Cobro por conectores API | Ilimitadas con Webhooks y Apps Script |
Conclusión#
Un CRM basado en Google Sheets y Google Apps Script es la alternativa ideal para empresas que buscan agilidad, control absoluto sobre sus flujos comerciales y máxima rentabilidad sin atarse a licencias mensuales de software.
¿Necesitas estructurar un CRM personalizado con plantillas de cotización y flujos automatizados para tu equipo? Conoce nuestros servicios de Automatización y Software a Medida o contáctanos hoy mismo para asesorarte.
¿Te gustaría profundizar en estos temas?
Aprende sobre desarrollo de software, apps a medida, automatizaciones con N8N, Next.js y Cloud con casos reales.


