사용자 식별자와 속성

개요

사용자 식별자는 사용자를 고유하게 식별하는 목적으로 사용합니다.
사용자 식별자의 의미와 중요성, 선택하는 기준 등에 대해서는 사용자 식별자 관리하기 문서를 참고하시기 바랍니다.

이 문서에서는 SDK에서 사용자 식별자를 처리하는 두 가지 방식을 다룹니다.

SDK 내부적으로 관리하는 디바이스 식별자 사용

🚧

클라이언트 측 SDK에 한해 사용 가능합니다.

클라이언트 측 SDK는 디바이스 식별자를 내부적으로 관리하는 기능을 포함하고 있습니다. 내부적으로 관리되는 디바이스 식별자를 통해 사용자를 자동으로 식별합니다.

사용자 지정 식별자 사용

사용자 식별자를 파라미터로 직접 전달하는 방식입니다. 전달하는 식별자는 직접 관리하는 Primary Key, 디바이스 식별자, 회원 아이디, 이메일, 해시값 등이 될 수 있습니다.

  • 사용자 지정 식별자를 만드는 예시 코드를 본 문서 하단에서 제공하고 있습니다.

클라이언트 측 SDK

두 가지 방법을 통해 사용자 식별자를 사용할 수 있습니다.

  • SDK 내부적으로 관리하는 디바이스 식별자 사용
  • 사용자 지정 식별자 사용

SDK 내부적으로 관리하는 디바이스 식별자 사용

클라이언트 측 SDK는 디바이스의 식별자를 관리하는 기능을 포함하고 있습니다. 따라서 사용자 식별자를 별도로 전달하지 않아도 사용자를 자동으로 식별할 수 있습니다.
JavaScript, Android, iOS의 경우 SDK가 관리하는 디바이스 식별자를 얻을 수 있으니 아래 예제 코드를 참고하시기 바랍니다.

// 테스트 그룹 분배
const experimentKey = 42
const variation = hackleClient.variation(experimentKey)

// 사용자 이벤트 전송
hackleClient.track("purchase")

// 내부적으로 관리되는 디바이스 식별자 가져오기
const userId = Hackle.getUserId()
// 테스트 그룹 분배
int experimentKey = 42;
Variation variation = hackleApp.variation(experimentKey);

// 사용자 이벤트 전송
hackleApp.track("purchase");

// 내부적으로 관리되는 디바이스 식별자 가져오기
String deviceId = hackleApp.getDeviceId();
// 테스트 그룹 분배
let variation = hackleApp.variation(experimentKey: 42)

// 사용자 이벤트 전송
hackleApp.track(eventKey: "purchase")

// 내부적으로 관리되는 디바이스 식별자 가져오기
let deviceId = hackleApp.deviceId
<HackleProvider hackleClient={hackleClient}>
  <YourApp />
</HackleProvider>

사용자 지정 식별자 사용

SDK는 파라미터를 통해 받은 식별자를 통해 사용자를 식별합니다. 전달하는 식별자는 직접 관리하는 Primary Key, 디바이스 식별자, 회원 아이디, 이메일, 해시값 등이 될 수 있습니다.

// 테스트 그룹 분배
const experimentKey = 42;
const user = { id: "ae2182e0" };
const variation = hackleClient.variation(experimentKey, user);

// 사용자 이벤트 전송
hackleClient.track("purchase", user);
// 테스트 그룹 분배
long experimentKey = 42L;
String userId = "ae2182e0";
Variation variation = hackleApp.variation(experimentKey, userId);

// 사용자 이벤트 전송
hackleApp.track("purchase", userId);
// 테스트 그룹 분배
let variation = hackleApp.variation(experimentKey: 42, userId: "ae2182e0")

// 사용자 이벤트 전송
hackleApp.track(eventKey: "purchase", userId: "ae2182e0")
const user = { 
    id: "ae2182e0"
}

<HackleProvider hackleClient={hackleClient} user={user}>
  <YourApp />
</HackleProvider>

서버 측 SDK

서버 측 SDK는 사용자를 특정할 수 없기 때문에 항상 사용자 지정 식별자를 파라미터로 전달해야 합니다.

// 테스트 그룹 분배
long experimentKey = 42L;
User user = User.of("ae2182e0");
Variation variation = hackleClient.variation(experimentKey, user);

// 사용자 이벤트 전송
hackleClient.track("purchase", user);
# 테스트 그룹 분배
uesr = Hackle.user('ae2182e0')
variation = hackle_client.variation(experiment_key=42, user=user)

# 사용자 이벤트 전송
event = Hackle.event(key='purchase')
hackle_client.track(event=event, user=user)
// 테스트 그룹 분배
const experimentKey = 42;
const user = { id: "ae2182e0" };
hackleClient.variation(experimentKey, user);

// 사용자 이벤트 전송
hackleClient.track("purchase", user);
// 테스트 그룹 분배
$experimentKey = 42;
$userId = 'ae2182e0'
$variation = $hackleClient->variation($experimentKey, $userId);

// 사용자 이벤트 전송
$hackleClient->track('purchase', $userId);
# 테스트 그룹 분배
user = Hackle.user(id: 'ae2182e0')
variation = hackle_client.variation(experiment_key: 42, user: user)

# 사용자 이벤트 전송
event = Hackle.event(key: 'purchase')
hackle_client.track(event: event, user: user)

예시: 사용자 지정 식별자 만들기

로그인 사용자만을 대상으로 데이터가 필요한 경우에는 로그인 시 사용하는 회원 아이디나 이메일 주소 등을 식별자로 사용할 수 있습니다.
그러나 비로그인 사용자를 포함할 경우에는 앱, 기기 혹은 브라우저를 기반으로 구분할 수 있는 값을 활용하는 것을 권장하고 있습니다. (모바일 앱의 경우에는 UUID 혹은 ADID 값을, PC/Mobile 웹의 경우에는 쿠키 값)

아래에 쿠키를 기반으로 사용자 식별자를 생성하는 예시를 소개합니다.

import Cookies from "js-cookie"
import uuid4 from "uuid4"
function getUserId() {
  const key = "PCID" // 원하는 이름을 입력
  const id = Cookies.get(key)
  if (id) {
    return id
  } else {
    const id = uuid4()
    const [top, second] = window.location.hostname.split(".").reverse()
    const domain = `.${second}.${top}`
    Cookies.set(key, id, { expires: 99999, domain: domain, path: "/" })
    return id
  }
}
const app = require("express")()
const bodyParser = require("body-parser")
const cookieParser = require("cookie-parser")
const {v4: uuidv4} = require("uuid")

app.use(bodyParser.urlencoded({extended: false}))
app.use(cookieParser())
app.set("view engine", "ejs")
app.set("views", "views")

function extractDomain(hostname) {
    const DOMAIN_MATCH_REGEX = /[a-z0-9][a-z0-9-]+\.[a-z.]{2,6}$/i;
    const SIMPLE_DOMAIN_MATCH_REGEX = /[a-z0-9][a-z0-9-]*\.[a-z]+$/i;
    let domain_regex = DOMAIN_MATCH_REGEX;
    const parts = hostname.split(".");
    const tld = parts[parts.length - 1];
    if (tld.length > 4 || tld === "com" || tld === "org") {
        domain_regex = SIMPLE_DOMAIN_MATCH_REGEX;
    }
    const matches = hostname.match(domain_regex);
    return matches ? matches[0] : "";
}

app.use((req, res, next) => {
    const domain = extractDomain(req.headers.host)

    if (!req.cookies.deviceId) {
        const deviceId = uuidv4()
        res.cookie("deviceId", deviceId, {
            maxAge: 365 * 10 * 365 * 24 * 60 * 60,
            domain: domain,
            path: "/"
        })
        req.cookies.deviceId = deviceId
    }
    next()
});

app.get("/", (req, res) => {
    console.log(req.cookies.deviceId)
    res.render("index")
});

app.listen(3000, () => {
    console.log("App Start")
});

클라이언트, 서버 간 식별자 맞추기

클라이언트, 서버 SDK 를 동시에 사용하는 경우 각 환경에서 동일한 유저에 대해서 동일한 식별자로 맞추어 하여 사용할 수 있습니다.

이러한 경우에는 클라이언트, 서버간 API 통신시에 아래와 같이 HTTP 헤더를 통해서 식별자를 전달하는 방식을 권장드립니다.

X-DEVICE-ID: a3017217-3d46-4d7e-8d88-a0a905709fe4

속성(Property)

핵클 SDK는 사용자(User) 객체에 속성을 추가할 수 있도록 지원합니다.
사용자 속성으로 사용자별 정보를 전송하면 반복적인 코드 작업을 줄이면서도 A/B테스트나 데이터 분석에서 다양하게 활용할 수 있습니다.

속성은 속성명(key)과 속성값(value)을 한 쌍으로 보내야 합니다.
사용자 객체에 추가 가능한 속성 개수는 최대 64개입니다.

속성명(key)

일반적인 변수명처럼 만들되 식별하기 쉽게 만드는 것을 권장합니다.
글자수 제한은 64자입니다. (64 characters)
대소문자를 구분하지 않습니다. 예를 들어 AGE와 age는 동일한 속성명으로 인식합니다.

속성값(value)

value는 boolean, string, number 타입을 지원합니다.
string 타입인 경우 글자수 제한은 64자입니다. (64 characters)
string 타입은 대소문자를 구분합니다. 예를 들어 APPLE과 apple은 서로 다른 속성값으로 인식합니다.
number 타입인 경우 정수 최대 15자리, 소수점 최대 6자리를 지원합니다.

예시

사용자(User) 객체는 테스트 그룹 분배, 기능 플래그 결정, 사용자 이벤트 전송에서 파라미터로 사용됩니다.
아래 예시에서는 세 가지 속성(age, grade, is_paying_user)을 추가한 것을 확인할 수 있습니다.

import io.hackle.android.HackleApp
import io.hackle.sdk.common.User
import io.hackle.sdk.common.Variation
  
User user = User.builder(userId)
    .property("age", 30)
    .property("grade", "GOLD")
    .property("is_paying_user", false)
    .build();
    
// 테스트 그룹 분배  
Variation variation = hackleApp.variation(experimentKey, user);

// 기능 플래그 결정
boolean featureOn = hackleApp.isFeatureOn(featureKey, user);

// 사용자 이벤트 전송
hackleApp.track(event, user);
import io.hackle.android.Hackle
import io.hackle.sdk.common.User
import io.hackle.sdk.common.Variation
  
val user = Hackle.user(userId) {
    property("age", 30)
    property("grade", "GOLD")
    property("is_paying_user", false)
}
    
// 테스트 그룹 분배
val variation = hackleApp.variation(experimentKey, user)

// 기능 플래그 결정
val featureOn = hackleApp.isFeatureOn(featureKey, user)

// 사용자 이벤트 전송
hackleApp.track(event, user)