Trong thế giới marketing kỹ thuật số, dữ liệu là vua. Tuy nhiên, việc tổng hợp thủ công dữ liệu từ nhiều nguồn khác nhau như Google Search Console, Google Ads, Facebook Ads, TikTok Ads… vào một báo cáo duy nhất không chỉ tốn thời gian, công sức mà còn dễ xảy ra sai sót.
May mắn thay, với sự kết hợp mạnh mẽ giữa Google Sheets và Google Apps Script, bạn hoàn toàn có thể xây dựng một hệ thống báo cáo tự động, linh hoạt và gần như miễn phí. Hệ thống này giúp bạn tập trung dữ liệu về một nơi, dễ dàng theo dõi hiệu suất chiến dịch và đưa ra quyết định nhanh chóng hơn.
Bài viết này sẽ hướng dẫn bạn chi tiết từng bước để thiết lập hệ thống tự động hóa này, bao gồm các phương pháp cập nhật nhất (tính đến tháng 4 năm 2025), cách kết nối với các nền tảng phổ biến và những lưu ý quan trọng.
Đối tượng hướng tới: Các đội ngũ marketing (đặc biệt là team nhỏ), chuyên viên phân tích dữ liệu, chủ doanh nghiệp hoặc bất kỳ ai muốn tự động hóa và kiểm soát quy trình báo cáo của mình.
Yêu cầu cơ bản:
- Tài khoản Google.
- Kiến thức cơ bản về Google Sheets.
- Quyền truy cập vào Google Search Console, Google Ads và các tài khoản quảng cáo khác (Meta, TikTok…) mà bạn muốn tích hợp.
⚙️ Bước 1: Chuẩn bị Môi Trường Làm Việc
- Tạo Google Sheet: Truy cập Google Drive, tạo một Google Sheet mới và đặt tên gợi nhớ, ví dụ:
Báo cáo Marketing Tự Động
. - Tạo các Trang tính (Sheets): Bên trong file Google Sheet vừa tạo, hãy tạo các trang tính riêng biệt để chứa dữ liệu từ mỗi nguồn và một trang tính tổng hợp. Ví dụ:
GSC Data
(cho Google Search Console)Google Ads Data
Meta Ads Data
(nếu bạn định tích hợp)TikTok Ads Data
(nếu bạn định tích hợp)Tổng hợp
(để gom dữ liệu từ các sheet trên)
- Mở Trình soạn thảo Apps Script: Trong Google Sheet, vào menu
Tiện ích mở rộng
(Extensions) ->Apps Script
. Một tab trình soạn thảo mới sẽ mở ra. - Đặt tên Dự án Script: Nhấp vào “Dự án không có tiêu đề” ở góc trên bên trái và đặt tên cho dự án script, ví dụ:
Marketing Automation Scripts
.
🧩 Bước 2: Tự Động Lấy Dữ Liệu Google Search Console (GSC)
Google Search Console cung cấp dữ liệu quan trọng về hiệu suất tìm kiếm tự nhiên. Chúng ta sẽ dùng Apps Script để tự động lấy dữ liệu này.
-
Kích hoạt Google Search Console API:
- Trong trình soạn thảo Apps Script, ở menu bên trái, nhấp vào
Dịch vụ
(Services). - Nhấp vào nút
+ Thêm dịch vụ
. - Tìm và chọn
Google Search Console API
. - Nhấn
Thêm
. Thao tác này cho phép script của bạn tương tác với GSC API. - Lưu ý: Đảm bảo dự án Google Cloud Platform được liên kết với script của bạn (thường tự động) đã bật “Google Search Console API”. Apps Script thường xử lý việc này khi bạn thêm dịch vụ.
- Trong trình soạn thảo Apps Script, ở menu bên trái, nhấp vào
-
Viết Script Lấy Dữ Liệu GSC: Dán đoạn mã sau vào trình soạn thảo script. Đoạn mã này sử dụng dịch vụ nâng cao
SearchConsole
(API mới) để lấy dữ liệu./** * Lấy dữ liệu Google Search Console (Top 100 queries) và ghi vào Sheet 'GSC Data'. * Cần bật Dịch vụ Nâng cao 'Google Search Console API'. */ function getGSCData() { // !!! THAY ĐỔI GIÁ TRỊ NÀY !!! const siteURL = 'sc-domain:yourdomain.com'; // Thay bằng domain property (vd: 'sc-domain:example.com') hoặc URL prefix property (vd: 'https://www.example.com/') của bạn. const sheetName = "GSC Data"; // Tên sheet để ghi dữ liệu const spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); let sheet = spreadsheet.getSheetByName(sheetName); if (!sheet) { sheet = spreadsheet.insertSheet(sheetName); } // Tính toán ngày: Lấy dữ liệu 7 ngày gần nhất, kết thúc vào ngày hôm kia (do GSC có độ trễ) const today = new Date(); const endDate = new Date(today); endDate.setDate(today.getDate() - 2); // Kết thúc vào hôm kia const startDate = new Date(endDate); startDate.setDate(endDate.getDate() - 6); // Bắt đầu 7 ngày trước endDate const startDateString = Utilities.formatDate(startDate, Session.getScriptTimeZone(), 'yyyy-MM-dd'); const endDateString = Utilities.formatDate(endDate, Session.getScriptTimeZone(), 'yyyy-MM-dd'); // Cấu hình yêu cầu API const request = { startDate: startDateString, endDate: endDateString, dimensions: ['query'], // Lấy dữ liệu theo từ khóa. Có thể thêm 'page', 'country', 'device' rowLimit: 100, // Số lượng dòng tối đa muốn lấy startRow: 0 // Bắt đầu từ dòng đầu tiên // type: 'web' // Loại tìm kiếm (mặc định là web) }; try { Logger.log(`Đang yêu cầu dữ liệu GSC cho ${siteURL} từ ${startDateString} đến ${endDateString}`); // Gọi API qua Dịch vụ Nâng cao SearchConsole const response = SearchConsole.SearchAnalytics.query(siteURL, request); if (response.rows && response.rows.length > 0) { sheet.clearContents(); // Xóa dữ liệu cũ // Ghi header const headers = ["Keyword", "Clicks", "Impressions", "CTR", "Position"]; sheet.getRange(1, 1, 1, headers.length).setValues([headers]).setFontWeight("bold"); // Chuẩn bị dữ liệu để ghi const data = response.rows.map(row => [ row.keys[0], // Keyword row.clicks, // Clicks row.impressions, // Impressions (row.ctr * 100).toFixed(2) + '%', // CTR (định dạng %) row.position.toFixed(2) // Position (làm tròn 2 chữ số) ]); // Ghi dữ liệu vào sheet sheet.getRange(2, 1, data.length, data[0].length).setValues(data); sheet.autoResizeColumns(1, headers.length); // Tự động điều chỉnh độ rộng cột Logger.log(`Đã lấy thành công ${data.length} dòng dữ liệu GSC.`); } else { Logger.log(`Không có dữ liệu GSC trả về hoặc response.rows không tồn tại/rỗng.`); sheet.clearContents(); sheet.getRange("A1").setValue("Không có dữ liệu GSC cho khoảng thời gian đã chọn."); } } catch (error) { Logger.log(`Lỗi khi lấy dữ liệu GSC: ${error}\nStack: ${error.stack}`); // Ghi lỗi vào sheet để dễ theo dõi sheet.clearContents(); sheet.getRange("A1").setValue(`Lỗi khi lấy dữ liệu GSC: ${error}`); } }
-
Chạy và Ủy quyền (Authorization):
- Chọn hàm
getGSCData
từ menu thả xuống phía trên trình soạn thảo. - Nhấn nút
Chạy
(biểu tượng tam giác). - Lần đầu tiên chạy, Google sẽ yêu cầu bạn cấp quyền cho script. Xem xét kỹ các quyền (đặc biệt là quyền xem dữ liệu Google Search Console) và nhấn
Cho phép
nếu bạn đồng ý. Script có thể cần chạy lại sau khi cấp quyền. - Kiểm tra
Log
(Nhật ký thực thi – biểu tượng con bọ) để xem kết quả hoặc lỗi. Dữ liệu sẽ xuất hiện trong sheetGSC Data
.
- Chọn hàm
-
Thiết lập Chạy Tự động (Trigger):
- Ở menu bên trái, nhấp vào
Trình kích hoạt
(biểu tượng đồng hồ). - Nhấp vào nút
+ Thêm trình kích hoạt
. - Cấu hình trigger như sau:
- Chọn hàm để chạy:
getGSCData
- Chọn triển khai để chạy:
HEAD
- Chọn nguồn sự kiện:
Dựa trên thời gian
- Chọn loại trình kích hoạt dựa trên thời gian:
Trình kích hoạt hàng ngày
(hoặc tần suất bạn muốn) - Chọn thời gian trong ngày để chạy (ví dụ: 2 giờ sáng – 3 giờ sáng, khi máy chủ ít tải).
- Cài đặt thông báo lỗi: Chọn tần suất nhận email nếu script lỗi.
- Chọn hàm để chạy:
- Nhấn
Lưu
. Bạn có thể cần cấp lại quyền cho trigger.
- Ở menu bên trái, nhấp vào
🔄 Bước 3: Tự Động Lấy Dữ Liệu Quảng Cáo
Việc lấy dữ liệu quảng cáo có độ phức tạp khác nhau tùy nền tảng.
A. Google Ads (Sử dụng Dịch vụ AdsApp
)
Đây là cách được khuyến nghị và tương đối dễ dàng cho Google Ads vì Apps Script có dịch vụ tích hợp sẵn.
-
Điều kiện: Bạn cần có quyền truy cập (ít nhất là quyền đọc) vào tài khoản Google Ads hoặc tài khoản Người quản lý (MCC).
-
Viết Script: Dịch vụ
AdsApp
cho phép bạn chạy các truy vấn bằng Ngôn ngữ Truy vấn Google Ads (GAQL)./** * Lấy dữ liệu hiệu suất chiến dịch Google Ads và ghi vào sheet 'Google Ads Data'. * Sử dụng dịch vụ tích hợp sẵn AdsApp. */ function getGoogleAdsData() { const sheetName = "Google Ads Data"; const spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); let sheet = spreadsheet.getSheetByName(sheetName); if (!sheet) { sheet = spreadsheet.insertSheet(sheetName); } // Chọn khoảng thời gian. Ví dụ: HÔM QUA, 7_NGÀY_QUA, 30_NGÀY_QUA // Xem thêm tại: https://developers.google.com/google-ads/scripts/docs/reference/adsapp/adsapp_reportroot#report_4 const dateRange = 'YESTERDAY'; // Viết truy vấn GAQL const query = ` SELECT campaign.name, campaign.status, metrics.clicks, metrics.impressions, metrics.cost_micros, -- Chi phí tính bằng đơn vị micro (1/1,000,000 đơn vị tiền tệ) metrics.conversions, metrics.ctr, -- Tỷ lệ nhấp metrics.average_cpc -- Chi phí trung bình mỗi lượt nhấp (đơn vị micro) FROM campaign WHERE segments.date DURING ${dateRange} AND campaign.status != 'REMOVED' -- Loại bỏ các chiến dịch đã xóa ORDER BY campaign.name `; try { Logger.log(`Đang yêu cầu dữ liệu Google Ads cho khoảng thời gian: ${dateRange}`); const report = AdsApp.report(query); // Xóa dữ liệu cũ và xuất báo cáo mới ra sheet sheet.clearContents(); report.exportToSheet(sheet); Logger.log("Đã xuất dữ liệu Google Ads thô ra sheet."); // === Xử lý dữ liệu sau khi xuất === if (sheet.getLastRow() > 1) { // Chỉ xử lý nếu có dữ liệu (ngoài hàng tiêu đề) // 1. Chuyển đổi Chi phí (cost_micros) và CPC (average_cpc) từ micros sang đơn vị tiền tệ const costColumnIndex = sheet.createTextFinder("metrics.cost_micros").findNext().getColumn(); const cpcColumnIndex = sheet.createTextFinder("metrics.average_cpc").findNext().getColumn(); const dataRange = sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn()); // Dữ liệu từ hàng 2 const values = dataRange.getValues(); for (let i = 0; i < values.length; i++) { // Chuyển đổi Cost if (values[i][costColumnIndex - 1] && typeof values[i][costColumnIndex - 1] === 'number') { values[i][costColumnIndex - 1] = values[i][costColumnIndex - 1] / 1000000; } // Chuyển đổi CPC if (values[i][cpcColumnIndex - 1] && typeof values[i][cpcColumnIndex - 1] === 'number') { values[i][cpcColumnIndex - 1] = values[i][cpcColumnIndex - 1] / 1000000; } // Định dạng CTR thành % const ctrColumnIndex = sheet.createTextFinder("metrics.ctr").findNext().getColumn(); if (values[i][ctrColumnIndex - 1] && typeof values[i][ctrColumnIndex - 1] === 'number') { values[i][ctrColumnIndex - 1] = (values[i][ctrColumnIndex - 1]).toFixed(4); // Giữ 4 số lẻ cho CTR } } dataRange.setValues(values); // Ghi lại giá trị đã chuyển đổi dataRange.setNumberFormat(costColumnIndex, '#,##0.00'); // Định dạng tiền tệ cho Cost dataRange.setNumberFormat(cpcColumnIndex, '#,##0.00'); // Định dạng tiền tệ cho CPC dataRange.setNumberFormat(ctrColumnIndex, '0.00%'); // Định dạng % cho CTR // 2. Đổi tên cột tiêu đề cho thân thiện hơn sheet.getRange(1, costColumnIndex).setValue("Cost"); sheet.getRange(1, cpcColumnIndex).setValue("Avg. CPC"); sheet.getRange(1, sheet.createTextFinder("campaign.name").findNext().getColumn()).setValue("Campaign Name"); sheet.getRange(1, sheet.createTextFinder("campaign.status").findNext().getColumn()).setValue("Status"); sheet.getRange(1, sheet.createTextFinder("metrics.clicks").findNext().getColumn()).setValue("Clicks"); sheet.getRange(1, sheet.createTextFinder("metrics.impressions").findNext().getColumn()).setValue("Impressions"); sheet.getRange(1, sheet.createTextFinder("metrics.conversions").findNext().getColumn()).setValue("Conversions"); sheet.getRange(1, sheet.createTextFinder("metrics.ctr").findNext().getColumn()).setValue("CTR"); sheet.autoResizeColumns(1, sheet.getLastColumn()); Logger.log("Đã xử lý và định dạng dữ liệu Google Ads."); } else { Logger.log("Không có dữ liệu Google Ads nào được trả về cho khoảng thời gian đã chọn."); } } catch (error) { Logger.log(`Lỗi khi lấy hoặc xử lý dữ liệu Google Ads: ${error}\nStack: ${error.stack}`); sheet.clearContents(); sheet.getRange("A1").setValue(`Lỗi khi lấy dữ liệu Google Ads: ${error}`); } }
-
Chạy, Ủy quyền và Thiết lập Trigger: Thực hiện tương tự như Bước 2 (mục 3 và 4), chọn hàm
getGoogleAdsData
và cấp quyền truy cập Google Ads khi được yêu cầu. Thiết lập trigger chạy hàng ngày.
B. Meta Ads (Facebook/Instagram), TikTok Ads (Yêu cầu Kỹ thuật Cao)
Việc lấy dữ liệu từ các nền tảng này phức tạp hơn đáng kể vì không có dịch vụ Apps Script tích hợp sẵn. Bạn cần tương tác trực tiếp với API của họ.
-
Phương pháp: Sử dụng dịch vụ
UrlFetchApp
của Apps Script để gửi yêu cầu HTTP đến API Marketing của Meta hoặc TikTok. -
Các bước chính:
- Đăng ký Ứng dụng: Tạo một ứng dụng trên cổng thông tin dành cho nhà phát triển (Developer Portal) của Meta/TikTok.
- Xác thực (OAuth 2.0): Đây là phần phức tạp nhất. Bạn cần lập trình luồng OAuth để lấy
access token
(mã truy cập) cho phép script truy cập dữ liệu quảng cáo của bạn. Bạn cũng cần cơ chế để lưu trữ và tự động làm mới token này khi nó hết hạn. - Gọi API: Xây dựng URL và payload (dữ liệu gửi đi) cho các yêu cầu API theo tài liệu của Meta/TikTok để lấy các chỉ số (metrics), thứ nguyên (dimensions) bạn cần.
- Xử lý Phản hồi: API thường trả về dữ liệu dưới dạng JSON. Bạn cần dùng
JSON.parse()
để phân tích dữ liệu này và trích xuất thông tin cần thiết. - Xử lý Giới hạn Tốc độ (Rate Limiting): Các API đều có giới hạn về số lượng yêu cầu bạn có thể thực hiện. Script cần có cơ chế chờ hoặc xử lý lỗi khi gặp giới hạn này.
- Bảo mật: Quản lý
access token
vàapp secret
một cách an toàn (ví dụ: sử dụngPropertiesService
của Apps Script, không viết thẳng vào code).
-
Khuyến nghị: Nếu bạn không quen thuộc với việc làm việc với API và OAuth 2.0, việc tự xây dựng giải pháp này có thể rất tốn thời gian và khó khăn.
C. Sử dụng Công cụ Bên Thứ Ba (Giải pháp Thay thế)
Các công cụ như Supermetrics, TwoMinuteReports, Power My Analytics… là các Add-on (tiện ích bổ sung) cho Google Sheets giúp đơn giản hóa việc lấy dữ liệu từ nhiều nền tảng quảng cáo (bao gồm Meta, TikTok, LinkedIn…).
- Ưu điểm: Dễ sử dụng, không cần code, hỗ trợ nhiều nền tảng, tự động xử lý xác thực và làm mới dữ liệu.
- Nhược điểm: Có phí (thường là đăng ký theo tháng/năm).
- Cách hoạt động: Cài đặt Add-on -> Kết nối tài khoản quảng cáo -> Tạo truy vấn (chọn chỉ số, khoảng thời gian) -> Lên lịch làm mới tự động.
🧠 Bước 4: Tổng Hợp, Trực Quan Hóa và Chia Sẻ Báo Cáo
Sau khi dữ liệu tự động đổ về các sheet GSC Data
, Google Ads Data
…, bước tiếp theo là tổng hợp và trình bày chúng.
-
Tổng hợp Dữ liệu:
- Sử dụng sheet
Tổng hợp
. - Dùng hàm
QUERY
hoặcIMPORTRANGE
để lấy và kết hợp dữ liệu từ các sheet nguồn.QUERY
rất mạnh mẽ để lọc, sắp xếp và tổng hợp. - Ví dụ (giả sử bạn muốn tổng hợp Clicks và Impressions theo nguồn):
Excel
=QUERY( {'GSC Data'!A2:C, ARRAYFORMULA(IF('GSC Data'!A2:A<>"", "GSC", IFERROR(1/0))) ; 'Google Ads Data'!A2:E, ARRAYFORMULA(IF('Google Ads Data'!A2:A<>"", "Google Ads", IFERROR(1/0))) }, "SELECT Col6, SUM(Col2), SUM(Col3) WHERE Col6 IS NOT NULL GROUP BY Col6 LABEL Col6 'Nguồn Dữ Liệu', SUM(Col2) 'Tổng Clicks', SUM(Col3) 'Tổng Impressions'", 0)
(Lưu ý: Công thức này cần điều chỉnh chính xác số cột và tên sheet của bạn. Nó tạo thêm một cột ảo để đánh dấu nguồn dữ liệu)
- Sử dụng sheet
-
Trực Quan Hóa Dữ Liệu:
- Google Sheets Charts: Tạo các biểu đồ (cột, đường, tròn…) trực tiếp từ dữ liệu trong sheet
Tổng hợp
hoặc các sheet nguồn để có cái nhìn nhanh. - Looker Studio (Khuyến nghị): Đây là công cụ miễn phí của Google cho phép tạo dashboard tương tác, chuyên nghiệp.
- Kết nối Google Sheet của bạn làm nguồn dữ liệu trong Looker Studio.
- Kéo thả các chỉ số và thứ nguyên để tạo biểu đồ, bảng biểu đa dạng.
- Khi dữ liệu trong Google Sheet được Apps Script cập nhật, dashboard Looker Studio sẽ tự động phản ánh dữ liệu mới (có thể cần cài đặt tần suất làm mới trong Looker Studio).
- Google Sheets Charts: Tạo các biểu đồ (cột, đường, tròn…) trực tiếp từ dữ liệu trong sheet
-
Chia Sẻ Báo Cáo Tự Động: Dùng Apps Script để gửi email thông báo hoặc bản tóm tắt báo cáo.
/** * Gửi email báo cáo hàng tuần đính kèm file PDF của toàn bộ spreadsheet. */ function sendWeeklyReportEmail() { const spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); const recipientEmail = "team@example.com"; // Thay bằng email người nhận const subject = `Báo cáo Marketing Tuần - ${Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'dd/MM/yyyy')}`; const body = `Chào team,
Báo cáo hiệu suất Ads & SEO tuần này đã được tổng hợp. Vui lòng xem chi tiết trong file PDF đính kèm.
Link truy cập Google Sheet gốc: ${spreadsheet.getUrl()}
Trân trọng, Hệ thống Báo cáo Tự động`;
try {
// Tạo file PDF từ toàn bộ spreadsheet
const pdfBlob = spreadsheet.getAs('application/pdf').setName(`${spreadsheet.getName()} - Report ${Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'yyyy-MM-dd')}.pdf`);
// Gửi email với file đính kèm
GmailApp.sendEmail(recipientEmail, subject, body, {
attachments: [pdfBlob],
name: "Hệ thống Báo cáo Tự động" // Tên người gửi hiển thị
});
Logger.log(`Đã gửi email báo cáo PDF thành công đến ${recipientEmail}`);
} catch (error) {
Logger.log(`Lỗi khi gửi email báo cáo: ${error}\nStack: ${error.stack}`);
// Có thể gửi thông báo lỗi đến admin
GmailApp.sendEmail('admin@example.com', 'LỖI Script Gửi Báo Cáo', `Script sendWeeklyReportEmail gặp lỗi: ${error}`);
}
}
```
* Thiết lập Trigger cho hàm `sendWeeklyReportEmail` chạy hàng tuần (ví dụ: vào sáng thứ Hai). Nhớ cấp quyền cho script gửi email qua `GmailApp`.
🚦Bước 5: Các Lưu Ý Quan Trọng
- Ủy Quyền & Quyền: Luôn kiểm tra kỹ các quyền mà script yêu cầu trước khi cấp phép.
- Xử Lý Lỗi: Sử dụng
try...catch
trong các hàm gọi API hoặc xử lý dữ liệu quan trọng. DùngLogger.log()
để ghi lại quá trình và lỗi, giúp gỡ rối dễ dàng hơn. Cân nhắc ghi lỗi vào một sheet riêng hoặc gửi email thông báo lỗi. - Giới Hạn API & Apps Script: Google Apps Script và các API bên ngoài đều có giới hạn sử dụng hàng ngày (ví dụ: thời gian chạy script, số lần gọi API, số email được gửi). Với lượng dữ liệu cực lớn, bạn có thể chạm ngưỡng này.
- Bảo Mật: Không bao giờ viết thẳng các thông tin nhạy cảm như API key, client secret, access token vào code. Sử dụng
PropertiesService
của Apps Script để lưu trữ chúng một cách an toàn hơn. - Bảo Trì: API của các nền tảng có thể thay đổi. Bạn cần theo dõi và cập nhật script của mình khi cần thiết để đảm bảo chúng tiếp tục hoạt động.
🎯 Tổng kết
- Google Sheets + Apps Script = Giải pháp automation nhẹ, tiết kiệm, mạnh mẽ cho team marketing nhỏ.
- Không cần phần mềm đắt tiền, không phải chờ IT, bạn vẫn có thể làm chủ báo cáo.
- Hệ thống hóa toàn bộ data Ads + SEO về một nơi = dễ nhìn – dễ ra quyết định.