API

JavaScript SDK 가이드

작성일 2026.03.24 | 수정일 2026.03.25

1. 설치

SOLAPI CRM SDK는 CDN과 NPM 두 가지 방식으로 설치할 수 있습니다. 번들 크기는 gzip 압축 시 약 2.3KB로 매우 가볍습니다.

CDN 방식 (권장)

<!-- SOLAPI CRM SDK -->
<script src="https://cdn.solapi.com/sdk/crm-sdk/stable/solapi-crm.min.js"></script>
<script>
  SolapiCRM.init({
    trackingKey: 'tk_live_xxxxxxxxxxxxxxxx',
    entityId: 'CRMRC1_contacts',
    autoPageView: true
  });
</script>

NPM 방식

npm install @solapi/crm-browser
yarn add @solapi/crm-browser
pnpm add @solapi/crm-browser
import SolapiCRM from '@solapi/crm-browser';

SolapiCRM.init({
  trackingKey: 'tk_live_xxxxxxxxxxxxxxxx',
  entityId: 'CRMRC1_contacts',
  autoPageView: true
});

2. 초기화 — init(config)

SDK를 사용하려면 먼저 init() 메서드로 초기화해야 합니다.

설정 옵션

{
  "trackingKey": {
    "type": "string",
    "default": "(필수)",
    "description": "추적 키. 형식: tk_live_xxx 또는 tk_test_xxx"
  },
  "entityId": {
    "type": "string",
    "default": "(선택)",
    "description": "기본 개체 ID"
  },
  "endpoint": {
    "type": "string",
    "default": "/api/crm/v1/track",
    "description": "API 엔드포인트 URL"
  },
  "autoPageView": {
    "type": "boolean",
    "default": "false",
    "description": "페이지뷰 자동 추적 활성화"
  },
  "batchSize": {
    "type": "number",
    "default": "10",
    "description": "한 번에 전송할 이벤트 수"
  },
  "flushInterval": {
    "type": "number",
    "default": "10000",
    "description": "이벤트 전송 주기 (밀리초)"
  },
  "maxQueueSize": {
    "type": "number",
    "default": "100",
    "description": "큐에 보관할 최대 이벤트 수"
  },
  "debug": {
    "type": "boolean",
    "default": "false",
    "description": "디버그 로그 활성화"
  }
}

전체 설정 예시

SolapiCRM.init({
  // 필수: 추적 키
  trackingKey: 'tk_live_abc123xyz',

  // 권장: 기본 개체 ID
  entityId: 'CRMRC1_contacts',

  // 선택: 페이지뷰 자동 추적
  autoPageView: true,

  // 선택: 배치 설정
  batchSize: 20,
  flushInterval: 5000,
  maxQueueSize: 200,

  // 선택: 디버그 모드 (개발 환경에서만)
  debug: process.env.NODE_ENV === 'development'
});

프로덕션 환경에서는 debug: false로 설정하고, batchSizeflushInterval을 조정하여 네트워크 트래픽을 최적화하세요.

3. 이벤트 추적 — track(eventType, properties?, options?)

사용자 행동을 추적하여 CRM 레코드에 연결합니다. 이벤트는 큐에 저장되었다가 배치로 전송됩니다.

파라미터

{
  "eventType": {
    "type": "string",
    "description": "이벤트 타입 (예: PURCHASE, SIGNUP, CLICK)"
  },
  "properties": {
    "type": "object",
    "description": "이벤트 속성"
  },
  "options.category": {
    "type": "string",
    "description": "이벤트 카테고리"
  },
  "options.label": {
    "type": "string",
    "description": "이벤트 레이블"
  },
  "options.value": {
    "type": "number",
    "description": "이벤트 값"
  },
  "options.recordId": {
    "type": "string",
    "description": "특정 레코드 ID"
  }
}

기본 이벤트 추적

// 단순 이벤트
SolapiCRM.track('SIGNUP');

// 버튼 클릭 이벤트
document.getElementById('cta-button').addEventListener('click', () => {
  SolapiCRM.track('BUTTON_CLICK', {
    buttonId: 'cta-button',
    buttonText: '무료로 시작하기',
    page: window.location.pathname
  });
});

속성과 함께 추적

// 구매 이벤트 with 상세 속성
SolapiCRM.track('PURCHASE', {
  productId: 'PROD_123',
  productName: '나이키 에어맥스',
  category: '신발',
  quantity: 1,
  price: 159000,
  currency: 'KRW',
  discount: 10000
}, {
  category: 'ecommerce',
  label: 'summer_sale_2026',
  value: 149000
});

특정 레코드에 연결

SolapiCRM.track('PREMIUM_UPGRADE', {
  plan: 'Enterprise',
  billingCycle: 'annual',
  amount: 2400000
}, {
  recordId: 'CRMRC1_user_xyz123',
  category: 'subscription',
  value: 2400000
});

배치 처리 동작

이벤트는 다음 조건 중 하나가 충족될 때 서버로 전송됩니다:

  • 큐 크기: batchSize에 도달하면 자동 전송 (기본값: 10개)

  • 시간 간격: flushInterval 시간이 지나면 전송 (기본값: 10초)

  • 탭 닫기: 브라우저 탭이 닫히거나 페이지를 떠날 때 visibilitychange 이벤트로 자동 전송

  • 재시도: 네트워크 오류 시 최대 3회까지 재시도 (지수 백오프)

  • 큐 오버플로: maxQueueSize를 초과하면 가장 오래된 이벤트부터 삭제

이벤트가 큐에 저장되므로 즉시 서버에 전송되지 않습니다. 실시간 처리가 필요한 경우 SolapiCRM.flush()를 호출하여 강제로 전송하세요.

4. 페이지뷰 추적 — trackPageView()

수동 페이지뷰 추적

// 페이지가 로드될 때
SolapiCRM.trackPageView();

// React Router 예시
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

function App() {
  const location = useLocation();

  useEffect(() => {
    SolapiCRM.trackPageView();
  }, [location]);

  return <div>...</div>;
}

자동 페이지뷰 추적 (권장)

autoPageView: true로 초기화하면 SDK가 자동으로 페이지뷰를 추적합니다. SPA 프레임워크(React, Vue, Angular)에서도 별도 코드 없이 모든 라우팅이 자동 추적됩니다.

자동 감지 이벤트:

  • history.pushState: React Router, Vue Router 등의 라우팅

  • history.replaceState: URL 변경 없이 상태만 변경하는 경우

  • popstate: 브라우저 뒤로 가기/앞으로 가기

자동 수집 속성

{
  "url": {
    "description": "전체 URL",
    "example": "https://example.com/products"
  },
  "path": {
    "description": "경로",
    "example": "/products"
  },
  "title": {
    "description": "페이지 제목",
    "example": "Products - MyShop"
  },
  "referrer": {
    "description": "이전 페이지",
    "example": "https://google.com"
  }
}

5. 전환 추적 — 표준 이벤트 프리셋

자주 사용되는 이벤트를 표준화된 메서드로 간편하게 추적할 수 있습니다. 프리셋 메서드는 내부적으로 track()을 호출하며, 적절한 카테고리·레이블·값이 자동 설정됩니다.

일반 전환 이벤트

// 회원가입 추적 (SIGN_UP)
SolapiCRM.trackSignUp({
  method: 'email'           // 필수: 가입 방식
});

// 로그인 추적 (LOGIN)
SolapiCRM.trackLogin({
  method: 'kakao'           // 필수: 로그인 방식
});

// 폼 제출 추적 (FORM_SUBMIT)
SolapiCRM.trackFormSubmit({
  formId: 'contact-form',   // 필수: 폼 ID
  formName: '문의하기'       // 선택: 폼 이름 (레이블로 사용)
});

이커머스 전환 이벤트

// 상품 조회 (PRODUCT_VIEW)
SolapiCRM.trackProductView({
  productId: 'PROD_001',    // 필수
  name: '프리미엄 요금제',    // 필수
  category: 'plans',        // 선택
  price: 79000,             // 선택 (value로 사용)
  currency: 'KRW'           // 선택
});

// 장바구니 추가 (CART_ADD)
SolapiCRM.trackAddToCart({
  productId: 'PROD_001',    // 필수
  name: '프리미엄 요금제',    // 필수
  quantity: 1,              // 선택 (기본: 1)
  price: 79000              // 선택 (value = price × quantity)
});

// 결제 시작 (CHECKOUT_START)
SolapiCRM.trackCheckoutStart({
  totalAmount: 79000,       // 필수 (value로 사용)
  itemCount: 1,             // 필수
  cartId: 'CART_001',       // 선택
  currency: 'KRW'           // 선택
});

// 구매 완료 (PURCHASE)
SolapiCRM.trackPurchase({
  orderId: 'ORD_001',       // 필수
  totalAmount: 79000,       // 필수 (value로 사용)
  items: [{                 // 선택
    productId: 'PROD_001',
    name: '프리미엄 요금제',
    quantity: 1,
    price: 79000
  }],
  currency: 'KRW'           // 선택
});

// 환불 (REFUND)
SolapiCRM.trackRefund({
  orderId: 'ORD_001',       // 필수
  refundAmount: 79000       // 필수 (value로 사용)
});

퍼널 분석 예시

프리셋 이벤트를 조합하여 전환 퍼널을 구성할 수 있습니다:

{
  "구매 퍼널": {
    "description": "상품 조회부터 구매까지의 전환 경로",
    "flow": "PAGE_VIEW → PRODUCT_VIEW → CART_ADD → CHECKOUT_START → PURCHASE"
  },
  "가입 퍼널": {
    "description": "첫 방문부터 로그인까지",
    "flow": "PAGE_VIEW → SIGN_UP → LOGIN"
  },
  "폼 퍼널": {
    "description": "페이지 방문 후 폼 제출",
    "flow": "PAGE_VIEW → FORM_SUBMIT"
  },
  "커스텀 퍼널": {
    "description": "프리셋 + track() 조합",
    "flow": "SIGN_UP → (커스텀) → (커스텀)"
  }
}

프리셋 메서드와 track()을 자유롭게 조합하여 사용할 수 있습니다. 대시보드의 "이벤트 퍼널" 위젯에서 전환율을 시각화할 수 있습니다.

6. 사용자 식별 — identify(recordId, traits?)

로그인한 사용자를 CRM 레코드에 연결합니다. 익명 사용자의 이벤트를 알려진 레코드로 병합하는 핵심 기능입니다.

기본 사용법

// 로그인 시 — 레코드 ID만 전달
SolapiCRM.identify('CRMRC1_user_xyz123');

// 이후 이벤트는 자동으로 이 레코드에 연결됨
SolapiCRM.track('VIEW_DASHBOARD');

속성과 함께 식별

SolapiCRM.identify('CRMRC1_user_xyz123', {
  name: '홍길동',
  email: 'hong@example.com',
  phone: '01012345678',
  plan: 'premium',
  lastLogin: new Date().toISOString()
});

익명 사용자 → 알려진 사용자 전환 흐름

  1. 첫 방문 (익명 상태): SDK가 자동으로 익명 ID를 생성합니다 (anon_1234567890abcdef)

  2. 익명 이벤트 수집: 로그인 전 이벤트는 익명 ID로 추적됩니다

  3. 사용자 로그인: identify()를 호출하여 레코드 ID와 연결합니다

  4. 서버 측 이벤트 병합: 서버가 자동으로 익명 ID의 모든 이벤트를 알려진 레코드로 병합합니다

  5. 이후 이벤트: 모든 이벤트가 알려진 레코드에 직접 연결됩니다

익명 ID는 로컬스토리지에 저장되어 브라우저를 닫아도 유지됩니다. 사용자가 로그인하지 않아도 여러 세션에 걸쳐 행동을 추적할 수 있습니다.

7. 레코드 생성 — createRecord(data)

클라이언트에서 직접 새로운 CRM 레코드를 생성할 수 있습니다.

파라미터

{
  "entityId": {
    "type": "string",
    "description": "개체 ID (선택, 없으면 init()의 기본값 사용)"
  },
  "name": {
    "type": "string",
    "description": "레코드 이름 (필수)"
  },
  "data": {
    "type": "object",
    "description": "레코드 속성 (선택)"
  },
  "tags": {
    "type": "string[]",
    "description": "태그 목록 (선택)"
  }
}
// 회원가입 폼 제출 시
async function handleSignup(formData) {
  try {
    const record = await SolapiCRM.createRecord({
      entityId: 'CRMRC1_contacts',
      name: formData.name,
      data: {
        email: formData.email,
        phone: formData.phone,
        company: formData.company,
        source: 'website_signup'
      },
      tags: ['new_user', 'trial']
    });

    console.log('Created record:', record.recordId);
    SolapiCRM.identify(record.recordId);
  } catch (error) {
    console.error('Failed to create record:', error);
  }
}

레코드 생성 기능을 사용하려면 추적 키에 createRecords 권한이 활성화되어 있어야 합니다.

8. 슈퍼 프로퍼티 — register() / registerOnce() / unregister()

슈퍼 프로퍼티는 모든 track() 호출에 자동으로 포함되는 전역 속성입니다.

register(properties) — 전역 속성 등록

SolapiCRM.register({
  plan: 'premium',
  region: 'ko-KR',
  appVersion: '2.1.0'
});

// 이후 모든 track()에 자동 포함됨
SolapiCRM.track('VIEW_PAGE');
// → properties: { plan: 'premium', region: 'ko-KR', appVersion: '2.1.0' }

registerOnce(properties) — 한 번만 등록

이미 존재하는 속성은 덮어쓰지 않습니다. 첫 방문 시점의 정보를 보존하는 데 유용합니다.

SolapiCRM.registerOnce({
  initialLandingPage: window.location.href,
  initialReferrer: document.referrer,
  firstVisit: new Date().toISOString()
});

unregister(propertyName) — 속성 제거

SolapiCRM.unregister('plan');

9. 프라이버시 제어

GDPR, CCPA 등의 개인정보 보호 규정을 준수하기 위한 추적 거부 기능을 제공합니다.

// 추적 거부
SolapiCRM.optOutTracking();

// 추적 허용 (다시 활성화)
SolapiCRM.optInTracking();

// 추적 거부 상태 확인
if (SolapiCRM.hasOptedOut()) {
  console.log('사용자가 추적을 거부했습니다.');
}

EU 지역 사용자에게는 추적 시작 전에 명시적인 동의를 받아야 합니다. 기본적으로 optOutTracking() 상태로 시작하고, 사용자가 동의한 후 optInTracking()을 호출하세요.

10. 세션 관리

reset() — 세션 초기화

새로운 익명 ID를 생성하고 모든 슈퍼 프로퍼티를 초기화합니다. 로그아웃 시 사용하세요.

function handleLogout() {
  SolapiCRM.reset();
  window.location.href = '/login';
}

flush() — 이벤트 즉시 전송

큐에 있는 모든 이벤트를 즉시 서버로 전송합니다.

// 구매 완료 후 즉시 전송
SolapiCRM.track('PURCHASE', { orderId: 'ORD_123', amount: 159000 });
await SolapiCRM.flush();
window.location.href = '/order-complete';

destroy() — SDK 완전 정리

SDK를 완전히 정리합니다. 이벤트 전송, 타이머 정지, History API 복원, 이벤트 리스너 제거 등 모든 작업을 수행합니다.

await SolapiCRM.destroy();

11. 보안 설정

허용 도메인 (Allowed Domains)

{
  "example.com": {
    "description": "example.com만 허용"
  },
  "*.example.com": {
    "description": "모든 서브도메인"
  },
  "localhost:3000": {
    "description": "로컬 개발 환경"
  },
  "설정 안 함": {
    "description": "모든 도메인 허용"
  }
}

권한 설정

  • trackEvents: 이벤트 추적 (track(), trackPageView(), identify()) 허용

  • createRecords: 레코드 생성 (createRecord()) 허용

환경별 키 분리

const trackingKey = process.env.NODE_ENV === 'production'
  ? 'tk_live_production_key'
  : 'tk_test_development_key';

SolapiCRM.init({
  trackingKey,
  entityId: 'CRMRC1_contacts',
  debug: process.env.NODE_ENV !== 'production'
});

추적 키 (tk_live_xxx)와 SOLAPI API 키 (NCSxxx...)는 다릅니다. API 키는 절대 클라이언트 코드에 포함하면 안 됩니다.

12. 트러블슈팅

{
  "SolapiCRM is not defined": {
    "cause": "CDN 스크립트 미로드",
    "solution": "CDN URL 확인, 스크립트 순서 확인"
  },
  "이벤트 미수집": {
    "cause": "init() 미호출 또는 키 오류",
    "solution": "debug: true로 로그 확인"
  },
  "401 Unauthorized": {
    "cause": "추적 키 무효/폐기",
    "solution": "키 활성 상태 확인, 새 키 생성"
  },
  "403 Forbidden": {
    "cause": "도메인 미허용",
    "solution": "허용 도메인 목록 확인"
  },
  "SPA 페이지뷰 미수집": {
    "cause": "autoPageView 비활성",
    "solution": "autoPageView: true 설정"
  },
  "이벤트 중복 전송": {
    "cause": "init() 중복 호출",
    "solution": "앱에서 한 번만 호출"
  }
}

디버그 모드 활성화

SolapiCRM.init({
  trackingKey: 'tk_test_xxx',
  entityId: 'CRMRC1_contacts',
  debug: true
});

// 콘솔 출력 예시:
// [SolapiCRM] Initialized with trackingKey: tk_test_***
// [SolapiCRM] Track event: BUTTON_CLICK
// [SolapiCRM] Flushing 1 events...
// [SolapiCRM] Events sent successfully

13. FAQ

Q: 추적 키를 클라이언트 코드에 노출해도 안전한가요? 네, 안전합니다. 추적 키는 쓰기 전용이며, 허용 도메인 검증과 권한 제한으로 보호됩니다.

Q: 여러 개체(Entity)에 이벤트를 추적할 수 있나요? 네, init()에서 기본 개체를 설정하고, track() 호출 시 entityId 옵션으로 다른 개체를 지정할 수 있습니다.

Q: 이벤트가 실시간으로 전송되나요? 아니요, 이벤트는 배치로 전송됩니다. 실시간 전송이 필요한 경우 SolapiCRM.flush()를 호출하세요.

Q: 익명 사용자의 이벤트는 얼마나 보관되나요? 90일간 보관됩니다. 90일 내에 identify()를 호출하면 알려진 레코드로 병합됩니다.

Q: 모바일 앱에서도 사용할 수 있나요? 현재 SDK는 웹 브라우저 전용입니다. 모바일 앱에서는 REST API를 직접 호출하세요.

Q: 이벤트 이름 규칙이 있나요? 공식 규칙은 없지만 대문자 + 언더스코어를 권장합니다. (예: BUTTON_CLICK, VIEW_PRODUCT, ADD_TO_CART)