CRM + Google Sheets + Apps Script: Tự Xây Pipeline Tự Động
Xây CRM pipeline tự động hoàn toàn miễn phí với Google Sheets + Apps Script — không cần phần mềm, không cần lập trình phức tạp.
Hướng dẫn từng bước viết Apps Script để tự động hóa: gửi email follow-up, cập nhật trạng thái deal, báo cáo tuần và nhắc nhở theo lịch — biến Google Sheets thành CRM tự động thực sự.
Mục lục:
- 1. Tổng quan hệ thống CRM tự động với Sheets + Apps Script
- 2. Cấu trúc Google Sheets CRM
- 3. Script #1: Auto email khi lead mới vào
- 4. Script #2: Nhắc nhở follow-up quá hạn
- 5. Script #3: Báo cáo pipeline tuần tự động
- 6. Script #4: Auto cập nhật trạng thái deal
- 7. Tích hợp nâng cao: Webhook & Zapier
- 8. FAQ
1. Tổng Quan Hệ Thống CRM Tự Động
Google Apps Script là JavaScript chạy trên server của Google, cho phép tự động hóa mọi tác vụ trong Google Workspace (Sheets, Gmail, Calendar, Drive). Kết hợp Google Sheets làm database + Apps Script làm automation engine = CRM tự động mạnh mẽ, miễn phí 100%.
// Luồng tự động hóa CRM
Lead mới điền form
→ Google Forms → Sheets (tự động)
→ Apps Script trigger onFormSubmit()
→ Gửi email chào mừng tự động
→ Assign cho sales rep
→ Tạo task follow-up trong 24h
Hàng ngày lúc 8:00 sáng:
→ Apps Script Time trigger
→ Quét deals quá hạn follow-up
→ Gửi email nhắc nhở cho sales rep
Mỗi thứ Hai 8:00 sáng:
→ Apps Script Time trigger
→ Tổng hợp pipeline tuần
→ Gửi báo cáo cho manager
2. Cấu Trúc Google Sheets CRM Để Tích Hợp Apps Script
Trước khi viết script, cần chuẩn hóa cấu trúc Sheets để script hoạt động đúng:
Sheet "PIPELINE" — Cột bắt buộc (theo thứ tự)
| A | B | C | D | E | F | G | H | I |
|---|---|---|---|---|---|---|---|---|
| Deal ID | Tên KH | SĐT | Giai đoạn | Giá trị | Follow-up ngày | Sales Rep | Email Rep |
Sheet "CONFIG" — Cài đặt hệ thống
Lưu các cấu hình: email manager, số ngày trước khi nhắc nhở, template email, danh sách giai đoạn pipeline. Script đọc config từ đây thay vì hardcode.
3. Script #1: Auto Email Khi Lead Mới Vào
Script này trigger khi có row mới được thêm vào sheet PIPELINE (thường từ Google Forms hoặc import thủ công):
// Trigger: onEdit hoặc onFormSubmit
function onNewLeadAdded(e) {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('PIPELINE');
const lastRow = sheet.getLastRow();
const newRow = sheet.getRange(lastRow, 1, 1, 9).getValues()[0];
const customerName = newRow[1]; // Cột B
const customerEmail = newRow[2]; // Cột C
const salesRepEmail = newRow[8]; // Cột I
// 1. Gửi email chào mừng cho khách hàng
if (customerEmail) {
const subject = "Xin chào " + customerName + " — Cảm ơn bạn đã liên hệ";
const body = "Kính gửi " + customerName + ",\n\n" +
"Cảm ơn bạn đã quan tâm đến dịch vụ của chúng tôi.\n" +
"Đội sales sẽ liên hệ với bạn trong vòng 24 giờ làm việc.\n\n" +
"Trân trọng,\nĐội Sales SheetStore";
GmailApp.sendEmail(customerEmail, subject, body);
}
// 2. Thông báo cho sales rep được assign
if (salesRepEmail) {
const repSubject = "[Lead mới] " + customerName + " cần follow-up";
const repBody = "Bạn vừa được assign lead mới:\n\n" +
"Tên: " + customerName + "\n" +
"Email: " + customerEmail + "\n" +
"SĐT: " + newRow[3] + "\n\n" +
"Vui lòng liên hệ trong 24 giờ.";
GmailApp.sendEmail(salesRepEmail, repSubject, repBody);
}
// 3. Set follow-up date = ngày mai
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
sheet.getRange(lastRow, 7).setValue(tomorrow); // Cột G
console.log('New lead processed: ' + customerName);
}
4. Script #2: Nhắc Nhở Follow-up Quá Hạn
Chạy mỗi ngày lúc 8 giờ sáng, quét toàn bộ pipeline tìm deals cần follow-up hôm nay hoặc đã quá hạn:
function sendFollowUpReminders() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('PIPELINE');
const data = sheet.getDataRange().getValues();
const today = new Date();
today.setHours(0, 0, 0, 0);
const overdueDeals = [];
const todayDeals = [];
// Bỏ qua row 1 (header)
for (let i = 1; i < data.length; i++) {
const row = data[i];
const stage = row[4]; // Cột E - Giai đoạn
const followUpDate = row[6]; // Cột G - Ngày follow-up
const salesRepEmail = row[8]; // Cột I
// Bỏ qua deals đã closed
if (stage === 'Closed Won' || stage === 'Closed Lost') continue;
if (!followUpDate || !salesRepEmail) continue;
const fDate = new Date(followUpDate);
fDate.setHours(0, 0, 0, 0);
if (fDate < today) {
overdueDeals.push({ row: i + 1, data: row });
} else if (fDate.getTime() === today.getTime()) {
todayDeals.push({ row: i + 1, data: row });
}
}
// Gom deals theo sales rep và gửi 1 email tổng hợp
const repDeals = {};
[...overdueDeals, ...todayDeals].forEach(deal => {
const email = deal.data[8];
if (!repDeals[email]) repDeals[email] = { overdue: [], today: [] };
if (overdueDeals.includes(deal)) {
repDeals[email].overdue.push(deal);
} else {
repDeals[email].today.push(deal);
}
});
Object.keys(repDeals).forEach(repEmail => {
const deals = repDeals[repEmail];
let body = '📋 TÓM TẮT FOLLOW-UP HÔM NAY
';
if (deals.overdue.length > 0) {
body += "⚠️ QUÁ HẠN (" + deals.overdue.length + " deals):
";
deals.overdue.forEach(d => {
body += " • " + d.data[1] + " (" + d.data[2] + ") — " +
"Hạn: " + d.data[6] + "
";
});
body += '
';
}
if (deals.today.length > 0) {
body += "📅 CẦN FOLLOW-UP HÔM NAY (" + deals.today.length + " deals):
";
deals.today.forEach(d => {
body += " • " + d.data[1] + " (" + d.data[2] + ")
";
});
}
body += '
Vui lòng cập nhật trạng thái sau khi liên hệ.';
GmailApp.sendEmail(
repEmail,
"[CRM] " + (deals.overdue.length + deals.today.length) + " deals cần follow-up hôm nay",
body
);
});
console.log('Reminders sent to ' + Object.keys(repDeals).length + ' reps');
}
5. Script #3: Báo Cáo Pipeline Tuần Tự Động
function sendWeeklyPipelineReport() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('PIPELINE');
const data = sheet.getDataRange().getValues();
// Tính toán thống kê
const stats = {
total: 0,
byStage: {},
totalValue: 0,
weightedValue: 0,
closedWon: 0,
closedWonValue: 0
};
const stageWeights = {
'New Lead': 0.1,
'Contacted': 0.2,
'Qualified': 0.4,
'Proposal': 0.6,
'Negotiation': 0.8,
'Closed Won': 1.0
};
for (let i = 1; i < data.length; i++) {
const row = data[i];
if (!row[0]) continue; // Bỏ qua row trống
const stage = row[4];
const value = parseFloat(row[5]) || 0;
stats.total++;
stats.byStage[stage] = (stats.byStage[stage] || 0) + 1;
stats.totalValue += value;
stats.weightedValue += value * (stageWeights[stage] || 0);
if (stage === 'Closed Won') {
stats.closedWon++;
stats.closedWonValue += value;
}
}
// Tạo nội dung báo cáo
const formatVND = (n) =>
new Intl.NumberFormat('vi-VN').format(n) + ' đ';
let report = '📊 BÁO CÁO PIPELINE TUẦN
';
report += '================================
';
report += "Tổng deals: " + stats.total + "
";
report += "Pipeline value: " + formatVND(stats.totalValue) + "
";
report += "Weighted forecast: " + formatVND(Math.round(stats.weightedValue)) + "
";
report += "Closed Won tuần này: " + stats.closedWon + " deals
";
report += "Doanh thu chốt: " + formatVND(stats.closedWonValue) + "
";
report += 'PHÂN BỔ THEO GIAI ĐOẠN:
';
Object.keys(stageWeights).forEach(stage => {
const count = stats.byStage[stage] || 0;
if (count > 0) {
report += " " + stage + ": " + count + " deals
";
}
});
// Đọc email manager từ CONFIG sheet
const configSheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('CONFIG');
const managerEmail = configSheet
? configSheet.getRange('B1').getValue()
: Session.getActiveUser().getEmail();
GmailApp.sendEmail(
managerEmail,
"[CRM] Báo cáo pipeline tuần " + new Date().toLocaleDateString("vi-VN"),
report
);
console.log('Weekly report sent to: ' + managerEmail);
}
6. Script #4: Auto Cập Nhật Trạng Thái Theo Thời Gian
// Tự động chuyển deal sang "Stale" nếu không có activity 14 ngày
function markStaleDeals() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('PIPELINE');
const data = sheet.getDataRange().getValues();
const today = new Date();
const staleDays = 14;
let staleCount = 0;
for (let i = 1; i < data.length; i++) {
const stage = data[i][4];
const followUpDate = data[i][6];
// Chỉ check các deal đang open
if (!stage || stage.includes('Closed') || stage === 'Stale') continue;
if (!followUpDate) continue;
const fDate = new Date(followUpDate);
const daysDiff = Math.floor(
(today - fDate) / (1000 * 60 * 60 * 24)
);
if (daysDiff > staleDays) {
// Đánh dấu màu đỏ và thêm note
sheet.getRange(i + 1, 5).setBackground('#fee2e2'); // Highlight đỏ
const currentNote = sheet.getRange(i + 1, 5).getNote();
sheet.getRange(i + 1, 5).setNote(
"[Stale " + daysDiff + " ngày] " + currentNote
);
staleCount++;
}
}
console.log("Marked " + staleCount + " stale deals");
}
⚙️ Cách thiết lập Time-based Triggers
- 1. Mở Apps Script Editor (Extensions → Apps Script)
- 2. Click biểu tượng đồng hồ bên trái (Triggers)
- 3. Click "Add Trigger" góc dưới phải
- 4. Chọn function → Event source: "Time-driven" → "Day timer" → "8am to 9am"
- 5. Lưu trigger — script sẽ chạy tự động mỗi ngày
7. Tích Hợp Nâng Cao: Webhook & Zapier
🔗 Nhận lead từ Facebook Ads qua Zapier
Facebook Lead Ads → Zapier → Google Sheets (thêm row mới) → Apps Script onEdit trigger → xử lý lead tự động. Chi phí: Zapier Free plan (100 tasks/tháng) đủ cho startup nhỏ.
📱 Nhận lead từ form website
Website contact form → Google Forms (miễn phí) → Google Sheets → Apps Script. Không cần Zapier. Google Forms tích hợp trực tiếp với Sheets — response mới = row mới tự động.
💬 Gửi thông báo Zalo qua ESMS API
Apps Script có thể gọi ESMS API để gửi Zalo ZNS (Zalo Notification Service) khi có lead mới hoặc khi deal chuyển giai đoạn. Chi phí ESMS: ~300-500đ/tin nhắn Zalo ZNS.
📥 Template CRM Google Sheets + Apps Script từ SheetStore
Thay vì tự viết từ đầu, template CRM Google Sheets từ SheetStore đã có sẵn tất cả 4 scripts trên, đã được test và tối ưu. Copy một lần, customize trong 30 phút, tiết kiệm 10+ giờ coding.
Xem thêm: CRM Google Sheets cơ bản | Tự động hóa sales pipeline | Top 10 CRM tốt nhất 2026
8. FAQ
Apps Script có giới hạn gì không?
Giới hạn miễn phí: 90 phút runtime/ngày, 100 email/ngày qua GmailApp (dùng tài khoản Google thường), 20 triggers. Với Google Workspace Business, giới hạn tăng lên 6 giờ/ngày và 1,500 email/ngày. Cho SME dưới 50 người, giới hạn free hoàn toàn đủ dùng.
Cần biết lập trình để dùng Apps Script không?
Không cần chuyên sâu. Apps Script là JavaScript đơn giản — nếu bạn biết copy-paste và thay đổi tên biến, bạn có thể customize các scripts trên. Template từ SheetStore đã viết sẵn, chỉ cần đổi email và tên cột theo dữ liệu của bạn.
Google Sheets CRM + Apps Script có thể thay thế HubSpot không?
Cho team dưới 10 người và dưới 500 contacts: hoàn toàn có thể. Bạn sẽ cần tự build một số tính năng mà HubSpot có sẵn (email tracking, mobile app), nhưng tiết kiệm $540+/năm (HubSpot Starter 10 users). Khi scale lên 20+ người, nên chuyển sang CRM chuyên dụng.
Chia sẻ bài viết:
Tuân Hoang
Đội ngũ SheetStore
Bạn thấy bài viết hữu ích?
Đăng ký nhận thông báo khi có bài viết mới.