Tạo Webhook Nhận Dữ Liệu Vào Google Sheets Bằng Apps Script doPost
14 tháng 5, 2026
5 phút đọc
Webhook Là Gì Và Tại Sao Dùng Apps Script?
Webhook là URL nhận dữ liệu theo thời gian thực từ ứng dụng khác khi có sự kiện xảy ra. Thay vì trả phí cho Zapier hay Make (Integromat), bạn tự xây dựng webhook endpoint bằng Google Apps Script — miễn phí, không giới hạn request (trong quota Apps Script).
Ứng dụng thực tế: Nhận đơn hàng từ website WooCommerce, nhận lead từ landing page, nhận cảnh báo từ monitoring system, đồng bộ dữ liệu từ app mobile.
Xây Dựng doPost() Webhook Cơ Bản
/**
* Webhook endpoint — nhận POST request và lưu vào Google Sheets
* Deploy: Extensions → Apps Script → Deploy → New Deployment
* Type: Web App | Execute as: Me | Who has access: Anyone
*/
function doPost(e) {
try {
// Parse JSON body
let data;
if (e.postData && e.postData.type === 'application/json') {
data = JSON.parse(e.postData.contents);
} else if (e.parameter) {
data = e.parameter; // Form-encoded data
} else {
return jsonResponse({ success: false, error: 'No data received' }, 400);
}
// Validate token bảo mật
const expectedToken = PropertiesService.getScriptProperties().getProperty('WEBHOOK_TOKEN');
if (expectedToken && data.token !== expectedToken) {
return jsonResponse({ success: false, error: 'Unauthorized' }, 401);
}
// Lưu vào sheet
const sheetName = data.sheet || 'Webhook Data';
const sheet = getOrCreateSheet(sheetName);
const savedRow = appendDataToSheet(sheet, data);
return jsonResponse({
success: true,
row: savedRow,
message: 'Data saved successfully',
timestamp: new Date().toISOString()
});
} catch (error) {
console.error('doPost error: ' + error.toString());
return jsonResponse({ success: false, error: error.toString() }, 500);
}
}
function jsonResponse(data, statusCode) {
// Apps Script không hỗ trợ custom HTTP status code
// Luôn trả 200, đặt status trong body
return ContentService
.createTextOutput(JSON.stringify({ ...data, statusCode: statusCode || 200 }))
.setMimeType(ContentService.MimeType.JSON);
}
Xử Lý Dữ Liệu Và Append Vào Sheet
function appendDataToSheet(sheet, data) {
const timestamp = new Date();
// Nếu sheet trống, tạo header row
if (sheet.getLastRow() === 0) {
const headers = ['Timestamp', ...Object.keys(data).filter(k => k !== 'token' && k !== 'sheet')];
sheet.appendRow(headers);
sheet.getRange(1, 1, 1, headers.length).setFontWeight('bold').setBackground('#f0f0f0');
}
// Lấy headers để map đúng thứ tự cột
const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
const newRow = headers.map(header => {
if (header === 'Timestamp') return timestamp;
return data[header] !== undefined ? data[header] : '';
});
sheet.appendRow(newRow);
return sheet.getLastRow();
}
function getOrCreateSheet(sheetName) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName(sheetName);
if (!sheet) {
sheet = ss.insertSheet(sheetName);
}
return sheet;
}
doGet() Để Đọc Dữ Liệu
/**
* GET endpoint — trả về dữ liệu từ sheet dưới dạng JSON
* URL: https://script.google.com/...?action=list&sheet=Orders&limit=10
*/
function doGet(e) {
try {
const action = e.parameter.action || 'list';
const sheetName = e.parameter.sheet || 'Webhook Data';
const limit = parseInt(e.parameter.limit) || 100;
// Validate token
const expectedToken = PropertiesService.getScriptProperties().getProperty('WEBHOOK_TOKEN');
if (expectedToken && e.parameter.token !== expectedToken) {
return jsonResponse({ success: false, error: 'Unauthorized' }, 401);
}
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
if (!sheet) {
return jsonResponse({ success: false, error: 'Sheet not found: ' + sheetName });
}
if (action === 'count') {
return jsonResponse({ success: true, count: Math.max(0, sheet.getLastRow() - 1) });
}
// Trả về dữ liệu dạng array of objects
const allData = sheet.getDataRange().getValues();
if (allData.length <= 1) {
return jsonResponse({ success: true, data: [], total: 0 });
}
const headers = allData[0];
const rows = allData.slice(1, limit + 1).map(row => {
const obj = {};
headers.forEach((h, i) => { obj[h] = row[i]; });
return obj;
});
return jsonResponse({ success: true, data: rows, total: allData.length - 1 });
} catch (error) {
return jsonResponse({ success: false, error: error.toString() }, 500);
}
}
Deploy Web App Và Cài Token Bảo Mật
Deploy:
- Apps Script Editor → Deploy → New deployment
- Type: Web app
- Execute as: Me (dùng quyền tài khoản của bạn)
- Who has access: Anyone (để nhận request từ bên ngoài)
- Copy URL deployment
Cài Secret Token:
// Chạy hàm này một lần để set token
function setupWebhookToken() {
const token = Utilities.getUuid(); // Tạo UUID ngẫu nhiên
PropertiesService.getScriptProperties().setProperty('WEBHOOK_TOKEN', token);
console.log('Token:', token); // Copy token này để dùng trong requests
}
Test Webhook Với curl
# Test POST request
curl -X POST "https://script.google.com/macros/s/AKfy.../exec" -H "Content-Type: application/json" -d '{"token":"your-token-here","sheet":"Orders","name":"Nguyen Van A","email":"a@test.com","amount":500000}'
# Test GET request
curl "https://script.google.com/macros/s/AKfy.../exec?action=list&sheet=Orders&token=your-token&limit=5"
Tích Hợp Với WooCommerce / WordPress
<?php
// functions.php — gửi đơn hàng mới đến Google Sheets
add_action('woocommerce_new_order', function($orderId) {
$order = wc_get_order($orderId);
$webhookUrl = 'https://script.google.com/macros/s/AKfy.../exec';
wp_remote_post($webhookUrl, [
'body' => json_encode([
'token' => 'your-secret-token',
'sheet' => 'WooCommerce Orders',
'order_id' => $orderId,
'customer' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
'email' => $order->get_billing_email(),
'total' => $order->get_total(),
'status' => $order->get_status(),
]),
'headers' => ['Content-Type' => 'application/json'],
]);
});
?>
Kết hợp với tự động gửi email khi có row mới để nhận thông báo mỗi khi webhook nhận được đơn hàng từ WooCommerce.
Chia sẻ bài viết:
Tuân Hoang
Đội ngũ SheetStore
Google SheetsGoogle Apps ScriptCRMAutomationPhần mềm quản lý doanh nghiệp
Google Workspace Certified, 5+ years experience
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.