빠른 연동
프로젝트 생성 후 브라우저와 서버리스 route handler에 첫 이벤트를 붙이고, 수집 성공을 확인합니다.
리옵트 데이터를 처음 붙이는 개발자를 위한 가이드입니다. 브라우저 이벤트 하나와 서버리스 이벤트 하나를 보내고, 프로젝트 화면에서 수집 결과를 확인합니다.
시작하기 전에
다음 네 가지를 준비하세요.
| 준비물 | 확인하는 곳 |
|---|---|
| 조직 | /dashboard에서 만들거나 선택합니다. |
| 프로젝트 | /dashboard의 새 프로젝트에서 만듭니다. 조직의 owner 또는 admin이어야 합니다. |
브라우저용 writeKey | 프로젝트 홈의 SDK Integration snippet에서 확인합니다. |
서버용 clientId, serverSecret | 콘솔에서 프로젝트를 만든 직후의 창에 한 번 표시됩니다. CLI로 만들면 reopt-data project create 응답의 clients.server.id와 clientSecret입니다. |
콘솔에서 프로젝트를 만들면 생성 직후 창에 Write Key, 서버 Client ID, 서버 Client Secret이 표시됩니다. 서버 Client Secret은 창을 닫으면 다시 볼 수 없으니 먼저 복사해 두세요. 키 발급의 자세한 내용은 조직과 프로젝트에 있습니다.
serverSecret은 서버 전용 비밀값입니다.
브라우저 번들, HTML, client component, 공개 저장소에는 넣지 마세요.
SDK 옵션과 환경변수 예시에서는 같은 값을 clientSecret이라는 이름으로 넣습니다.
조직에 수집 가능한 데이터 포인트도 있어야 합니다.
콘솔에서 만든 조직은 Free로 시작하며, Starter나 Pro를 구독한 뒤부터 이벤트를 수집합니다. 구독하지 않은 조직, 한도를 다 쓴 조직, 할당량이 0인 조직(데모 워크스페이스 포함)은 이벤트를 보내도 429 quota_exceeded로 거절됩니다. 비용과 보존 정책에서 플랜을 확인하세요.
1. 패키지 설치하기
pnpm add @reopt-ai/data-sdk-client @reopt-ai/data-sdk-server브라우저 코드와 서버 코드를 섞지 않도록 패키지를 둘로 나눴습니다.
브라우저에서 도는 코드는 -client를, 서버에서 도는 코드는 -server를 import합니다.
-server는 server-only를 import하므로, 실수로 client component에서 가져다 쓰면 런타임이 아니라 빌드 단계에서 실패합니다. 그래서 clientSecret이 브라우저 번들에 실려 나가지 않습니다.
브라우저만 붙일 계획이라면 -client 하나로 충분합니다.
모노레포 안에서 특정 앱에만 설치한다면 해당 앱 디렉터리에서 실행하세요.
| 패키지 | 진입점 | 함께 필요한 것 |
|---|---|---|
@reopt-ai/data-sdk-client | .(프레임워크 없음), ./react, ./next | ./react는 React 18 이상, ./next는 Next.js 14 이상 |
@reopt-ai/data-sdk-server | .(Next.js 요청 스코프), ./proxy, ./node(워커·크론), ./ai(AI 텔레메트리) | 요청 스코프와 proxy는 Next.js 15 이상 |
2. 환경변수 추가하기
브라우저에서 쓰는 값은 공개 환경변수로 둡니다. 서버에서 쓰는 값은 공개 prefix 없이 둡니다.
# Browser
NEXT_PUBLIC_REOPT_WRITE_KEY="wpk_..."
NEXT_PUBLIC_REOPT_API_URL="https://data.reopt.ai"
# Server
REOPT_CLIENT_ID="<서버용 client ID>"
REOPT_CLIENT_SECRET="sec_..."
REOPT_BASE_URL="https://data.reopt.ai"writeKey는 서버 쪽에도 필요합니다.
인증에는 쓰지 않습니다. 인증은 clientId/clientSecret이 맡고, 이 값은 어느 쿠키를 읽을지를 정합니다.
그래서 한 도메인에 두 프로젝트를 붙여도 서로의 방문자를 덮어쓰지 않습니다.
baseUrl에는 기본값이 없습니다. 브라우저 SDK는 writeKey나 baseUrl이 비어 있으면 경고를 남기고 아무것도 보내지 않습니다.
3. 브라우저 이벤트 보내기
앱의 클라이언트 진입점에서 SDK를 초기화합니다.
초기화 뒤에는 track, identify, pageView를 쓸 수 있습니다.
import { init, identify, track } from "@reopt-ai/data-sdk-client";
init({
writeKey: process.env.NEXT_PUBLIC_REOPT_WRITE_KEY!,
baseUrl: process.env.NEXT_PUBLIC_REOPT_API_URL!,
debug: true,
});
track("signup_clicked", {
location: "header",
plan: "starter",
});
identify("user_123", {
plan: "starter",
});init()은 첫 $pageview를 직접 보냅니다. 여기서 pageView()를 한 번 더 부르면 같은 페이지가 두 번 세어집니다.
pageView()는 SPA에서 화면이 바뀔 때 호출하세요. Next.js App Router라면 추적 설정의 ReoptPageView가 이동마다 대신 보냅니다.
debug: true는 로컬과 미리보기 환경에서 큐와 전송 상태를 확인할 때만 사용하세요.
운영 환경에서는 불필요한 로그가 남지 않도록 끄는 것이 좋습니다.
4. Next.js route handler에서 서버 이벤트 보내기
Next.js 안에서는 요청 스코프 클라이언트를 씁니다.
track()만 부르면 응답 뒤의 전송은 SDK가 처리합니다.
먼저 요청 스코프 클라이언트를 모듈 스코프에서 한 번만 만들어 둡니다. 요청마다 다시 만들면 배칭과 세션 조회 캐시를 모두 잃습니다.
// lib/reopt.ts
import "server-only";
import { createReopt } from "@reopt-ai/data-sdk-server";
export const { getReopt, getBootstrap } = createReopt({
clientId: process.env.REOPT_CLIENT_ID!,
clientSecret: process.env.REOPT_CLIENT_SECRET!,
// 쿠키 이름을 유도하는 값. 브라우저에서 쓰는 것과 반드시 같아야 합니다
writeKey: process.env.NEXT_PUBLIC_REOPT_WRITE_KEY!,
baseUrl: process.env.REOPT_BASE_URL!,
});// app/api/checkout/route.ts
import { getReopt } from "@/lib/reopt";
export async function POST(request: Request) {
const body = await request.json();
const reopt = await getReopt();
const queued = reopt.track("checkout_completed", {
orderId: body.orderId,
amount: body.amount,
currency: "KRW",
});
return Response.json({ ok: queued.queued, eventId: queued.eventId });
}getReopt()가 반환하는 클라이언트는 이 요청을 보낸 방문자에게 이미 묶여 있습니다.
브라우저가 심어 둔 device 쿠키를 읽어 이벤트에 실어 보냅니다. 그래서 결제·주문 완료처럼 서버에서 확정되는 전환도 그 방문자의 현재 세션과 퍼널에 이어집니다.
flush()를 직접 부르지 않아도 됩니다.
Vercel에서는 SDK가 요청의 waitUntil을 자동으로 찾아 전송을 넘깁니다. 따로 설치할 패키지는 없습니다.
그런 수단이 없는 상시 실행 서버에서는 SDK 자체 배칭 타이머가 처리합니다.
응답 직후 프로세스가 멈추는 다른 서버리스 호스트라면 createReopt({ waitUntil })로 호스트의 waitUntil을 넘기거나, 응답 전에 await reopt.flush()를 호출하세요.
방문자가 수집을 거부(opt-out)했다면 getReopt()는 아무것도 보내지 않는 클라이언트를 돌려줍니다.
호출부에 동의 분기를 넣을 필요가 없습니다.
Next.js가 아닌 워커·크론·스크립트에서는 요청이 없으므로 다른 진입점을 씁니다.
import { createReoptNode } from "@reopt-ai/data-sdk-server/node";
const reopt = createReoptNode({
clientId: process.env.REOPT_CLIENT_ID!,
clientSecret: process.env.REOPT_CLIENT_SECRET!,
baseUrl: process.env.REOPT_BASE_URL!,
});
await reopt.trackAndFlush("nightly_report_generated", { rows: 12_400 });
await reopt.close(); // 프로세스 종료 전 필수. 타이머를 멈추고 큐를 비웁니다5. 수집 결과 확인하기
첫 이벤트를 보낸 뒤 아래 순서로 확인하세요.
- 브라우저 Network 탭에서
POST /api/track응답이 200인지 봅니다. - 응답의
accepted가 1 이상인지 봅니다. - 프로젝트의 이벤트 스트림에서 방금 보낸 이벤트가 시간 역순 목록에 나타나는지 확인합니다.
- 데이터 카탈로그에서 이벤트 이름이 보이는지 확인합니다.
- 로그인 직후
identify를 보냈다면 사용자 프로필에profileId가 연결되는지 확인합니다.
분석 화면 반영은 수집 뒤에 이어지므로, 응답이 200이어도 화면에는 잠시 뒤에 나타날 수 있습니다.
브라우저 SDK가 무엇을 보냈는지 페이지 안에서 보려면 @reopt-ai/data-sdk-devtool 패널을 붙이세요. 큐에 들어간 이벤트와 전송된 배치, 서버 응답을 민감 값이 가려진 상태로 보여줍니다. 붙이는 방법은 추적 설정에 있습니다.
원본 보기성공 응답은 보통 다음 형태입니다.
{
"status": "ok",
"requestId": "...",
"mode": "browser",
"accepted": 1,
"duplicates": 0,
"rejected": [],
"queued": true
}accepted는 이번 요청에서 새로 저장된 이벤트 수입니다.
mode는 어떤 자격증명으로 보냈는지에 따라 browser(write key) 또는 server(client ID + secret)입니다.
queued가 true이면 분석 화면에 반영할 작업이 예약된 것입니다.
브라우저 요청에는 서버가 세션을 이어 붙일 때 쓰는 session 값이 함께 내려올 수 있습니다. SDK가 알아서 보관하므로 직접 다룰 필요는 없습니다.
자주 막히는 지점
| 증상 | 확인할 것 |
|---|---|
| 401 응답 | 브라우저에는 writeKey, 서버에는 clientId + serverSecret을 썼는지 확인하세요. clientId는 writeKey가 아니라 서버용 client의 ID입니다. |
400 validation_failed | 이벤트 타입, eventId, timestamp, payload 구조가 수집 형식에 맞는지 확인하세요. |
429 rate_limited | 프로젝트당 분당 요청 한도에 걸렸습니다. Retry-After만큼 기다리면 풀립니다. |
429 quota_exceeded | 조직의 월간 데이터 포인트 한도입니다. 기다려도 풀리지 않으니 플랜과 한도를 확인하세요. |
콘솔에 [reopt] ... missing | writeKey 또는 baseUrl이 비어 SDK가 꺼진 상태입니다. 환경변수가 빌드에 들어갔는지 확인하세요. |
| 응답은 200인데 화면에 늦게 보임 | 분석 화면 반영은 수집 뒤에 이어집니다. 이벤트 스트림에서 먼저 확인하고, 집계 화면은 잠시 뒤에 다시 보세요. |
| 페이지뷰가 두 배로 잡힘 | init() 뒤에 pageView()를 한 번 더 부르고 있지 않은지 확인하세요. |
| 같은 이벤트가 duplicate 처리됨 | 같은 eventId를 재사용하고 있지 않은지 확인하세요. 브라우저에서는 5초 안에 같은 내용의 이벤트를 다시 보내도 duplicate로 처리됩니다. |
| 사용자가 연결되지 않음 | 로그인 직후 identify를 보냈는지, 이후 이벤트에 profileId가 붙는지 확인하세요. |
다음 단계
- SDK 동작을 더 자세히 보려면 추적 설정
- 에러 수집, 세션 리플레이, AI 텔레메트리를 켜려면 추적 설정의 에러 수집 켜기부터 이어지는 절
- 이벤트 의미를 정리하려면 데이터 카탈로그
- 수집 요청의 형식과 오류 코드는 데이터 수집과 거버넌스