@vircle/sdk-web
v0.4.1
Published
Vircle SDK for Web applications
Maintainers
Readme
@vircle/sdk-web
VircleCore를 확장하여 웹 환경에 특화된 기능을 제공하는 웹 애플리케이션용 Vircle Analytics SDK입니다. 자동 추적, 브라우저 컨텍스트 수집, 웹 스토리지 지원, 하이브리드 암호화 등 웹 환경에 최적화된 기능을 제공합니다.
주요 기능
핵심 기능
- VircleCore 상속: 코어 SDK의 모든 기능 + 웹 특화 기능
- 자동 추적: 페이지뷰, 클릭, 폼 제출, JavaScript 에러 자동 감지
- SPA 지원: History API 래핑으로 라우트 변경 감지
- 웹 컨텍스트 수집: 브라우저, OS, 디바이스, UTM 파라미터 등
성능 최적화
- requestIdleCallback: UI 블로킹 없는 백그라운드 처리
- 컨텍스트 캐싱: 반복적인 DOM 접근 방지
- 스마트 스토리지: IndexedDB/LocalStorage 자동 선택으로 대용량 데이터 지원
- 이벤트 배칭: 네트워크 요청 최소화
- 큐 크기 제한: TaskScheduler 큐 오버플로우 방지 (기본 1000)
크로스 도메인 어트리뷰션
- URL
_vuid자동 적용: 아웃링크에?_vuid=xxx가 있으면 SDK의 anonymousId를 해당 값으로 교체 - 라운지→Cafe24 시나리오: 동일 VUID로 크로스 도메인 이벤트 수집
세션 관리
- 세션 타임아웃: 비활성 상태 감지 후 자동 세션 로테이션 (기본 30분)
- fetch+keepalive: 페이지 종료 시
Authorization헤더 포함 이벤트 전송
보안 및 프라이버시
- 페이로드 암호화: Web Crypto API 기반 하이브리드 암호화 (AES-256-GCM + RSA-OAEP)
- 추적 제외: data-vircle-ignore 속성으로 민감 정보 보호
- 안전한 에러 처리: SDK 안정성을 위한 모든 외부 API 호출 보호
- 전용 에러 클래스: 상세한 에러 코드 및 디버깅 정보 제공
설치
npm install @vircle/sdk-web
# 또는
yarn add @vircle/sdk-web
# 또는
pnpm add @vircle/sdk-web예제 실행
예제는 packages/demo-web 디렉토리에서 확인할 수 있습니다:
# 저장소 클론 후
cd packages/demo-web
# ESM 예제
open esm/index.html
# React 예제
cd react && pnpm install && pnpm start
# Next.js 예제
cd nextjs && pnpm install && pnpm dev자세한 내용은 demo-web README를 참조하세요.
빠른 시작
기본 사용법
import { VircleWeb } from '@vircle/sdk-web';
// SDK 초기화 (VircleCore 설정 + 웹 전용 설정)
const vircle = new VircleWeb({
apiKey: 'your-api-key',
environment: 'production',
// 배치 처리 설정 (VircleCore 기능)
batch: {
size: 50, // 기본값: 50
timeout: 5000, // 기본값: 5000ms
flushInterval: 10000, // 기본값: 10000ms
},
// 웹 전용 자동 추적 설정
trackPageViews: true,
trackClicks: true,
trackForms: true,
trackErrors: true,
singlePageApp: true,
// 암호화 활성화
enableEncryption: true,
// 스토리지 설정
storageType: 'auto',
storagePrefix: 'vircle_',
}, {
// 웹 전용 옵션
flushOnUnload: true,
contextCacheTime: 300000,
});
// SDK 초기화 필수!
await vircle.initialize();
// 커스텀 이벤트 추적
await vircle.track('button_clicked', {
button_id: 'purchase',
value: 99.99,
});
// 사용자 식별 (identify 이벤트로 서버 전송)
await vircle.identify('user-123', {
email: '[email protected]',
name: '홍길동',
});ES Modules (브라우저)
<!-- 방법1: CDN 사용 (standalone 빌드 - 모든 의존성 포함) -->
<script type="module">
import { VircleWeb } from 'https://static.vircle.co.kr/sdk/v1/js/vircle-web-sdk.standalone.esm.js';
const vircle = new VircleWeb({
apiKey: 'your-api-key',
environment: 'production',
trackPageViews: true,
trackClicks: true,
});
await vircle.initialize();
</script>
<!-- 방법2: 로컬 파일 사용 -->
<script type="module" src="/dist/vircle-web-sdk.standalone.esm.js"></script>UMD (레거시 지원)
<script src="https://static.vircle.co.kr/sdk/v1/js/vircle-web-sdk.min.js"></script>
<script>
// UMD 빌드는 VircleWebSDK 전역 변수로 VircleWeb 클래스를 직접 노출합니다
const vircle = new VircleWebSDK({
apiKey: 'your-api-key',
});
vircle.initialize().then(() => {
console.log('SDK 초기화 완료');
});
</script>아키텍처
┌────────────────────────────────────────────┐
│ VircleWeb │
│ (VircleCore 상속 + 웹 전용 기능) │
├────────────────────────────────────────────┤
│ • 자동 추적 (페이지뷰/클릭/폼/에러/SPA) │
│ • 웹 컨텍스트 수집 (WebContextCollector) │
│ • 세션 타임아웃 / 로테이션 │
│ • fetch+keepalive (페이지 이탈 보호) │
│ • StorageFactory (IndexedDB/LocalStorage) │
│ • 하이브리드 암호화 (WebExtendedCryptoAdapter)│
│ • 에러 클래스 (VircleWebError 계열) │
└────────────────────┬───────────────────────┘
│ extends
┌────────────────────┴───────────────────────┐
│ VircleCore │
│ (이벤트/전송/플러그인/암호화/원격 설정/스토리지) │
└────────────────────────────────────────────┘웹 전용 기능 상세
자동 추적 시스템
SDK는 setupAutoTracking 메서드를 통해 다양한 브라우저 이벤트를 자동으로 추적합니다:
페이지뷰 추적
- 초기 로드: 페이지 첫 로드 시 자동 추적
- SPA 라우트 변경: History API (
pushState,replaceState) 래핑 - 브라우저 네비게이션:
popstate이벤트 감지 - 추적 데이터: URL, 제목, 리퍼러, UTM 파라미터
클릭 추적
- 전역 이벤트 위임:
document에 단일 리스너로 모든 클릭 감지 - 요소 정보 수집: 태그명, 텍스트, 클래스, ID
- 추적 대상:
A,BUTTON,INPUT,SELECT,TEXTAREA요소만 추적 - 추적 제외:
data-vircle-ignore속성으로 민감 요소 제외 - data- 속성 수집*: idle 시간에 비동기로 추가 data 속성 수집
폼 제출 추적
- 자동 감지: 모든
form태그의submit이벤트 - 수집 정보: 폼 ID, name, action, method
- 보안: 폼 데이터는 수집하지 않음
에러 추적
- JavaScript 에러:
ErrorEvent리스너 (메시지, 파일명, 라인, 컬럼, 스택) - Promise 거부:
PromiseRejectionEvent리스너 (reason)
웹 컨텍스트 수집 (WebContextCollector)
collect() 호출 시 device, page, app, custom 4가지 컨텍스트를 병렬로 수집합니다.
device (DeviceContext)
User-Agent 기반 디바이스/브라우저/OS 감지 및 화면 정보 수집
| 필드 | 타입 | 소스 | 설명 |
|------|------|------|------|
| type | 'mobile' \| 'tablet' \| 'desktop' | navigator.userAgent | UA 패턴 매칭으로 판별 |
| os | string | navigator.userAgent | Windows, macOS, Linux, Android, iOS, Chrome OS |
| osVersion | string \| undefined | navigator.userAgent | OS 버전 (예: 14.0) |
| browser | string | navigator.userAgent | Edge, Chrome, Firefox, Safari, Opera, IE |
| browserVersion | string \| undefined | navigator.userAgent | 브라우저 버전 (예: 120.0) |
| screenResolution | string | screen.width/height | "1920x1080" 형태 |
| viewport | { width, height } | window.innerWidth/Height | 현재 뷰포트 크기 |
| language | string | navigator.language | 브라우저 언어 (예: ko-KR) |
| timezone | string | Intl.DateTimeFormat | IANA 타임존 (예: Asia/Seoul) |
page (PageContext)
현재 페이지 URL 파싱 결과
| 필드 | 타입 | 소스 | 설명 |
|------|------|------|------|
| url | string | window.location.href | 전체 URL |
| title | string | document.title | 페이지 제목 |
| path | string | URL.pathname | 경로 (예: /products) |
| search | string | URL.search | 쿼리스트링 (예: ?category=electronics) |
| hash | string | URL.hash | 해시 프래그먼트 |
app (AppContext)
애플리케이션 메타 정보 (HTML meta 태그 기반)
| 필드 | 타입 | 소스 | 설명 |
|------|------|------|------|
| name | string | <meta name="application-name"> 또는 <meta property="og:site_name"> 또는 document.title | 앱 이름 |
| version | string \| undefined | <meta name="version"> | 앱 버전 |
| environment | 'development' \| 'production' | window.location.hostname | localhost/staging → development, 그 외 → production |
campaign (CampaignContext)
URL의 UTM 파라미터 및 광고 클릭 ID를 수집합니다. sessionStorage에 저장하여 MPA 페이지 전환 간에도 유지됩니다.
| 필드 | 타입 | 조건 | 설명 |
|------|------|------|------|
| source | string | utm_source 존재 시 | 트래픽 소스 (예: google) |
| medium | string | utm_medium 존재 시 | 트래픽 매체 (예: cpc) |
| campaign | string | utm_campaign 존재 시 | 캠페인 이름 |
| term | string | utm_term 존재 시 | 검색 키워드 |
| content | string | utm_content 존재 시 | 광고 콘텐츠 구분 |
| gclid | string | gclid 존재 시 | Google Ads 클릭 ID |
| fbclid | string | fbclid 존재 시 | Facebook 클릭 ID |
| msclkid | string | msclkid 존재 시 | Microsoft Ads 클릭 ID |
| ttclid | string | ttclid 존재 시 | TikTok 클릭 ID |
custom (Record<string, unknown>)
추가 브라우저 환경 정보 (가용한 경우에만 수집)
| 필드 | 타입 | 조건 | 설명 |
|------|------|------|------|
| referrer | string | document.referrer 존재 시 | 이전 페이지 URL |
| cookieEnabled | boolean | 항상 | 쿠키 활성화 여부 |
| doNotTrack | boolean | navigator.doNotTrack 존재 시 | DNT 설정 여부 |
| connection | { effectiveType, downlink, rtt, saveData } | Network Information API 지원 시 | 네트워크 연결 정보 |
| memory | { usedJSHeapSize, totalJSHeapSize, jsHeapSizeLimit } | performance.memory 지원 시 (Chrome 전용) | JS 힙 메모리 사용량 |
수집 결과 예시
{
device: {
type: 'desktop',
os: 'macOS',
osVersion: '14.0',
browser: 'Chrome',
browserVersion: '120.0',
screenResolution: '1920x1080',
viewport: { width: 1200, height: 800 },
language: 'ko-KR',
timezone: 'Asia/Seoul'
},
page: {
url: 'https://example.com/products?category=electronics',
title: '제품 목록',
path: '/products',
search: '?category=electronics',
hash: ''
},
app: {
name: 'My Store',
version: '2.1.0',
environment: 'production'
},
campaign: {
source: 'google',
medium: 'cpc',
campaign: 'summer_sale'
},
custom: {
referrer: 'https://google.com',
cookieEnabled: true,
doNotTrack: false,
connection: {
effectiveType: '4g',
downlink: 10.0,
rtt: 50,
saveData: false
},
memory: {
usedJSHeapSize: 12345678,
totalJSHeapSize: 33554432,
jsHeapSizeLimit: 2147483648
}
}
}스토리지 어댑터
SDK는 StorageFactory를 통해 환경에 최적화된 스토리지를 자동 선택합니다:
IndexedDB 어댑터 (권장)
- 대용량 지원: LocalStorage 5MB 제한 없이 대량 이벤트 저장
- 비동기 처리: UI 블로킹 없는 백그라운드 저장
- 트랜잭션 지원: 데이터 무결성 보장
- LRU 정리: 타임스탬프 인덱스 기반 오래된 데이터 자동 정리
LocalStorage 어댑터
- 자동 용량 관리: QuotaExceededError 시 LRU 캐시 정리
- 접두사 격리:
vircle_접두사로 다른 데이터와 분리 - 타임스탬프 추적: 데이터 저장 시간 기록
- 안전한 폴백: LocalStorage 불가 시 경고 후 계속 작동
스토리지 타입 선택
const vircle = new VircleWeb({
apiKey: 'your-api-key',
storageType: 'auto', // 'auto' | 'localStorage' | 'indexedDB'
});| 타입 | 설명 |
|------|------|
| auto (기본값) | IndexedDB 우선, 미지원 시 LocalStorage 폴백 |
| localStorage | 항상 LocalStorage 사용 |
| indexedDB | 항상 IndexedDB 사용 |
StorageFactory는 동기(create) 및 비동기(createAsync) 생성을 모두 지원합니다. 비동기 방식은 Safari Private 모드 등에서 IndexedDB 실제 사용 가능 여부를 테스트한 후 안전하게 폴백합니다.
암호화 (WebExtendedCryptoAdapter)
Web Crypto API 기반의 하이브리드 암호화를 제공합니다:
데이터 (JSON) → AES-256-GCM 암호화 → 암호문 + Auth Tag
AES 키 → RSA-OAEP (서버 공개키) → 암호화된 키
결과: { data, key, iv, authTag, metadata }암호화 활성화
const vircle = new VircleWeb({
apiKey: 'your-api-key',
enableEncryption: true, // Web Crypto API 기반 암호화 활성화
});제공 기능
- 하이브리드 암호화: AES-256-GCM (데이터) + RSA-OAEP (키 래핑)
- UUID v4 생성:
crypto.randomUUID또는getRandomValues폴백 - HMAC-SHA256 서명: 페이로드 무결성 검증
- 자동 가용성 감지: Web Crypto API 미지원 시 암호화 자동 비활성화
암호화된 페이로드 구조
interface EncryptedPayload {
data: string; // Base64 인코딩된 AES-GCM 암호문
key: string; // Base64 인코딩된 RSA-OAEP 암호화 AES 키
iv: string; // Base64 인코딩된 초기화 벡터 (96-bit)
authTag: string; // Base64 인코딩된 GCM 인증 태그 (128-bit)
metadata: {
algorithm: 'AES-256-GCM';
keyAlgorithm: 'RSA-OAEP';
timestamp: string;
};
}세션 타임아웃
SDK는 사용자 비활성 상태를 감지하여 자동으로 새 세션을 시작합니다:
- 기본 타임아웃: 30분 (설정 가능)
- 동작 방식:
visibilitychange → visible이벤트 시 마지막 활동 시간과 비교 - 세션 로테이션: 타임아웃 경과 시 새 세션 ID 생성 +
session_start이벤트 자동 추적 - 활동 갱신:
track()호출 시마다 마지막 활동 시간 갱신
const vircle = new VircleWeb({
apiKey: 'your-api-key',
sessionTimeout: 15 * 60 * 1000, // 15분
});fetch+keepalive (페이지 이탈 보호)
페이지 종료 시 fetch() + keepalive: true 옵션을 사용하여 대기 중인 이벤트를 안전하게 전송합니다:
- beforeunload: 페이지 닫기/새로고침 시 큐의 이벤트를 keepalive fetch로 전송
- visibilitychange → hidden: 탭 전환/최소화 시 keepalive fetch로 전송
- 장점:
Authorization헤더를 포함할 수 있어 인증된 요청으로 전송 가능 - 폴백:
keepalive미지원 환경에서는 자동으로 무시됩니다
const vircle = new VircleWeb(
{ apiKey: 'your-api-key' },
{ flushOnUnload: true }, // 기본값: true
);에러 클래스
SDK는 디버깅을 위한 구조화된 에러 클래스를 제공합니다:
| 에러 클래스 | 코드 | 설명 |
|------------|------|------|
| VircleWebError | - | 기본 에러 클래스 (코드, 상세정보 포함) |
| VircleConfigError | CONFIG_ERROR | 잘못된 설정 (API 키 누락 등) |
| VircleInitializationError | INITIALIZATION_ERROR | 초기화 실패 |
| VircleStorageError | STORAGE_ERROR | 스토리지 작업 실패 |
| VircleBrowserCompatibilityError | BROWSER_COMPATIBILITY_ERROR | 브라우저 미지원 기능 |
import { VircleWebError, VircleConfigError } from '@vircle/sdk-web';
try {
const vircle = new VircleWeb({ apiKey: '' });
await vircle.initialize();
} catch (error) {
if (error instanceof VircleConfigError) {
console.error('설정 오류:', error.code, error.details);
}
}성능 최적화 기술
- requestIdleCallback 활용: TaskScheduler를 통한 UI 블로킹 없는 백그라운드 이벤트 처리
- 컨텍스트 캐싱: ContextCache를 통한 브라우저 정보 캐싱 (기본 5분), 중복 수집 방지를 위한 Promise 재사용
- 이벤트 배칭: TransportService의 큐를 통한 네트워크 요청 최소화
- 메모리 관리: cleanup 시 모든 이벤트 리스너 제거 및 History API 원복으로 누수 방지
- 페이지 이탈 대응:
fetch()+keepalive를 사용한 페이지 종료 시 안정적 이벤트 전송 - 큐 크기 제한: TaskScheduler의
maxQueueSize(기본 1000)로 메모리 오버플로우 방지
추적 제외
특정 요소나 영역을 추적에서 제외하려면 data-vircle-ignore 속성을 사용하세요:
<!-- 이 버튼은 클릭 추적에서 제외됩니다 -->
<button data-vircle-ignore>추적 제외 버튼</button>
<!-- 이 영역 내의 모든 요소가 추적에서 제외됩니다 -->
<div data-vircle-ignore>
<button>추적 안됨</button>
<a href="#">이 링크도 추적 안됨</a>
</div>설정 옵션
VircleWebConfig
VircleConfig (코어)를 상속하며 웹 전용 옵션을 추가합니다.
interface VircleWebConfig extends VircleConfig {
trackPageViews?: boolean; // 자동 페이지뷰 추적 (기본: false)
trackClicks?: boolean; // 자동 클릭 추적 (기본: false)
trackForms?: boolean; // 자동 폼 제출 추적 (기본: false)
trackErrors?: boolean; // 자동 에러 추적 (기본: false)
singlePageApp?: boolean; // SPA 모드 (기본: false)
storagePrefix?: string; // 스토리지 키 접두사 (기본: 'vircle_')
storageType?: StorageType; // 스토리지 타입: 'auto' | 'localStorage' | 'indexedDB' (기본: 'auto')
enableEncryption?: boolean; // Web Crypto API 암호화 활성화 (기본: false)
sessionTimeout?: number; // 세션 타임아웃(ms) (기본: 1800000 = 30분)
}VircleConfig (코어) 주요 옵션
| 옵션 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| apiKey | string | (필수) | API 인증 키 |
| environment | 'development' \| 'production' | 'production' | 환경 설정 |
| debug | boolean | false | 디버그 모드 |
| batch.size | number | 50 | 배치당 최대 이벤트 수 |
| batch.timeout | number | 5000 | 배치 대기 시간(ms) |
| batch.flushInterval | number | 10000 | 자동 플러시 간격(ms) |
| retry.maxAttempts | number | 3 | 최대 재시도 횟수 |
| retry.initialDelay | number | 500 | 초기 백오프 지연(ms) |
| privacy.respectDoNotTrack | boolean | true | DNT 헤더 존중 |
| headers | Record<string, string> | - | 커스텀 HTTP 헤더 |
VircleWebOptions
interface VircleWebOptions extends Partial<VircleCoreOptions> {
flushOnUnload?: boolean; // 페이지 언로드 시 fetch+keepalive 전송 (기본: true)
contextCacheTime?: number; // 컨텍스트 캐시 시간(ms) (기본: 300000 = 5분)
}API 레퍼런스
초기화
await vircle.initialize(): Promise<void>SDK를 초기화하고 자동 추적을 시작합니다.
이벤트 추적
await vircle.track<TProperties>(
name: string,
properties?: TProperties,
context?: EventContext
): Promise<void>커스텀 이벤트를 추적합니다. requestIdleCallback을 활용하여 UI를 블로킹하지 않으며, 호출 시마다 세션의 마지막 활동 시간이 갱신됩니다.
페이지뷰 추적
await vircle.trackPageView(
properties?: Record<string, unknown>,
context?: EventContext
): Promise<void>페이지뷰를 수동으로 추적합니다. URL, 제목, 리퍼러 등의 페이지 컨텍스트를 자동 수집합니다.
사용자 식별
await vircle.identify<TTraits>(
userId: string,
traits?: TTraits
): Promise<void>사용자를 식별하고 속성을 설정합니다. VircleWeb에서는 호출 시 컨텍스트 캐시를 자동으로 무효화합니다.
사용자 리셋
await vircle.reset(): Promise<void>사용자 정보와 세션을 초기화합니다.
유틸리티
// 현재 페이지 URL
vircle.getCurrentUrl(): string
// 네트워크 연결 상태
vircle.isOnline(): boolean
// 크로스 도메인 어트리뷰션용 anonymousId
vircle.getAnonymousId(): string | undefined
// SDK 상태 확인
vircle.getStatus(): {
isInitialized: boolean;
sessionId?: string;
userId?: string;
pluginCount: number;
queueSize: number;
}
// 런타임 메트릭 조회
vircle.getMetrics(): {
queueSize: number;
isProcessing: boolean;
}
// 이벤트 수동 플러시
await vircle.flush(): Promise<void>
// 이벤트 수동 플러시 (타임아웃 지정)
await vircle.flush(timeoutMs?: number): Promise<void>정리
await vircle.cleanup(): Promise<void>SDK가 사용하는 모든 리소스를 정리합니다:
- 이벤트 리스너 제거 (
beforeunload,error,click,submit,popstate,visibilitychange) - History API 원복 (
pushState,replaceState) - 대기 중인 이벤트 전송 (
flush()) - 코어 서비스 정리 (
super.cleanup())
Exports
// 메인 SDK 클래스
import { VircleWeb } from '@vircle/sdk-web';
import VircleWeb from '@vircle/sdk-web'; // default export
// 설정 타입
import type { VircleWebConfig, VircleWebOptions } from '@vircle/sdk-web';
// 컨텍스트 수집기
import { WebContextCollector } from '@vircle/sdk-web';
// 스토리지
import { LocalStorageAdapter, IndexedDBAdapter, StorageFactory } from '@vircle/sdk-web';
import type { StorageType } from '@vircle/sdk-web'; // 'auto' | 'localStorage' | 'indexedDB'
// 암호화 어댑터
import { WebExtendedCryptoAdapter } from '@vircle/sdk-web';
// 에러 클래스
import {
VircleWebError,
VircleConfigError,
VircleInitializationError,
VircleStorageError,
VircleBrowserCompatibilityError,
} from '@vircle/sdk-web';
// Core 타입 재수출
import type {
VircleConfig,
EventContext,
DeviceContext,
PageContext,
AppContext,
UserTraits,
StorageAdapter,
} from '@vircle/sdk-web';빌드 파일 설명
| 파일 | 포맷 | 용도 | @vircle/sdk-core-ts | 사용 방법 |
|------|------|------|----------------------|-----------|
| dist/index.js | CJS | 번들러 (Webpack 등) | 외부 의존성 | require('@vircle/sdk-web') |
| dist/index.esm.js | ESM | 번들러 (Vite, Rollup 등) | 외부 의존성 | import { VircleWeb } from '@vircle/sdk-web' |
| dist/vircle-web-sdk.standalone.esm.js | ESM | 브라우저 직접 사용 | 번들에 포함 | <script type="module"> |
| dist/vircle-web-sdk.min.js | UMD | 레거시 브라우저 | 번들에 포함 | <script src="..."> |
| dist/index.d.ts | DTS | TypeScript 타입 정의 | - | 자동 적용 |
중요: 브라우저에서 직접 사용할 때는 반드시 standalone 또는 min 빌드를 사용하세요. npm 패키지로 사용 시 번들러가 @vircle/sdk-core-ts를 함께 번들링합니다.
브라우저 지원
- Chrome/Edge: 최신 2개 버전
- Firefox: 최신 2개 버전
- Safari: 최신 2개 버전
- iOS Safari: iOS 12+
- Chrome for Android: Android 6+
암호화 기능(
enableEncryption)은 Web Crypto API를 지원하는 브라우저에서만 동작합니다. 미지원 시 자동으로 비활성화됩니다.
보안 고려사항
클라이언트 측 API 키: 브라우저에서 사용되는 API 키는 공개됩니다. 데이터 수집(Write) 권한만 가진 키를 사용하세요.
민감한 데이터: 민감한 데이터가 수집되지 않도록
data-vircle-ignore속성을 적절히 사용하세요.스토리지: SDK는 LocalStorage/IndexedDB를 사용하여 데이터를 임시 저장합니다. 민감한 정보는 저장하지 않습니다.
암호화:
enableEncryption: true설정 시 서버 공개키로 이벤트 페이로드를 암호화합니다. 공개키는 CDN(RemoteConfigService)에서 자동 fetch됩니다.페이지 이탈 전송: 페이지 종료 시
fetch()+keepalive로 전송되며,Authorization헤더를 포함한 인증된 요청으로 전송됩니다. 정상 동작과 동일한fetch()기반 전송을 사용합니다.
성능 영향
- 번들 크기 (standalone): ~106KB (minified, core 포함), npm 패키지는 ~70KB (core 외부 의존성)
- 이벤트 추적: requestIdleCallback 기반으로 UI 블로킹 없음
- 컨텍스트 수집: 캐싱으로 반복적인 DOM 접근 방지 (기본 5분)
고급 사용 예제
SPA (Single Page Application) 설정
// singlePageApp: true 설정 시 History API (pushState, replaceState)를 래핑하여
// 라우트 변경을 자동으로 감지하고 페이지뷰를 추적합니다.
// React Router, Vue Router, Next.js 등 대부분의 SPA 프레임워크와 호환됩니다.
const vircle = new VircleWeb({
apiKey: 'your-api-key',
singlePageApp: true, // History API 래핑
trackPageViews: true, // 자동 페이지뷰 추적
});
await vircle.initialize();
// 이후 별도의 설정 없이 라우트 변경 시 자동으로 page_view 이벤트가 추적됩니다.에러 처리와 함께 사용
import { VircleWeb, VircleInitializationError } from '@vircle/sdk-web';
try {
const vircle = new VircleWeb({
apiKey: 'your-api-key',
trackErrors: false, // 자동 에러 추적 비활성화
});
await vircle.initialize();
// 수동으로 에러 추적
try {
await riskyOperation();
} catch (error) {
await vircle.track('error', {
message: error.message,
stack: error.stack,
component: 'PaymentForm',
});
throw error;
}
} catch (error) {
if (error instanceof VircleInitializationError) {
console.error('SDK 초기화 실패:', error.code, error.details);
}
}암호화 활성화
const vircle = new VircleWeb({
apiKey: 'your-api-key',
enableEncryption: true, // Web Crypto API 가용 시 자동 활성화
trackPageViews: true,
});
await vircle.initialize();
// 이후 모든 이벤트가 하이브리드 암호화되어 전송됩니다
await vircle.track('purchase', { amount: 99.99 });성능 최적화 설정
const vircle = new VircleWeb(
{
apiKey: 'your-api-key',
trackPageViews: true,
trackClicks: true,
sessionTimeout: 15 * 60 * 1000, // 15분 세션 타임아웃
},
{
contextCacheTime: 600000, // 10분 캐싱 (기본 5분)
flushOnUnload: true, // fetch+keepalive로 페이지 이탈 시 자동 전송 (기본값)
},
);
// 중요한 시점에 수동으로 flush (예: 결제 완료 후)
await vircle.flush();민감한 정보가 있는 페이지
<!-- 개인정보가 포함된 대시보드 -->
<div class="user-dashboard">
<!-- 사용자 정보는 추적에서 제외 -->
<h1 data-vircle-ignore>안녕하세요, 김철수님!</h1>
<!-- 계좌 정보는 추적에서 완전 제외 -->
<div data-vircle-ignore>
<p>계좌번호: 123-456-789</p>
<p>잔액: ₩1,234,567</p>
<button>송금하기</button>
</div>
<!-- 일반 액션은 추적 -->
<button>프로필 수정</button>
</div>동적 컨텍스트 추가
// 글로벌 컨텍스트 설정
vircle.setContext({
app: {
version: '2.1.0',
environment: 'production',
},
custom: {
experiment_id: 'exp_123',
feature_flags: {
new_ui: true,
beta_features: false,
},
},
});
// 특정 이벤트에만 컨텍스트 추가
await vircle.track(
'purchase_completed',
{
product_id: 'sku_123',
price: 49.99,
},
{
custom: {
payment_method: 'card',
coupon_used: true,
},
},
);문제 해결
SDK가 초기화되지 않음
// 상태 확인
const status = vircle.getStatus();
console.log('SDK 초기화 상태:', status.isInitialized);
// 네트워크 상태 확인
console.log('온라인 상태:', vircle.isOnline());이벤트가 전송되지 않음
// 디버그 모드로 재초기화
const vircle = new VircleWeb({
apiKey: 'your-api-key',
debug: true, // 콘솔에 디버그 로그 출력
});
// 수동으로 이벤트 플러시
await vircle.flush();메모리 누수 방지
// React 예제 - 컴포넌트 언마운트 시 반드시 cleanup 호출
// 일반적으로 SDK는 앱 레벨에서 한 번만 초기화합니다
useEffect(() => {
const vircle = new VircleWeb({
apiKey: 'your-api-key',
trackPageViews: true,
});
vircle.initialize();
return () => {
// cleanup()은 이벤트 리스너 제거, History API 원복, 큐 플러시를 수행합니다
vircle.cleanup();
};
}, []);암호화 관련
// 암호화 미지원 환경에서 enableEncryption: true로 설정한 경우
// 콘솔에 경고 메시지가 출력되고 암호화 없이 동작합니다
// "[Vircle] Web Crypto API를 사용할 수 없습니다. 암호화를 비활성화합니다."TypeScript 지원
SDK는 완전한 TypeScript 타입 정의를 제공합니다:
import {
VircleWeb,
VircleWebConfig,
VircleWebOptions,
WebExtendedCryptoAdapter,
VircleWebError,
} from '@vircle/sdk-web';
import type { EventContext, UserTraits, StorageType } from '@vircle/sdk-web';
// 타입 안전한 설정
const config: VircleWebConfig = {
apiKey: process.env.VIRCLE_API_KEY!,
trackPageViews: true,
trackErrors: true,
enableEncryption: true,
storageType: 'auto',
};
const options: VircleWebOptions = {
contextCacheTime: 300000,
flushOnUnload: true,
};
const vircle = new VircleWeb(config, options);
// 타입 안전한 이벤트 추적
// track()의 제네릭 파라미터는 Record<string, unknown>을 확장해야 합니다
interface PurchaseProperties {
product_id: string;
price: number;
currency: string;
quantity: number;
}
await vircle.track<PurchaseProperties>('purchase', {
product_id: 'sku_123',
price: 49.99,
currency: 'USD',
quantity: 1,
});
// 타입 안전한 사용자 속성
// identify()의 제네릭 파라미터는 Record<string, unknown>을 확장해야 합니다
interface CustomUserTraits {
email: string;
plan: 'free' | 'pro' | 'enterprise';
created_at: string;
}
await vircle.identify<CustomUserTraits>('user-123', {
email: '[email protected]',
plan: 'pro',
created_at: new Date().toISOString(),
});라이선스
MIT
