Tài liệu

Nhận diện người dùng

Việc nhận diện người dùng kết nối các phiên chat ẩn danh với hồ sơ người dùng thật.

Cách hoạt động

Khi bạn gọi Respondo.identify(), các trường được cung cấp sẽ được gắn vào cuộc hội thoại. Tất cả các trường đều là tùy chọn — chỉ cần truyền những trường bạn có. Ví dụ, bạn có thể chỉ gửi userId mà không cần email hay tên. Nhân viên hỗ trợ sẽ thấy dữ liệu này trong bảng chi tiết cuộc hội thoại.

Tham số#

Thuộc tínhKiểuBắt buộcMô tả
emailstringtùy chọnĐịa chỉ email của người dùng
namestringtùy chọnTên hiển thị
userIdstringtùy chọnID người dùng nội bộ hoặc ID hiển thị của bạn — hiển thị nguyên trạng trong bảng điều khiển
userHashstringtùy chọnChữ ký HMAC-SHA256 để xác minh danh tính
metadataobjecttùy chọnCác cặp khóa-giá trị của trường tùy chỉnh (plan, company, v.v.)
propertiesobjecttùy chọnThuộc tính liên hệ tùy chỉnh được định nghĩa trong Cài đặt agent. Khóa phải khớp với định nghĩa thuộc tính. Giá trị được lưu với tiền tố cp_ và có thể lọc trong Inbox.
Ví dụ: ứng dụng một trang (SPA)javascript
// Sau khi đăng nhập thành công
async function onLogin(user) {
  await authenticateUser(user);

  Respondo.identify({
    email: user.email,
    name: user.fullName,
    userId: user.id,
    metadata: {
      plan: user.subscription.plan,
      company: user.company.name,
      role: user.role,
      signedUp: user.createdAt
    },
    properties: {                        // thuộc tính liên hệ tùy chỉnh
      account_type: user.accountType,    // phải khớp với khóa từ Cài đặt agent
      industry: user.industry,
      contract_tier: user.tier
    }
  });
}
Với đoạn mã cài đặt chuẩn, bạn có thể gọi identify() vào bất kỳ lúc nào — các lời gọi được thực hiện trước khi widget.js tải xong sẽ được đoạn mã xếp vào hàng đợi và tự động phát lại khi widget khởi tạo. Dữ liệu danh tính chỉ bị loại bỏ (kèm cảnh báo trong console) nếu bạn tự tải widget.js và gọi identify() trước khi từng gọi init() — trong các thiết lập thủ công, hãy luôn gọi init() trước.

Khách ẩn danh#

Nếu bạn không gọi identify(), widget sẽ tự động gán một visitor ID cố định được lưu trong localStorage (khóa respondoai_visitor_id). Trong bảng điều khiển, cuộc hội thoại hiển thị dưới dạng Guest · Web widget.

Chế độHiển thị trên bảng điều khiểnYêu cầu HMAC
Không có identify()Guest · Web widgetKhông
identify({ email, name })Hiển thị tên + emailKhông — trừ khi Xác minh danh tính được bật; khi đó email/tên không có chữ ký sẽ bị âm thầm loại bỏ và phiên vẫn ẩn danh
identify({ userId })userId hiển thị nguyên trạngKhông — trừ khi Xác minh danh tính được bật; khi đó cần một userHash hợp lệ, nếu không danh tính sẽ bị loại bỏ
identify({ userId, userHash })Danh tính người dùng đã xác minhCó — được xác minh bằng mật mã

Khi Xác minh danh tính được bật cho kênh, mọi lời gọi identify() mang email hoặc userId mà không có userHash hợp lệ sẽ bị loại bỏ ở phía máy chủ và khách truy cập vẫn ẩn danh — xem phần Xác minh danh tính (HMAC) bên dưới.

Visitor ID được giữ qua các phiên trên cùng một trình duyệt. Nó không bao giờ được gửi tới Respondo như một danh tính đã xác thực — nó chỉ dùng để duy trì tính liên tục của cuộc hội thoại ẩn danh.

Nhận diện chỉ bằng userId (không cần email hay tên)#

Nếu nền tảng của bạn không có email hay tên người dùng — ví dụ bạn chỉ có một ID hiển thị nội bộ — bạn có thể chỉ truyền userId. Không cần trường nào khác. Bảng điều khiển sẽ hiển thị userId nguyên trạng trong chi tiết cuộc hội thoại.

userId + metadata (không cần email hay tên)javascript
// Nền tảng của bạn chỉ có một ID hiển thị — thế là đủ
Respondo.identify({
  userId: user.displayId,      // ví dụ "USR-4821" — hiển thị trong bảng điều khiển
  metadata: {                  // ngữ cảnh bổ sung tùy chọn
    plan: 'premium',
    region: 'eu-west'
  }
});
// Không cần email hay tên — widget hoạt động chỉ với userId
Để ngăn việc giả mạo userId, hãy ghép nó với userHash (xem phần Xác minh danh tính bên dưới). Nếu không có HMAC, bất kỳ ai cũng có thể truyền userId bất kỳ từ console trình duyệt.

Google Tag Manager / identify() trì hoãn#

Khi nhúng qua GTM, dữ liệu người dùng có thể chưa sẵn sàng khi trang tải. Có hai cách tiếp cận:

Cách A: localStorageKey (không cần JS)javascript
// Nếu nền tảng của bạn đã ghi user ID vào localStorage:
Respondo.init({
  agentId: 'YOUR_AGENT_ID',
  localStorageKey: 'myapp_user_id'  // tự động đọc localStorage.getItem('myapp_user_id')
});
// Không cần gọi identify() — widget tự động lấy userId
Cách B: identify() trì hoãn qua dataLayerjavascript
// 1. Khởi tạo widget ngay lập tức (thẻ GTM)
Respondo.init({ agentId: 'YOUR_AGENT_ID' });

// 2. Sau đó, khi dữ liệu người dùng xuất hiện (ví dụ từ dataLayer hoặc ứng dụng của bạn):
var waitForUser = setInterval(function() {
  var uid = localStorage.getItem('myapp_user_id');
  if (uid && window.Respondo && typeof window.Respondo.identify === 'function') {
    clearInterval(waitForUser);
    Respondo.identify({ userId: uid });
  }
}, 500);
localStorageKey chỉ được dùng nếu chưa có userId nào được đặt qua identify(). Các lời gọi identify() tường minh luôn được ưu tiên.

Xác minh danh tính (HMAC)#

Nếu không xác minh, bất kỳ ai cũng có thể mạo danh một người dùng bằng cách truyền userId hoặc email giả. Xác minh danh tính dùng HMAC-SHA256 để chứng minh bằng mật mã rằng danh tính của người dùng được đặt bởi máy chủ của bạn, chứ không phải bởi mã phía client.

Cách hoạt động#

  1. Bật Xác minh danh tính trong phần cài đặt kênh của bạn — bạn sẽ nhận được một khóa bí mật.
  2. Trên máy chủ của bạn, hãy tính HMAC-SHA256(secret, userId) — secret là khóa, userId là thông điệp — và gửi kết quả về frontend. Nếu bạn chỉ nhận diện người dùng bằng email (không có userId), hãy ký email thay thế: payload được ký là userId khi có, nếu không thì là email. Nếu bạn truyền cả hai, hãy ký userId; nó được ưu tiên.
  3. Truyền hash dưới dạng userHash trong Respondo.identify().
  4. Respondo xác minh hash ở phía máy chủ. Nếu không hợp lệ, danh tính sẽ bị loại bỏ và người dùng được coi là ẩn danh.
Không bao giờ để lộ khóa bí mật của bạn trong mã frontend. HMAC phải được tính trên backend của bạn.
Khi xác minh đã được bật, mọi lời gọi identify() mang userId hoặc email đều phải kèm một userHash hợp lệ — nếu không, các trường danh tính sẽ bị loại bỏ và khách truy cập được coi là ẩn danh.

Ví dụ phía máy chủ#

Node.jsjavascript
const crypto = require('crypto');

const SECRET = process.env.RESPONDO_IDENTITY_SECRET;

function generateUserHash(userId) {
  return crypto
    .createHmac('sha256', SECRET)
    .update(userId)
    .digest('hex');
}

// Trong endpoint API của bạn:
app.get('/api/respondo-hash', (req, res) => {
  const hash = generateUserHash(req.user.id);
  res.json({ userHash: hash });
});
Pythonpython
import hmac, hashlib, os

SECRET = os.environ['RESPONDO_IDENTITY_SECRET']

def generate_user_hash(user_id: str) -> str:
    return hmac.new(
        SECRET.encode(),
        user_id.encode(),
        hashlib.sha256
    ).hexdigest()

# Trong view / endpoint của bạn:
user_hash = generate_user_hash(request.user.id)
Gogo
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
)

func GenerateUserHash(userID, secret string) string {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(userID))
    return hex.EncodeToString(mac.Sum(nil))
}

Sử dụng ở frontend#

Với Xác minh danh tínhjavascript
// Lấy hash từ máy chủ CỦA BẠN
const { userHash } = await fetch('/api/respondo-hash').then(r => r.json());

Respondo.identify({
  email: user.email,
  name: user.name,
  userId: user.id,
  userHash: userHash  // chữ ký HMAC-SHA256
});