사용자 식별
사용자 식별은 익명 채팅 세션을 실제 사용자 프로필과 연결합니다.
작동 방식
Respondo.identify()를 호출하면 제공된 필드가 대화에 첨부됩니다. 모든 필드는 선택 사항입니다 — 가지고 있는 값만 전달하세요. 예를 들어 이메일이나 이름 없이 userId만 보낼 수도 있습니다. 지원 상담원은 이 데이터를 대화 상세 패널에서 확인합니다.
매개변수#
| 속성 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
| string | 선택 | 사용자의 이메일 주소 | |
| name | string | 선택 | 표시 이름 |
| userId | string | 선택 | 내부 사용자 ID 또는 표시 ID — 대시보드에 그대로 표시됩니다 |
| userHash | string | 선택 | 신원 확인을 위한 HMAC-SHA256 서명 |
| metadata | object | 선택 | 커스텀 필드의 키-값 쌍(plan, company 등) |
| properties | object | 선택 | Agent Settings에서 정의한 커스텀 연락처 속성. 키는 속성 정의와 일치해야 합니다. 값은 cp_ 접두사와 함께 저장되며 Inbox에서 필터링할 수 있습니다. |
예시: 싱글 페이지 앱javascript
// 로그인 성공 후
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: { // 커스텀 연락처 속성
account_type: user.accountType, // Agent Settings의 키와 일치해야 함
industry: user.industry,
contract_tier: user.tier
}
});
}표준 설치 스니펫을 사용하면
identify()를 언제든지 호출할 수 있습니다 — widget.js 로드가 끝나기 전에 이루어진 호출은 스니펫이 큐에 쌓아 두었다가 위젯이 초기화되면 자동으로 다시 재생합니다. 신원 데이터가(콘솔 경고와 함께) 버려지는 경우는 widget.js를 직접 로드하면서 init()을 한 번도 호출하지 않은 채 identify()를 호출할 때뿐입니다 — 수동 설정에서는 항상 init()을 먼저 호출하세요.익명 방문자#
identify()를 호출하지 않으면, 위젯이 자동으로 영속적인 방문자 ID를 할당하여 localStorage(키 respondoai_visitor_id)에 저장합니다. 대시보드에서는 대화가 Guest · Web widget으로 표시됩니다.
| 모드 | 대시보드 표시 | HMAC 필요 여부 |
|---|---|---|
identify() 없음 | Guest · Web widget | 아니요 |
identify({ email, name }) | 이름 + 이메일 표시 | 아니요 — 단, 신원 확인이 활성화된 경우에는 서명되지 않은 이메일/이름이 조용히 제거되고 세션은 익명으로 유지됩니다 |
identify({ userId }) | userId 그대로 표시 | 아니요 — 단, 신원 확인이 활성화된 경우에는 유효한 userHash가 필요하며, 없으면 신원이 제거됩니다 |
identify({ userId, userHash }) | 검증된 사용자 신원 | 예 — 암호학적으로 검증됨 |
채널에 신원 확인이 활성화되어 있으면, 유효한 userHash 없이 이메일이나 userId를 담은 identify()는 서버 측에서 제거되고 방문자는 익명으로 유지됩니다 — 아래의 신원 확인(HMAC)을 참조하세요.
방문자 ID는 동일한 브라우저에서 여러 세션에 걸쳐 유지됩니다. 인증된 신원으로 Respondo에 전송되는 일은 없으며 — 익명 대화의 연속성을 위해서만 사용됩니다.
userId만으로 식별(이메일이나 이름 없이)#
플랫폼에 사용자 이메일이나 이름이 없다면 — 예를 들어 내부 표시 ID만 있다면 — userId만 전달할 수 있습니다. 다른 필드는 필요 없습니다. 대시보드는 대화 상세에 userId를 그대로 표시합니다.
userId + metadata(이메일이나 이름 없이)javascript
// 플랫폼에 표시 ID만 있어도 충분합니다
Respondo.identify({
userId: user.displayId, // 예: "USR-4821" — 대시보드에 표시됨
metadata: { // 선택적 추가 맥락
plan: 'premium',
region: 'eu-west'
}
});
// 이메일이나 이름은 필요 없습니다 — 위젯은 userId만으로 동작합니다userId 위조를 방지하려면
userHash와 함께 사용하세요 (아래의 신원 확인 참고). HMAC 없이는 누구나 브라우저 콘솔에서 임의의 userId를 전달할 수 있습니다.Google Tag Manager / 지연된 identify()#
GTM을 통해 임베드할 때는 페이지 로드 시점에 사용자 데이터가 준비되지 않을 수 있습니다. 두 가지 방법이 있습니다:
옵션 A: localStorageKey(JS 불필요)javascript
// 플랫폼이 이미 사용자 ID를 localStorage에 기록하는 경우:
Respondo.init({
agentId: 'YOUR_AGENT_ID',
localStorageKey: 'myapp_user_id' // localStorage.getItem('myapp_user_id')를 자동으로 읽음
});
// identify() 호출 불필요 — 위젯이 스스로 userId를 가져옵니다옵션 B: dataLayer를 통한 지연된 identify()javascript
// 1. 위젯을 즉시 초기화(GTM 태그)
Respondo.init({ agentId: 'YOUR_AGENT_ID' });
// 2. 이후 사용자 데이터가 나타나면(예: dataLayer 또는 앱에서):
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는 identify()를 통해 userId가 아직 설정되지 않은 경우에만 사용됩니다. 명시적 identify() 호출이 항상 우선합니다.신원 확인(HMAC)#
검증이 없으면 누구나 가짜 userId나 email을 전달하여 사용자를 사칭할 수 있습니다. 신원 확인은 HMAC-SHA256을 사용하여 사용자 신원이 클라이언트 측 코드가 아니라 서버에서 설정되었음을 암호학적으로 증명합니다.
작동 방식#
- 채널 설정에서 신원 확인을 활성화하세요 — 비밀 키를 받게 됩니다.
- 서버에서
HMAC-SHA256(secret, userId)를 계산하고 — 시크릿이 키, userId가 메시지입니다 — 결과를 프런트엔드로 전송하세요. 사용자를 이메일로만 식별한다면(userId 없음) 대신 이메일을 서명하세요: 서명 대상은 userId가 설정되어 있으면 userId, 없으면 이메일입니다. 둘 다 전달하면 userId를 서명합니다 — userId가 우선합니다. Respondo.identify()에서 해시를userHash로 전달하세요.- Respondo가 서버 측에서 해시를 검증합니다. 유효하지 않으면 신원 정보가 제거되고 사용자는 익명으로 처리됩니다.
비밀 키를 프런트엔드 코드에 절대 노출하지 마세요. HMAC은 백엔드에서 계산해야 합니다.
검증이 활성화되면
userId나 email을 담은 모든 identify() 호출에 유효한 userHash가 포함되어야 합니다 — 그렇지 않으면 신원 필드가 제거되고 방문자는 익명으로 처리됩니다.서버 측 예시#
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');
}
// API 엔드포인트에서:
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()
# 뷰 / 엔드포인트에서:
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))
}프런트엔드 사용법#
신원 확인 적용javascript
// 서버에서 해시를 가져옵니다
const { userHash } = await fetch('/api/respondo-hash').then(r => r.json());
Respondo.identify({
email: user.email,
name: user.name,
userId: user.id,
userHash: userHash // HMAC-SHA256 서명
});