Tự đếm click affiliate bằng Cloudflare D1 thay vì chờ báo cáo sàn

Báo cáo của Shopee cập nhật mỗi ngày một lần lúc 3 giờ 30 chiều. Một Worker chuyển hướng và một bảng D1 cho bạn số liệu ngay lập tức, và miễn phí.

Ngô Quang Hiển

Ảnh minh họa mã nguồn trên màn hình

Bảng điều khiển Shopee Affiliate ghi một dòng nhỏ ở góc: “Dữ liệu được cập nhật hàng ngày vào lúc 3:30 chiều”. Nghĩa là đăng bài lúc 9 giờ sáng thì gần một ngày sau bạn mới biết có ai bấm vào hay không.

Với người làm web, chờ như vậy là không cần thiết.

Ý tưởng: một lớp chuyển hướng của riêng mình

Thay vì đặt link s.shopee.vn thẳng vào HTML, đặt một đường dẫn nội bộ:

<a href="/go/tai-nghe-abc" rel="nofollow sponsored">tai nghe ABC</a>

Đường dẫn /go/ do bạn kiểm soát. Khi có người bấm, mã của bạn chạy trước, ghi một dòng vào database, rồi mới chuyển hướng sang link thật.

Vì sao đáng làm, ngoài chuyện xem số sớm

Đổi link không phải sửa bài. Sản phẩm hết hàng, campaign kết thúc, đổi shop: sửa một dòng cấu hình thay vì mở lại từng bài viết cũ.

Không rải link affiliate ra HTML tĩnh. Trình thu thập dữ liệu chỉ thấy đường dẫn nội bộ, và bạn chặn nó trong robots.txt.

Số liệu là của bạn. Nếu một ngày bạn chạy thêm TikTok hay một sàn khác, tất cả vẫn nằm chung một bảng, cùng một cách đo.

Bảng dữ liệu tối thiểu

Đừng thiết kế thừa. Một bảng, năm cột là đủ để trả lời câu hỏi duy nhất bạn thật sự có: bài nào ra click.

CREATE TABLE clicks (
  id      INTEGER PRIMARY KEY AUTOINCREMENT,
  slug    TEXT    NOT NULL,
  ts      INTEGER NOT NULL,
  country TEXT    NOT NULL DEFAULT '',
  referer TEXT    NOT NULL DEFAULT ''
);

CREATE INDEX idx_clicks_slug_ts ON clicks (slug, ts);

Không lưu địa chỉ IP, không lưu chuỗi user agent. Bạn không cần chúng, và không lưu thì không phải nghĩ về chuyện bảo vệ chúng.

Chỗ dễ làm sai: đừng bắt người dùng chờ database

Đây là điểm quan trọng nhất trong toàn bộ bài này.

// Ghi log chạy SAU khi phản hồi đã được gửi đi.
ctx.waitUntil(
  ctx.env.DB.prepare('INSERT INTO clicks (slug, ts) VALUES (?1, ?2)')
    .bind(slug, Date.now())
    .run()
    .catch((err) => console.error(err))
);

return new Response(null, {
  status: 302,
  headers: { Location: target, 'Cache-Control': 'no-store' },
});

Hai chi tiết:

waitUntil đẩy việc ghi ra ngoài đường đi của phản hồi. Người bấm được chuyển hướng ngay, và nếu D1 chậm hoặc lỗi thì họ vẫn tới đúng nơi cần tới.

Cache-Control: no-store là bắt buộc. Thiếu nó, CDN sẽ cache lệnh chuyển hướng và từ click thứ hai trở đi mã của bạn không chạy nữa. Bạn sẽ ngồi tự hỏi vì sao số liệu đứng im.

Chi phí

Gói miễn phí của Cloudflare D1 cho 5 triệu dòng đọc và 100 nghìn dòng ghi mỗi ngày. Một trang blog cá nhân không chạm tới mức đó. Toàn bộ hệ thống này tốn đúng tiền tên miền.

Cái nó không thay thế

Số liệu này là click, không phải đơn hàng. Chuyển đổi và hoa hồng vẫn chỉ có trong báo cáo của sàn, vì chỉ sàn mới biết ai mua gì. Hai nguồn dùng cho hai việc khác nhau: click của bạn nói bài nào hấp dẫn, báo cáo của sàn nói bài nào ra tiền. Cần cả hai.