Thực hành n8n đa kênh · Bài 4

Đưa form website về bảng khách hàng bằng n8n

Bài thực hành cho website đã có form đăng ký: đưa dữ liệu về bảng khách qua node Webhook, chặn spam bằng CAPTCHA có xác minh phía máy chủ, xin đồng ý đúng cách và chỉ lưu những gì cần. Đối chiếu tài liệu chính thức của n8n (bản 2.44.4), Cloudflare, Google và Luật Bảo vệ dữ liệu cá nhân ngày 20–21/10/2026.

Cập nhật 21/10/2026⏱ 10 phút đọcCài đặt & bắt đầuNgười mới → Trung cấp

Khách điền form, thông tin nằm im trong hộp thư

Website có form "Đăng ký tư vấn". Mỗi lần khách gửi, một email về hộp thư chung; nhân viên chép tay sang bảng tính, lúc nhớ lúc quên, khách thật lẫn giữa thư rác từ bot. (Tình huống minh hoạ.)

Bài này nối form có sẵn vào bảng khách bằng n8n: bot rác bị chặn trước khi chạm tới bảng, mỗi dòng có bằng chứng khách đã đồng ý cho bạn liên hệ.

Đưa form website về bảng khách bằng n8n là gì?

Đưa form website về bảng khách bằng n8n là đổi địa chỉ nhận của form thành Production URL của node Webhook, để n8n xác minh CAPTCHA, kiểm tra ô đồng ý, ghi một dòng vào Google Sheets rồi đưa khách tới trang cảm ơn.

  1. Form trên websiteÔ đồng ý, ô ẩn bẫy bot, widget CAPTCHA
  2. WebhookNhận POST, lọc sớm bằng Only Run If
  3. HTTP RequestGọi Siteverify xác minh token CAPTCHA
  4. IfCAPTCHA hợp lệ và khách đã tích ô đồng ý?
  5. Google SheetsAppend or Update Row theo số điện thoại
  6. Respond to WebhookRedirect tới trang cảm ơn
Luồng form website về bảng khách (ví dụ minh hoạ)
Sơ đồ đưa form website về bảng khách hàng bằng n8n: form có ô đồng ý và CAPTCHA gửi POST tới node Webhook, HTTP Request gọi Siteverify xác minh token, node If rẽ nhánh hợp lệ hoặc từ chối, Google Sheets Append or Update Row ghi một dòng khách, Respond to Webhook chuyển khách tới trang cảm ơn
Hình: Form website đi qua Webhook, CAPTCHA, If rồi vào Google Sheets (minh hoạ)

Nếu bạn chưa có website, dùng n8n Form Trigger như trong workflow đầu tiên sẽ nhanh hơn.

Chuẩn bị

Dòng tiêu đề Google SheetCopy rồi gõ từng tên vào một ô ở dòng 1 của bảng
thoi_gian | ho_ten | so_dien_thoai | nhu_cau | dong_y_tu_van | dong_y_nhan_tin | phien_ban_dong_y | trang_thai

Không có cột ngày sinh, địa chỉ, số giấy tờ: form tư vấn không cần thì không thu.

Nguồn: Google Sheets – dòng tiêu đề · Turnstile – widget

Bước 1. Sửa form: ô đồng ý, ô ẩn và widget CAPTCHA

Mẫu dưới là form HTML tối giản (ví dụ minh hoạ). Dùng trình dựng trang khác thì giữ giao diện, chỉ cần: gửi tới Production URL, tên trường như mẫu, hai ô đồng ý tách riêng, có widget CAPTCHA.

Mã HTML form mẫuCopy rồi dán vào trang form; thay phần trong <…>
<form action="<Production URL của node Webhook>" method="POST">
  <label>Họ tên <input name="ho_ten" required></label>
  <label>Số điện thoại <input name="so_dien_thoai" type="tel" required></label>
  <label>Bạn cần tư vấn gì? <textarea name="nhu_cau"></textarea></label>

  <!-- Ô ẩn bẫy bot (kỹ thuật thường dùng, không có tiêu chuẩn chính thức) -->
  <div style="position:absolute;left:-5000px" aria-hidden="true">
    <input name="website" tabindex="-1" autocomplete="off">
  </div>

  <label><input type="checkbox" name="dong_y_tu_van" value="co" required>
    Tôi đồng ý để <Tên công ty> dùng họ tên, số điện thoại và nhu cầu tôi cung cấp để liên hệ tư vấn. <a href="<link chính sách dữ liệu>">Chi tiết</a></label>
  <label><input type="checkbox" name="dong_y_nhan_tin" value="co">
    (Không bắt buộc) Tôi đồng ý nhận tin giới thiệu sản phẩm qua <kênh>, tối đa <tần suất>; từ chối bất kỳ lúc nào.</label>

  <input type="hidden" name="phien_ban_dong_y" value="<mã phiên bản lời đồng ý, vd DY-2026-10>">
  <div class="cf-turnstile" data-sitekey="<Site key của Turnstile>"></div>
  <button type="submit">Gửi đăng ký</button>
</form>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

Nguồn: Turnstile – script, cf-turnstile-response · Luật 91/2025/QH15 – Điều 9, 28

Bước 2. Node Webhook: nhận dữ liệu và lọc sớm

  1. Tạo workflow, thêm Webhook. HTTP Method: POST. Path: giữ chuỗi ngẫu nhiên mặc định để khó đoán.
  2. Respond: Using 'Respond to Webhook' Node.
  3. Options → Ignore Bots: bật, để bỏ qua trình xem trước liên kết và bot thu thập web.
  4. Options → Only Run If: dán biểu thức dưới đây. Yêu cầu có ô ẩn bị điền, hoặc thiếu token CAPTCHA, nhận mã 200 nhưng không tạo execution, nên không tốn lượt chạy của gói.
  5. Bấm Listen for test event (Test URL nghe trong 120 giây), tạm đặt Test URL vào form, gửi thử bằng dữ liệu giả. Dữ liệu hiện ở OUTPUT, các trường nằm trong body.
Biểu thức ô Only Run IfCopy rồi dán vào ô Only Run If của node Webhook
{{ !$json.body.website && !!$json.body['cf-turnstile-response'] }}
Tài liệu n8n lưu ý: nếu biểu thức Only Run If bị lỗi, n8n cho yêu cầu đi qua và chỉ ghi cảnh báo. Vì vậy bước xác minh CAPTCHA ở Bước 3 vẫn bắt buộc. Xác thực Header/Basic/JWT của Webhook chỉ dùng được khi máy chủ website gửi thay trình duyệt; giá trị bí mật đặt trong mã HTML công khai thì ai cũng xem được.

Website gửi form bằng JavaScript (fetch) thì đặt Options → Allowed Origins (CORS) là tên miền website thay cho mặc định *.

Nguồn: Webhook – Only Run If, Ignore Bots, CORS · Test URL 120 giây

Bước 3. Xác minh CAPTCHA phía máy chủ

Theo Cloudflare, chỉ hiện widget trên trình duyệt là không đủ: phải gọi API Siteverify cho từng token. Token hết hạn sau 300 giây và chỉ xác minh được một lần. Để Secret key không nằm lộ trong node, cất nó vào credential:

  1. Vào Credentials → tạo credential loại Custom Auth (nhóm credential chung của HTTP Request), dán JSON dưới đây với Secret key thật. Khi lưu, đặt Allowed HTTP Request Domains chỉ cho challenges.cloudflare.com nếu ô này có.
  2. Thêm HTTP Request sau Webhook, cấu hình như khối thứ hai.
  3. Chạy thử: OUTPUT phải có success: true và hostname đúng tên miền website của bạn.
Nội dung ô JSON của credential Custom AuthCopy rồi dán vào ô JSON trong cửa sổ Credentials; thay phần trong <…>
{
  "body": {
    "secret": "<Secret key của Turnstile>"
  }
}
Cấu hình node HTTP RequestCopy để đối chiếu khi điền từng ô của node
Method: POST
URL: https://challenges.cloudflare.com/turnstile/v0/siteverify
Authentication: Generic Credential Type → Custom Auth → (credential vừa tạo)
Send Body: bật · Body Content Type: JSON · Specify Body: Using Fields Below
  Name: response
  Value: {{ $('Webhook').item.json.body['cf-turnstile-response'] }}

Tham số remoteip (IP khách) là tuỳ chọn; không gửi thì khỏi xử lý thêm dữ liệu cá nhân. Lỗi timeout-or-duplicate: token đã dùng hoặc quá hạn.

Dùng Google reCAPTCHA: POST tới https://www.google.com/recaptcha/api/siteverify với secret, response (token ở trường g-recaptcha-response, hiệu lực hai phút, xác minh một lần). Google ghi đây là tham số POST, không nói nhận JSON, nên chọn Body Content Type Form Urlencoded và dùng credential Custom Auth riêng (domain www.google.com). Đầu trang xác minh này hiện ghi đã ngưng dùng (deprecated), trỏ sang Google Cloud Fraud Defense: đọc tài liệu hiện hành trước khi chọn. Với cả hai, chạy thử bằng Test URL và xem OUTPUT để chắc khoá bí mật được gộp đúng vào yêu cầu.

Nguồn: Turnstile – server-side validation · reCAPTCHA – verify · HTTP Request credentials – Custom Auth · Credentials – Allowed domains

Bước 4. Rẽ nhánh hợp lệ hay từ chối

Thêm If với hai điều kiện, nối bằng AND:

Nhánh false: thêm Respond to Webhook, Respond With Redirect về trang form kèm thông báo chung "Gửi chưa thành công, vui lòng thử lại". Không đưa họ tên hay số điện thoại lên đường dẫn chuyển hướng.

Nguồn: If node · Respond to Webhook – Redirect

Bước 5. Ghi vào Google Sheets, chống trùng

  1. Nhánh true: thêm Google Sheets, thao tác Append or Update Row (có thì cập nhật, chưa có thì thêm).
  2. Credential: OAuth2, đăng nhập tài khoản Google công việc sở hữu bảng.
  3. Chọn Document, Sheet. Column to Match On: so_dien_thoai, để khách gửi lại không tạo dòng trùng.
  4. Mapping Column Mode: Map Each Column Manually. Chỉ ghép những cột trong bảng: kéo từ body của Webhook; thoi_gian điền {{ $now.toISO() }}; trang_thai điền moi. Token CAPTCHA và ô ẩn không có cột nên không bao giờ bị lưu.
  5. Settings của node: bật Retry On Fail.

Google Sheets API cho 60 lượt ghi mỗi phút mỗi người dùng trong một dự án (300 cho cả dự án), dư cho form tư vấn. Khách gửi lại thì dòng cũ bị ghi đè, kể cả thời điểm đồng ý; cần giữ lịch sử thì thêm trang tính "Nhật ký đồng ý" dùng Append Row.

Bản tự cài dùng ứng dụng OAuth của Google ở trạng thái Testing thì refresh token hết hạn sau 7 ngày, credential sẽ ngừng chạy. Hãy chuyển ứng dụng OAuth sang trạng thái phát hành trước khi chạy thật. Chi tiết làm bảng thành CRM: Google Sheets làm CRM với n8n.

Nguồn: Append or Update Row, Column to Match On · Sheets API limits · OAuth 2.0 – Testing 7 ngày · Google credentials · Retry On Fail

Bước 6. Trả lời trình duyệt, rồi Publish

  1. Sau Google Sheets, thêm Respond to Webhook, Respond With Redirect, Redirect URL là trang cảm ơn, ví dụ https://<website>/cam-on/. Website gửi bằng JavaScript thì chọn JSON, trả {"ok": true} rồi tự hiện lời cảm ơn.
  2. Không trả HTML: từ n8n 1.103.0, HTML trả qua webhook bị bọc trong iframe hộp cát, JavaScript và liên kết tương đối không chạy.
  3. Bấm Publish. Đổi địa chỉ form trên website sang Production URL. Từ giờ dữ liệu chạy thật không hiện trên bảng vẽ, xem ở tab Executions.
  4. Báo sale ngay: nối node Telegram cuối nhánh true như bot Telegram báo cáo.
Minh hoạ các lớp chống spam và xin đồng ý cho form website nối n8n: ô ẩn bẫy bot lọc bằng Only Run If (gợi ý thực hành, không có nguồn chính thức), Ignore Bots, CAPTCHA Turnstile hoặc reCAPTCHA xác minh Siteverify token dùng một lần, ô đồng ý không đánh dấu sẵn tách theo mục đích, chỉ lưu cột cần thiết vào bảng khách
Hình: Các lớp chặn spam và nguyên tắc xin đồng ý trên form (minh hoạ)

Theo tài liệu n8n, nếu workflow lỗi trước khi tới Respond to Webhook, trình duyệt nhận mã 500; nếu workflow kết thúc mà không đi qua node này, trả mã 200 kèm thông báo mặc định. Trên n8n Cloud, webhook không trả lời trong 100 giây sẽ báo lỗi 524.

Nguồn: Respond to Webhook – Redirect, 500, iframe · Production URL, Executions · Webhook – common issues

Kiểm tra đã chạy đúng

Lỗi thường gặp

Hiện tượngNguyên nhân thường gặpCách xử lý
Gửi form báo không tìm thấy webhookChưa Publish, hoặc form vẫn dùng Test URL đã hết 120 giâyPublish, dùng Production URL
Trình duyệt báo lỗi CORSWebsite gửi bằng fetch, chưa khai báo tên miềnĐặt Allowed Origins (CORS) là tên miền website
Siteverify luôn success: falseSai Secret key, thiếu token, hoặc token đã dùng/quá hạnXem error-codes; kiểm tra credential và tên trường
Lỗi 500 sau khi gửiNode trước Respond to Webhook bị lỗiXem Executions; thường do credential Google hoặc tên cột
Credential Google ngừng chạy sau một tuầnỨng dụng OAuth ở trạng thái TestingPhát hành ứng dụng OAuth rồi kết nối lại
Lệch cột trong bảngĐổi tên cột sau khi cấu hìnhChọn lại Mapping Column Mode để tải lại tên cột

Nguồn: Webhook – test/production · Turnstile – error codes · Google Sheets – common issues

An toàn và chính sách

Nguồn: Bộ Công an – Luật 91/2025 hiệu lực 01/01/2026 · Luật 91/2025/QH15 – văn bản · Nghị định 91/2020/NĐ-CP · Biến môi trường executions · Workflow settings

Muốn được tư vấn cách áp dụng n8n cho quy trình của doanh nghiệp, bạn có thể đăng ký Tư vấn 1-1 hoặc Coaching 1-1; chi phí báo sau buổi tư vấn.

Đọc tiếp: Đưa lead TikTok về hệ thống →

Câu hỏi thường gặp

Đã có n8n Form Trigger, sao còn dùng Webhook?

n8n Form Trigger tự sinh trang form, hợp khi bạn chưa có website hoặc cần form nhanh, xem bài workflow đầu tiên. Khi website đã có form theo giao diện thương hiệu, Webhook cho bạn giữ nguyên form đó và chỉ đổi nơi nhận dữ liệu.

Chỉ dùng ô ẩn (honeypot) để chặn spam có đủ không?

Không nên dựa vào một lớp. Ô ẩn là kỹ thuật thường dùng nhưng không có tiêu chuẩn chính thức và không chặn được bot chủ đích. Lớp chắc chắn hơn là CAPTCHA có xác minh phía máy chủ: Cloudflare ghi rõ widget phía trình duyệt là không đủ, phải gọi Siteverify cho từng token.

Có được đánh dấu sẵn ô đồng ý để khách đỡ phải bấm không?

Không. Luật Bảo vệ dữ liệu cá nhân 91/2025/QH15 yêu cầu sự đồng ý tự nguyện, rõ ràng, theo từng mục đích, và nêu rõ sự im lặng hoặc không phản hồi không được coi là đồng ý. Ô đồng ý phải để trống cho khách tự chọn.

Có nên lưu địa chỉ IP của người gửi form không?

Chỉ lưu khi có mục đích rõ. Tham số địa chỉ IP khi gọi Siteverify là tuỳ chọn ở cả Turnstile và reCAPTCHA, nên bạn có thể không gửi và không lưu. Nguyên tắc dữ liệu tối thiểu giúp giảm rủi ro khi bảng tính bị chia sẻ nhầm.

Vì sao gửi form xong bị lỗi 500?

Theo tài liệu n8n, khi workflow lỗi trước lúc tới node Respond to Webhook, webhook trả mã 500. Mở tab Executions xem node nào lỗi, thường là credential Google hết hạn hoặc tên cột trong bảng bị đổi.

Tài liệu liên quan

Xem tất cả tài liệu hướng dẫn →

Bước tiếp theo

Đăng ký tư vấn 1:1

Chuyên gia Aduca cùng bạn xem quy trình hiện tại, chọn việc nên giao cho AI Agent trước và cách kiểm soát rủi ro.

Về AducaChuỗi bài do đội ngũ Aduca biên soạn từ kinh nghiệm đào tạo và triển khai AI Agent cho Marketing – Sales. Aduca Academy do Nguyễn Đức – Chủ tịch Aduca Group sáng lập; ông kinh doanh thương mại điện tử từ 2012, chạy quảng cáo Facebook từ 2014 và đào tạo từ 2016. Phần thực hành từng bước nằm trong các thư mục OpenClaw, Hermes Agent, Claude, ChatGPT và n8n, Second Brain.

Nguồn tham khảo

Lịch sử cập nhật

Miễn trừ trách nhiệm

Bài viết thuộc chuỗi kiến thức của Công ty Cổ phần Giáo dục Aduca, chia sẻ miễn phí cho mục đích học tập. Thông tin kỹ thuật đối chiếu với tài liệu chính thức của các dự án và nền tảng tại ngày cập nhật (có ghi nguồn); phần nhận định là quan điểm của Aduca. OpenClaw, Hermes Agent, Claude (thương hiệu của Anthropic), ChatGPT (thương hiệu của OpenAI), n8n (thương hiệu của n8n GmbH), các phần mềm chạy model và các model AI mở (Ollama, LM Studio, Qwen, Gemma, gpt-oss…), Obsidian, Notion, phương pháp Building a Second Brain (Tiago Forte) cùng các phần mềm, dịch vụ nêu trong bài thuộc về chủ sở hữu tương ứng, không thuộc Aduca; Aduca không phải đối tác chính thức của các công ty này. Tính năng, gói và giá có thể thay đổi bất cứ lúc nào – hãy kiểm tra trang chính thức trước khi mua. Kết quả áp dụng phụ thuộc quy trình, dữ liệu và con người của từng doanh nghiệp; bài viết không cam kết doanh thu hay hiệu quả cụ thể. © 2026 Aduca — được trích dẫn khi ghi rõ nguồn aduca.vn.