Statsig 입문 2편. SDK Quickstart 의 4단계 (패키지 설치 → 초기화 → API key → 사용) 종합 실습. Node.js · Python · Java · JavaScript · React 언어별 초기화 코드, Client Key vs Server Secret 분기, 첫 Feature Gate · Dynamic Config · Experiment · logEvent 호출, StatsigUser 객체 설계, environment 옵션, custom IDs, 처음부터 잘 설계해야 하는 자리들까지 풀어쓴 학습 노트.
이 글은 Statsig 입문에서 운영까지 시리즈 2편이에요. 1편 에서 Statsig 가 뭘 해주는 플랫폼인가 큰 그림을 봤다면, 이번 2편은 실제로 코드에 박는 첫 30분 — SDK Quickstart (개발 환경에 라이브러리 붙이는 4단계 가이드)의 4단계예요.
이번 글의 목표
이 글을 끝까지 따라하면 Statsig 계정 → SDK 설치 → 첫 Feature Gate 분기 → 대시보드에서 ON/OFF 까지 end-to-end (앞단 코드부터 운영 대시보드까지 전 구간)가 됩니다.
목표는 30분 안에 첫 gate 박기. 코드 한 줄로 분기되는 기능 을 재배포 없이 대시보드에서 켜고 끄는 경험이에요.
처음 들으면 헷갈리는 자리
Quickstart 가 어렵게 느껴지는 자리가 두 군데예요.
첫째, Client Key 와 Server Secret 의 분기. 두 키가 역할이 다른데 처음엔 어느 코드에 어느 키 인지 헷갈려요.
둘째, 언어별 SDK 의 미묘한 차이. Node.js · Python · Java · React 가 같은 개념 이지만 API 명칭이 조금씩 다름. 공통 패턴 + 언어별 차이 둘 다 봐야 머리에 박혀요.
해결법은 4단계 한 그림 으로 잡는 것. 단계가 분명하면 어느 언어든 똑같이 풀려요.
Quickstart 4단계 — 큰 그림
| 단계 | 무엇 |
|---|---|
| 1. 패키지 설치 | npm/pip/maven 으로 SDK 추가 |
| 2. SDK 초기화 | 앱 시작 시 1회 initialize() |
| 3. API key 박기 | Client Key 또는 Server Secret |
| 4. 사용 | checkGate · getConfig · getExperiment · logEvent |
→ 모든 SDK 가 이 4단계. 언어별 차이는 문법 표면 만이에요.
지원 SDK 종류 — 어떤 걸로 시작할까
Statsig 공식 Quickstart 가 제공하는 SDK 큰 묶음이에요.
Client SDK (브라우저·모바일·데스크탑)
React · JavaScript · React Native · Next.js · Angular · Swift (iOS/macOS/tvOS) · Android · .NET Client · Flutter · Roku · Unity · C++ Client.
Server SDK (백엔드)
Node.js · Python · Java · Go · Ruby · PHP · Rust · .NET Core.
어디부터 — 우리 회사 stack 의 주력 언어 1개 부터예요. 대부분 환경을 보면 웹 SPA (Single Page Application, 페이지 전환 없이 도는 단일 페이지 앱)는 React 또는 JavaScript (브라우저), 백엔드 API 는 Node.js · Java · Python 중 하나, 모바일은 Swift (iOS) · Android (Kotlin) · Flutter (cross) 로 나뉘죠.
처음엔 한 SDK 만 박고 익숙해진 다음 다른 plat 추가하는 흐름이 안전해요.
단계 1: 패키지 설치
Node.js
npm install @statsig/js-server
# 또는
yarn add @statsig/js-server
Python
pip install statsig-python-core
Java (Gradle)
implementation 'com.statsig:javacore:LATEST_VERSION'
Java (Maven)
<dependency>
<groupId>com.statsig</groupId>
<artifactId>javacore</artifactId>
<version>LATEST_VERSION</version>
</dependency>
React
npm install @statsig/react-bindings
JavaScript (Snippet — 빌드 도구 없이)
<script> 한 줄로 CDN (Content Delivery Network, 정적 파일 배포 캐시 망) 에서 직접 로드 가능. 빌드 없는 정적 사이트·랜딩 페이지에 유용해요.
단계 2: SDK 초기화
여기가 언어별로 가장 차이 큰 자리. 패턴만 잡으면 다른 SDK 도 응용 가능해요.
Node.js (Server)
import Statsig from '@statsig/js-server';
const statsig = new Statsig("server-SECRET_KEY");
await statsig.initialize();
// 이제 사용 가능
initialize() 는 rule set 을 Statsig 서버에서 fetch 후 메모리 적재하는 일이에요. 앱 시작 시 1회 await 필수. 그 후 매 요청 평가 는 로컬 메모리 lookup 이라 빠르죠.
Python (Server)
from statsig_python_core import Statsig
options = {"environment": "production"}
statsig = Statsig("server-SECRET_KEY", options)
statsig.initialize().wait()
initialize().wait() 패턴은 비동기 초기화 + 완료 대기 의미. Node.js 의 await 와 동일해요.
React (Client)
import { StatsigProvider } from '@statsig/react-bindings';
function App() {
return (
<StatsigProvider
sdkKey="client-PUBLIC_KEY"
user={{ userID: "user-id" }}
loadingComponent={<div>Loading...</div>}
>
<YourApp />
</StatsigProvider>
);
}
StatsigProvider 가 React Context 로 SDK 주입. 최상위에 한 번 만 wrap 하면 돼요.
loadingComponent = SDK 초기화 중 (network round-trip) 표시할 UI. 잠깐의 blank 상태 회피용이에요.
JavaScript (Snippet)
<script src="https://cdn.jsdelivr.net/npm/@statsig/js-client@3/build/statsig-js-client.min.js?apikey=client-KEY"></script>
<script>
// initialize 후 사용
</script>
빌드 도구 없는 환경에서 CDN 한 줄 + URL query 의 apikey 로 키 전달이에요.
여기서 시험 함정이 하나 있어요 — CDN snippet 방식은 client key 가 URL 에 박힘 = 누구나 볼 수 있어요. 그래서 Client Key 는 반드시 공개 안전한 키 여야 해요. Server Secret 을 절대 client 측에 두지 말 것.
단계 3: API key — Client Key vs Server Secret
여기서 정말 중요한 시험 함정 — 두 키의 의미가 다름.
| 항목 | Client Key | Server Secret |
|---|---|---|
| 공개 가능? | ✓ (브라우저·모바일 코드에 박힘) | ✗ (절대 외부 노출 X) |
| prefix | client- |
secret- 또는 server- |
| 사용 위치 | React · JS · Swift · Android | Node.js · Python · Java · Go |
| 권한 | read-only · 평가만 | 평가 + event 로깅 + 운영 |
| rotation | 정기 교체 권장 | 유출 시 즉시 rotation |
키 발급 위치
Statsig console → Project Settings → API Keys. 거기서 Client Key 와 Server Secret 별도로 생성해요.
환경 분리
대부분 환경은 Development · Staging · Production 별로 각각 키 발급. 키 prefix 또는 metadata 에서 환경 구분하는 식이에요.
권장 패턴:
// 환경 변수로 분리
const sdkKey = process.env.STATSIG_SERVER_KEY;
const statsig = new Statsig(sdkKey);
코드에 키 하드코딩 금지. env 변수 + secrets manager (AWS Secrets · GCP Secret · Vault) 같은 키 보관소를 써요.
Server Secret 유출 = 즉시 rotation
만약 git push 또는 log 로 Server Secret 노출 됐다면 즉시 rotation + 노출 기간 동안 비정상 activity 점검. Public repo 에 commit 했으면 git history 도 정리 (Bitwarden 같은 secrets scanner 활용).
단계 4: 사용 — Gate · Config · Experiment · Event
Feature Gate 체크
// Node.js
const user = { userID: "user-123", email: "user@example.com" };
const showFeature = statsig.checkGate(user, "show_new_checkout");
if (showFeature) {
// 새 결제 흐름
} else {
// 기존 결제 흐름
}
# Python
from statsig_python_core import StatsigUser
user = StatsigUser(user_id="user-123", email="user@example.com")
show_feature = statsig.check_gate(user, "show_new_checkout")
// React (hook 활용)
import { useGate } from '@statsig/react-bindings';
function CheckoutPage() {
const { value: showFeature } = useGate("show_new_checkout");
return showFeature ? <NewCheckout /> : <OldCheckout />;
}
checkGate(user, gateName) 의 두 인자 — 사용자 객체 + gate (특정 기능을 켜고 끄는 분기 스위치) 이름. 반환은 boolean 이에요.
Dynamic Config 가져오기
// Node.js
const config = statsig.getConfig(user, "checkout_settings");
const minOrderValue = config.get("min_order_value", 50); // default 50
const freeShippingFrom = config.get("free_shipping_from", 100);
get(key, defaultValue) — config 에 해당 key 가 없으면 default 반환. production 안전 기본값 필수예요.
Experiment 평가
// Node.js
const experiment = statsig.getExperiment(user, "button_color_test");
const buttonColor = experiment.get("color", "blue");
Dynamic Config 와 거의 동일한 API. 통계적 추적 이 자동으로 백엔드에 기록되는 게 차이예요.
Event 로깅
// Node.js
statsig.logEvent(user, "checkout_completed", "1500", {
currency: "KRW",
items_count: 3,
payment_method: "card"
});
logEvent(user, eventName, value?, metadata?) 의 4 인자는 eventName 이벤트 이름, value 숫자 또는 문자열 (예: 결제 금액), metadata 추가 속성 (object) 으로 나뉘어요.
이 event 가 Product Analytics 의 funnel (구매 전환 단계별 이탈 추적) · retention (재방문 유지율) · cohort (가입 시점 단위 묶음) 에 자동 반영. 1편의 6 차트가 여기서 박은 event 로 만들어져요.
가장 단순한 첫 gate end-to-end
// 1. SDK 초기화 (app start)
const statsig = new Statsig(process.env.STATSIG_SERVER_KEY);
await statsig.initialize();
// 2. 매 요청에서 gate 체크
app.get('/checkout', (req, res) => {
const user = { userID: req.user.id };
const useNewFlow = statsig.checkGate(user, "new_checkout_flow");
if (useNewFlow) {
return res.render('checkout-v2');
}
return res.render('checkout-v1');
});
// 3. 결제 완료 event 로깅
app.post('/checkout/complete', (req, res) => {
const user = { userID: req.user.id };
statsig.logEvent(user, "checkout_completed", req.body.amount);
// ...
});
이게 minimal end-to-end. Statsig console 의 Feature Gates → Create Gate → "new_checkout_flow" 으로 gate 생성 후 10% rollout (전체 사용자 중 일부에게만 단계적 노출) 설정하면 코드 한 줄도 안 바꾸고 10% 사용자만 새 flow 노출돼요.
StatsigUser 객체 설계 — 처음부터 잘 잡아야 하는 자리
StatsigUser (또는 user object) 가 Statsig 의 모든 평가의 기준. user ID 설계 가 운영의 처음이자 끝이에요.
표준 필드
const user = {
userID: "stable-user-123", // 로그인 사용자 ID (가장 중요)
email: "user@example.com",
ip: "1.2.3.4",
country: "KR",
locale: "ko-KR",
appVersion: "1.5.0",
userAgent: "...",
custom: {
tier: "premium", // 비즈니스 속성
signupDate: "2024-01-01",
company: "acme-corp"
}
};
Custom IDs — Multi-tenant 환경
const user = {
userID: "user-123",
customIDs: {
"companyID": "company-456",
"deviceID": "device-789",
"sessionID": "session-abc"
}
};
Custom IDs 가 강력한 이유 — 일반 userID 와 독립적으로 무작위화 가능. 예: B2B SaaS (Business-to-Business, 기업 대상 소프트웨어 서비스) 가 company 단위 로 실험하는 식이에요.
여기서 시험 함정이 하나 있어요 — userID 만으로 실험하면 같은 회사의 사용자 A, B 가 다른 variant (실험에서 사용자에게 노출되는 분기 갈래) 일 수 있어요. B2B 는 customIDs.companyID 로 무작위화 가 일반적이에요.
Anonymous User (로그인 전)
const user = {
userID: undefined, // 로그인 전
customIDs: {
"deviceID": getOrCreateDeviceID() // 디바이스 단위
}
};
로그인 전 사용자도 experiment 에 포함 가능. device 단위 무작위화 후 로그인 시점에 userID 추가하면 돼요.
user object 의 일관성
같은 사용자 = 모든 SDK 가 같은 user 정보 보내야 함. Server SDK 에서 user.email 박았는데 Client SDK 에서 안 박으면 → 두 SDK 의 평가 결과 다를 수 있어요 (rule 이 email 기반인 경우).
→ user object 의 구성 코드 를 유틸 함수로 추출 하는 게 안전해요.
SDK 초기화 옵션 — 자주 쓰는 자리
environment
options = {"environment": "production"} # 또는 "staging" · "development"
statsig = Statsig(SDK_KEY, options)
같은 코드 + 다른 환경 키 로 운영. 환경별 *gate · experiment * 분리돼요.
timeout · network 옵션
const options = {
initTimeoutMs: 3000, // initialize timeout
syncInterval: 60_000, // rule sync 주기 (ms)
};
const statsig = new Statsig(SDK_KEY, options);
initTimeoutMs — Statsig 서버 응답 3초 초과 시 fallback (default value 로 동작). 운영 안전선이에요.
bootstrap (React · Next.js SSR)
// Server-side rendering 환경
<StatsigProvider
sdkKey="client-key"
user={user}
bootstrapValues={prefetchedValuesFromServer} // 서버에서 미리 가져온 값
>
초기 깜빡임 (flicker) 회피 — 서버에서 evaluated values 미리 가져온 후 client SDK 에 주입. SSR (Server-Side Rendering, 서버에서 HTML 미리 그려 보내는 방식) · Next.js 표준 패턴이에요.
자주 만나는 사고 — 30분 첫 통합
사고 1: initialize() 못 기다림
원인 — await 누락 → SDK 초기화 전 checkGate 호출.
해결 — Node.js await statsig.initialize(); · Python .initialize().wait(). 초기화 전 모든 호출 = default 값.
사고 2: Client 에 Server Secret 박음
원인 — React 앱 에 secret-... key 사용 → 누구나 브라우저 DevTools 에서 볼 수 있음.
해결 — Client = client-... key 만. immediate rotation if 유출.
사고 3: user.userID 가 동적
원인 — 매 요청마다 다른 userID (예: UUID 매번 생성).
해결 — stable user ID (DB 의 user.id). anonymous 는 deviceID 로.
사고 4: Event name 오타
원인 — "checkoutCompleted" 와 "checkout_completed" 가 혼용 → analytics 에서 두 event 로 갈림.
해결 — event name 상수화 (const EVENT_CHECKOUT_COMPLETED = "checkout_completed";) + naming convention 정의.
사고 5: Initialize timeout
원인 — Statsig 서버 응답 지연 → initTimeoutMs 초과 → SDK 가 default value 모드.
해결 — initTimeoutMs 늘림 (5000ms 등) + fallback 시 안전한 default 보장.
사고 6: React 의 SSR flicker
원인 — server-side render = gate OFF, client mount 후 = gate ON → 깜빡임.
해결 — bootstrapValues 또는 서버에서 evaluated values 주입.
사고 7: Custom 필드 type 불일치
원인 — user.custom.signupDate 가 어떤 곳은 string, 어떤 곳은 Date 객체.
해결 — team-wide user schema 정의 (TypeScript interface · Python dataclass).
운영 권장 패턴 — 처음부터 잘 잡기
Pattern 1: User factory 함수
// utils/statsig-user.js
export function buildStatsigUser(req) {
return {
userID: req.user?.id,
email: req.user?.email,
ip: req.ip,
country: req.headers['cf-ipcountry'],
customIDs: {
"companyID": req.user?.companyId,
"deviceID": req.cookies.deviceId
},
custom: {
tier: req.user?.tier,
signupDate: req.user?.createdAt
}
};
}
// 사용
const user = buildStatsigUser(req);
const showFeature = statsig.checkGate(user, "...");
모든 호출이 같은 user object 사용. 일관성이 보장돼요.
Pattern 2: 환경별 SDK key
# application.yml
statsig:
server-key: ${STATSIG_SERVER_KEY}
environment: ${SPRING_PROFILES_ACTIVE:production}
// Spring Boot
@Value("${statsig.server-key}") private String sdkKey;
@Value("${statsig.environment}") private String environment;
@Bean
public Statsig statsig() {
StatsigOptions options = StatsigOptions.builder()
.environment(environment)
.build();
Statsig statsig = new Statsig(sdkKey, options);
statsig.initialize();
return statsig;
}
profile 별 자동 분리 — local/dev/prod.
Pattern 3: Event 표준 정의
// types/events.ts
export const STATSIG_EVENTS = {
CHECKOUT_STARTED: "checkout_started",
CHECKOUT_COMPLETED: "checkout_completed",
ITEM_VIEWED: "item_viewed",
// ...
} as const;
export type EventName = typeof STATSIG_EVENTS[keyof typeof STATSIG_EVENTS];
TypeScript 의 as const + union type = event name 오타 컴파일 타임 검출.
Pattern 4: Server + Client 동시 사용
[브라우저] [Server]
React Client SDK Node.js Server SDK
↓ ↓
client-PUBLIC_KEY server-SECRET_KEY
↓ ↓
같은 user.userID 사용 → 같은 variant 결정
같은 user ID 면 Statsig 의 deterministic hashing (같은 입력은 항상 같은 분기로 가는 해시) 으로 모든 SDK 가 같은 variant. UI 일관 + 서버 측 metric 정확하게 나와요.
Pattern 5: Bootstrap (Next.js SSR)
// app/page.tsx (server component)
import { headers } from 'next/headers';
async function getStatsigBootstrap(user) {
// Server SDK 로 evaluated values 가져오기
return await serverStatsig.getClientInitializeResponse(user);
}
export default async function Page() {
const user = { userID: getCurrentUserId() };
const bootstrapValues = await getStatsigBootstrap(user);
return (
<StatsigProvider sdkKey="client-..." user={user} bootstrapValues={bootstrapValues}>
<App />
</StatsigProvider>
);
}
서버에서 미리 평가 → client 에 inject → flicker 없는 SSR.
시험 직전 한 번 더 — SDK Quickstart 함정 압축 노트
- Quickstart 4 단계 = 패키지 설치 → SDK 초기화 → API key → 사용
- 지원 SDK 약 22종 (Client + Server)
- 시작 권장 = 주력 언어 1개 부터, 익숙해진 다음 plat 추가
- 단계 1 패키지 설치 — npm · pip · maven · gradle
- 단계 2 SDK 초기화 = 앱 시작 시 1회
initialize() - Node.js =
await statsig.initialize() - Python =
statsig.initialize().wait() - Java =
Statsig.initialize()(builder 옵션 활용) - React =
<StatsigProvider sdkKey user loadingComponent> - JS Snippet = CDN script + URL query apikey
- rule set 메모리 적재 = 초기화의 의미, 매 요청 = 로컬 lookup (빠름)
- 단계 3 API key = Client Key (
client-) vs Server Secret (secret-/server-) - Client Key = 공개 안전, brower/mobile 에 박힘
- Server Secret = 절대 외부 X, 유출 시 즉시 rotation
- 환경별 (Dev/Staging/Prod) 별도 key
- 코드 하드코딩 X, env var + secrets manager
- 단계 4 사용 =
checkGate·getConfig·getExperiment·logEvent checkGate(user, gateName)→ booleangetConfig(user, name)→ config object,.get(key, default)로 값getExperiment(user, name)→ 같은 패턴 + 통계 자동 추적logEvent(user, name, value, metadata)→ Product Analytics 의 데이터 원천- StatsigUser 표준 필드 = userID · email · ip · country · locale · appVersion · userAgent · custom
- customIDs = multi-tenant 환경의 무작위화 단위 (companyID · deviceID · sessionID)
- B2B = customIDs.companyID 로 무작위화 (B2C 는 userID)
- Anonymous user = userID undefined + deviceID
- user object 일관성 — Server·Client·iOS·Android 모두 같은 user 필드
- user factory 함수 권장 (utils/statsig-user.js)
- environment 옵션 = production · staging · development
- initTimeoutMs = 초기화 timeout (운영 안전선)
- syncInterval = rule sync 주기
- bootstrapValues (React/Next.js SSR) = flicker 회피
- 함정 — initialize await 누락 → default 값 모드
- 함정 — Client 에 Server Secret = 즉시 유출
- 함정 — user.userID 가 동적 (UUID 매번) → 같은 사용자도 다른 variant
- 함정 — Event name 오타 (
checkoutCompletedvscheckout_completed) → 두 event 갈림 - 함정 — initialize timeout → fallback default 값
- 함정 — React SSR flicker → bootstrapValues
- 함정 — custom 필드 type 불일치 → user schema 정의
- 패턴 — user factory 함수
- 패턴 — 환경별 SDK key (env var · profile)
- 패턴 — event name 상수 + TypeScript
as const - 패턴 — Server + Client 동시 사용 (deterministic hashing)
- 패턴 — Next.js SSR bootstrap
- 결과 — 코드 한 번 + 대시보드에서 ON/OFF · rollout · A/B
공식 문서: Statsig SDK Quickstart 에서 원문을 확인할 수 있어요.
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
다음 글: