@reopt-ai/data-sdk
v0.2.3
Published
DEPRECATED — use @reopt-ai/data-sdk-client (browser/React/Next) and @reopt-ai/data-sdk-server (server components, route handlers, proxy, Node). reopt-data analytics SDK
Readme
@reopt-ai/data-sdk
폐기 예정(deprecated). 이 패키지는 두 개로 나뉘었습니다.
| 쓰던 것 | 바꿀 것 | | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | |
@reopt-ai/data-sdk(브라우저) |@reopt-ai/data-sdk-client—init/track/identify/pageView동일 | |@reopt-ai/data-sdk/react|@reopt-ai/data-sdk-client/react—ReoptProvider와 훅 동일,autoPageViewprop 제거 | |@reopt-ai/data-sdk/nextjs|@reopt-ai/data-sdk-client/next—ReoptProvider+<ReoptPageView />+<ReoptWebVitals />(usePathnameprop 불필요) | |@reopt-ai/data-sdk/node|@reopt-ai/data-sdk-server/node—apiUrl→baseUrl,batchSize/flushInterval→batch: { size, intervalMs }|새 패키지는 device id를 쿠키에 두고(Safari ITP에서 localStorage는 7일이면 사라짐), 서버 컴포넌트·라우트 핸들러·Next
proxy.ts용 API를 제공하며, 클라이언트 번들에 서버 패키지가 섞이면 빌드에서 실패합니다. 이 패키지의 기존 localStorage device id는 새 클라이언트가 첫 로드에서 자동으로 이어받습니다.0.2.x는 동작 호환 릴리스입니다(내부 엔진만
data-sdk-core로 교체). 두 마이너 뒤 제거됩니다.
reopt-data 분석 플랫폼용 클라이언트 SDK입니다.
설치
npm install @reopt-ai/data-sdk
# 또는
pnpm add @reopt-ai/data-sdk사용법
브라우저 (바닐라 JavaScript/TypeScript)
import { init, track, identify, pageView, enableAutoPageView, close } from "@reopt-ai/data-sdk";
// 초기화
init({
writeKey: "your-write-key",
baseUrl: "https://data.reopt.app", // 필수 — reopt-data 오리진
debug: true, // 선택사항, 디버그 로그 활성화
// deviceId: "anonymous-device-id", // 선택사항, 미지정 시 SDK가 생성/저장
});
// 이벤트 트래킹
const queued = track("button_click", { buttonId: "signup", location: "header" });
console.log(queued.eventId, queued.queued);
// 객체 형태로도 가능
track({
name: "purchase",
properties: { product: "Pro Plan", price: 99 },
profileId: "user-123", // 선택사항
});
// 사용자 식별
identify({
profileId: "user-123",
email: "[email protected]",
firstName: "John",
properties: { plan: "pro" },
});
// 페이지뷰 트래킹
pageView();
pageView({ path: "/custom-path", title: "Custom Title" });
// 자동 페이지뷰 (SPA에서 라우트 변경 감지)
const cleanup = enableAutoPageView();
// cleanup() 호출로 비활성화
// 테스트, micro frontend teardown 등에서 명시 정리
await close();React
import { ReoptProvider, useTrack, useIdentify, useReopt, useTrackOnMount } from "@reopt-ai/data-sdk/react";
// 1. Provider로 앱 감싸기
function App() {
return (
<ReoptProvider
config={{
writeKey: "your-write-key",
}}
autoPageView={true} // 자동 페이지뷰 트래킹
>
<MyApp />
</ReoptProvider>
);
}
// 2. Hook 사용
function SignupButton() {
const track = useTrack();
return <button onClick={() => track("signup_clicked", { source: "landing" })}>Sign Up</button>;
}
// 3. 사용자 식별
function LoginHandler() {
const identify = useIdentify();
const handleLogin = (user) => {
identify(user.id, { name: user.name, email: user.email });
};
return <button onClick={handleLogin}>Login</button>;
}
// 4. 마운트 시 트래킹
function ProductPage({ productId }) {
useTrackOnMount("product_viewed", { productId });
return <div>Product Details</div>;
}
// 5. 전체 API 접근
function AdvancedComponent() {
const { track, identify, pageView, reset, flush } = useReopt();
// ...
}Node.js (서버사이드)
import { Reopt, createReopt } from "@reopt-ai/data-sdk/node";
// 클래스 인스턴스 생성
const reopt = new Reopt({
clientId: "your-client-id",
clientSecret: "your-client-secret",
baseUrl: "https://data.reopt.app",
});
// 또는 팩토리 함수 사용
const reopt = createReopt({ clientId: "...", clientSecret: "..." });
// 이벤트 트래킹
reopt.track("server_event", { action: "api_call", endpoint: "/users" });
await reopt.flush();
// 서버리스/route handler에서는 한 번에 큐잉+전송 보장
const delivery = await reopt.trackAndFlush("checkout_completed", { orderId: "order-456" });
console.log(delivery.queue.eventId, delivery.flush?.status);
// 프로필 ID 설정 (이후 트래킹에 자동 포함)
reopt.setProfileId("user-123");
reopt.track("order_created", { orderId: "order-456" });
// 사용자 식별
reopt.identify("user-123", { name: "John", tier: "enterprise" });
// 프로퍼티 증가/감소
reopt.increment("user-123", "login_count");
reopt.decrement("user-123", "credits", 10);
// 큐에 쌓인 이벤트 즉시 전송
const result = await reopt.flush();
console.log(result.sent, result.pending);
// 정리
await reopt.close();API Reference
설정 옵션
| 옵션 | 타입 | 필수 | 설명 |
| ------------------- | --------- | --------------------- | ----------------------------------------------------------------------------- |
| writeKey | string | 브라우저/React에서 ✅ | 브라우저 안전 수집 키 |
| clientId | string | 서버에서 ✅ | 프로젝트 서버 클라이언트 ID |
| clientSecret | string | 서버에서 ✅ | 프로젝트 서버 시크릿 |
| baseUrl | string | ✅ | reopt-data 오리진. SDK가 경로를 붙인다 (apiUrl은 같은 값의 deprecated 표기) |
| debug | boolean | ❌ | 디버그 모드 활성화 |
| deviceId | string | ❌ | 익명 디바이스 ID 직접 지정 |
| autoFlushOnUnload | boolean | ❌ | 브라우저 종료/숨김 시 keepalive flush |
| storagePrefix | string | ❌ | 로컬 저장 키 prefix (기본값: reopt_) |
브라우저/React/Next.js 통합에는 writeKey만 사용하고, clientSecret은 서버 환경에서만 사용해야 합니다.
baseUrl은 필수이며 기본값이 없습니다. init()이 즉시 throw합니다.
기본 엔드포인트를 두면 설정을 빠뜨린 통합이 정상 동작처럼 보입니다 — SDK는 성공을 보고하고 이벤트는 아무 데도 가지 않으며, 빈 대시보드를 누군가 알아챌 때까지 아무것도 드러나지 않습니다. 초기화 시점에 실패하는 편이 고치기 가장 쌉니다.
baseUrl은 @reopt-ai/data-contract의 createDataClient({ baseUrl })과 같은 의미입니다. 끝 슬래시는 무시됩니다.
SDK가 자동으로 붙이는 메타데이터
eventId: 클라이언트에서 생성하는 UUID입니다. 서버의 raw event deduplication 키로 사용됩니다.timestamp: 클라이언트 이벤트 생성 시각입니다. 서버는 별도로 수신 시각도 저장합니다.reopt-device-id: 익명 디바이스 ID 헤더입니다. 브라우저에서는 기본적으로localStorage에 저장됩니다.
track, identify, increment, decrement, pageView, screenView는 { eventId, queued, reason?, errors? } 형태의 QueueResult를 반환합니다. flush()는 { status, sent, failed, pending } 형태의 FlushResult를 반환합니다.
flush()는 track 응답의 accepted + duplicates + rejected.length를 제출한 배치 크기와 대조합니다.
sent는 accepted와 duplicate, failed는 서버가 명시적으로 거부한 행 수입니다. 계약 버전이나 응답 합계가
맞지 않으면 배치를 성공으로 지우지 않고 pending에 보존합니다.
Node.js 서버 SDK는 서버리스 환경을 위해 trackAndFlush, identifyAndFlush, incrementAndFlush, decrementAndFlush를 제공합니다. 이 메서드들은 { queue, flush } 형태의 DeliveryResult를 반환하며, 큐잉이 실패한 경우 flush는 null입니다. close()는 pending timer/listener를 정리하고 큐에 남은 이벤트를 전송합니다.
직접 HTTP로 POST /api/track를 호출하는 경우에도 SDK와 같은 @reopt-ai/data-contract(track) 계약을 따라야 합니다. track, identify, increment, decrement 이벤트에는 eventId UUID와 millisecond timestamp가 필수입니다.
프로덕션 통합 패턴
Browser / SPA
- 앱 shell에서 한 번만
init()합니다. - SPA 라우팅에서는
enableAutoPageView()또는 React Provider의autoPageView를 사용합니다. - 테스트, Storybook, micro frontend teardown처럼 SDK 인스턴스 수명이 짧은 환경에서는
await close()를 호출합니다. init()을 다시 호출하면 이전 singleton은 자동으로close()되어 listener와 pending flush가 정리됩니다.localStorage가 막힌 브라우저에서도 수집은 시도하지만, device ID와 offline queue 영속성은 보장되지 않습니다.
React / Next.js
- Client Component에서
ReoptProvider로 앱을 감쌉니다. - Provider가 unmount되면 SDK는 남은 큐를 flush하고 page lifecycle listener를 정리합니다.
- 로그인 직후
useIdentify()로profileId를 설정하면 이후track()이벤트에 같은 프로필이 붙습니다. - 로그아웃 시에는
reset()으로 현재 프로필 ID와 pending queue를 비웁니다.
Node.js / Serverless
- 서버리스 route handler, webhook, cron job에서는
trackAndFlush계열을 우선 사용합니다. track()만 호출하고 요청을 종료하면 런타임이 scheduled flush를 끝까지 보장하지 않을 수 있습니다.- 긴 수명의 서버나 worker에서는 인스턴스를 재사용하고, 종료 시
await close()로 drain합니다. flush()와close()는 큐가 빌 때까지 drain을 시도합니다.
const delivery = await reopt.trackAndFlush("invoice_paid", { invoiceId });
if (!delivery.queue.queued) {
console.warn("event was not queued", delivery.queue.reason, delivery.queue.errors);
} else if (delivery.flush?.status !== "success") {
console.warn("event is still pending", delivery.flush?.pending);
}메서드
track(name, properties?)
커스텀 이벤트를 트래킹합니다.
identify(profileId, properties?)
사용자를 식별하고 프로필 속성을 설정합니다.
pageView(options?)
페이지뷰를 트래킹합니다. 자동으로 path, title, referrer를 캡처합니다.
screenView(screenName, properties?)
모바일/앱 화면 뷰를 트래킹합니다.
setProfileId(profileId)
이후 이벤트에 자동으로 포함될 프로필 ID를 설정합니다.
reset()
프로필 ID와 큐를 초기화합니다 (로그아웃 시 사용).
flush()
큐에 쌓인 이벤트를 즉시 서버로 전송합니다.
close()
큐에 남은 이벤트를 전송하고 SDK 리소스를 정리합니다. Node.js 서버 SDK와 브라우저 singleton API에서 사용할 수 있습니다.
React Hooks
| Hook | 설명 |
| ------------------------------------ | ---------------------------------- |
| useReopt() | 전체 SDK API 접근 |
| useTrack() | track 함수 반환 |
| useIdentify() | identify 함수 반환 |
| usePageView() | pageView 함수 반환 |
| useTrackOnMount(name, properties?) | 컴포넌트 마운트 시 이벤트 트래킹 |
| usePageViewOnMount(options?) | 컴포넌트 마운트 시 페이지뷰 트래킹 |
동의(Consent) 관리
이벤트를 카테고리별 동의 상태로 게이팅할 수 있습니다. 카테고리는 analytics, marketing, functional, performance입니다.
init({
writeKey: "...",
consent: {
categories: ["analytics", "marketing"],
defaultConsent: false, // 동의 전까지 수집하지 않음
},
});
// 마케팅 동의만 부여
setConsent("marketing", true);
// consentCategory로 이벤트를 분류 (미지정 시 기본값은 "analytics")
track("page_view", { plan: "pro" }); // 기본 analytics → analytics 미동의면 차단
track({ name: "promo_click", consentCategory: "marketing" }); // marketing 동의 → 전송
setAllConsent(false); // 전체 철회- 카테고리 검사는 enqueue 시점에 이뤄지며, 카테고리 자체는 서버로 전송되지 않습니다(클라이언트 측 게이트).
- 이미 큐에 들어간 이벤트는 동의 시점 기준으로 수집된 것이므로, 이후 다른 카테고리를 철회해도 전송됩니다.
setAllConsent(false)처럼 모든 카테고리가 거부된 전면 opt-out 상태가 되면 flush가 중단됩니다. consentCategory는track,identify,increment,decrement,pageView에서 지정할 수 있습니다.
SDK 제공 이벤트 이름
다음 이름은 SDK 메서드가 생성합니다:
$pageview- 페이지뷰$screen_view- 화면 뷰
이벤트 배치 처리
SDK는 성능 최적화를 위해 이벤트를 배치로 처리합니다:
- 이벤트는 큐에 쌓였다가 1초마다 자동 전송됩니다
flush()를 호출하면 즉시 전송됩니다- 브라우저에서는 페이지 언로드/숨김 시
keepalive로 자동 flush됩니다 - 일시적 실패(네트워크 오류·5xx·429)는 지수 백오프로 재시도하고, 영구 거부(그 외 4xx)는 해당 배치를 폐기해 후속 이벤트 전송을 막지 않습니다
- 오프라인 버퍼가 켜져 있으면 큐를 저장소에 보존하며, 페이지 언로드 시점에는 디바운스 없이 즉시 저장합니다
라이선스
MIT
