Optimizely 커넥터

Tajo를 통해 Optimizely Feature Experimentation을 Brevo에 연결하여 실험 결과를 동기화하고, 기능 플래그 세그먼트별로 캠페인을 타겟팅하며, A/B 테스트 데이터와 오디언스 인사이트로 마케팅 자동화를 강화하십시오.

개요

속성
플랫폼Optimizely
카테고리실험 (Custom)
설정 복잡도중간
공식 통합아니오
동기화 데이터실험, 오디언스, 이벤트, 기능 플래그
인증 방법개인 액세스 토큰 / OAuth 2.0

기능

  • 실험 동기화 - A/B 테스트 변형 할당을 Brevo 연락처 속성으로 푸시
  • 오디언스 타겟팅 - Optimizely 오디언스를 Brevo 캠페인 세그먼테이션에 사용
  • 전환 추적 - Optimizely 이벤트를 추적하고 Brevo 이벤트 추적에 매핑
  • 기능 플래그 동기화 - 활성화된 기능 플래그별로 연락처 세그먼트화
  • 결과 보고 - 실험 후 분석 마케팅 캠페인을 위해 실험 결과 동기화
  • 다중 프로젝트 지원 - 여러 Optimizely 프로젝트를 단일 Tajo 인스턴스에 연결

사전 요구 사항

시작하기 전에 다음이 준비되어 있는지 확인하십시오.

  1. Optimizely Feature Experimentation 계정
  2. Optimizely 앱 설정의 개인 액세스 토큰
  3. Optimizely 환경의 SDK 키
  4. API 접근이 가능한 Brevo 계정
  5. 커넥터 권한이 있는 Tajo 계정

인증

개인 액세스 토큰

Terminal window
# https://app.optimizely.com/v2/accountsettings/tokens 에서 생성
export OPTIMIZELY_ACCESS_TOKEN=your_personal_access_token
export OPTIMIZELY_SDK_KEY=your_sdk_key
export TAJO_API_KEY=your_tajo_api_key
export BREVO_API_KEY=your_brevo_api_key
// 모든 REST API 요청은 Bearer 토큰 인증 사용
const headers = {
'Authorization': `Bearer ${process.env.OPTIMIZELY_ACCESS_TOKEN}`,
'Content-Type': 'application/json'
};

SDK 인증

// 기능 플래그 평가를 위해 SDK 사용
const optimizelySDK = require('@optimizely/optimizely-sdk');
const optimizelyClient = optimizelySDK.createInstance({
sdkKey: process.env.OPTIMIZELY_SDK_KEY,
datafileOptions: {
autoUpdate: true,
updateInterval: 60000 // 1분
}
});
await optimizelyClient.onReady();

구성

기본 설정

connectors:
optimizely:
enabled: true
access_token: "${OPTIMIZELY_ACCESS_TOKEN}"
sdk_key: "${OPTIMIZELY_SDK_KEY}"
project_id: "12345678"
sync:
experiments: true
audiences: true
events: true
feature_flags: true
schedule: "0 */2 * * *" # 2시간마다
mapping:
experiment_variation: EXPERIMENT_VARIATION
feature_flags: ENABLED_FEATURES
audience_segments: OPT_SEGMENTS

필드 매핑

field_mapping:
user_id: email
experiment_key: EXPERIMENT_NAME
variation_key: VARIATION_NAME
feature_key: FEATURE_FLAG
enabled: FEATURE_ENABLED
audience_name: AUDIENCE_SEGMENT
decision_timestamp: EXPERIMENT_DATE

API 엔드포인트

엔드포인트메서드설명
https://api.optimizely.com/v2/projectsGET프로젝트 목록
https://api.optimizely.com/v2/experimentsGET실험 목록
https://api.optimizely.com/v2/experiments/{id}GET실험 세부 정보 가져오기
https://api.optimizely.com/v2/experiments/{id}/resultsGET실험 결과 가져오기
https://api.optimizely.com/v2/featuresGET기능 플래그 목록
https://api.optimizely.com/v2/features/{id}GET기능 플래그 가져오기
https://api.optimizely.com/v2/audiencesGET오디언스 목록
https://api.optimizely.com/v2/eventsGET추적된 이벤트 목록
https://logx.optimizely.com/v1/eventsPOST이벤트 추적 (SDK 엔드포인트)

코드 예제

커넥터 초기화

import { TajoClient } from '@tajo/sdk';
const tajo = new TajoClient({
apiKey: process.env.TAJO_API_KEY,
brevoApiKey: process.env.BREVO_API_KEY
});
await tajo.connectors.connect('optimizely', {
accessToken: process.env.OPTIMIZELY_ACCESS_TOKEN,
sdkKey: process.env.OPTIMIZELY_SDK_KEY,
projectId: '12345678'
});

실험 결정을 Brevo로 동기화

// 실험 결정을 추적하고 Brevo로 동기화
const optimizelyClient = optimizelySDK.createInstance({
sdkKey: process.env.OPTIMIZELY_SDK_KEY
});
await optimizelyClient.onReady();
// 결정 알림 리스너 등록
optimizelyClient.notificationCenter.addNotificationListener(
optimizelySDK.enums.NOTIFICATION_TYPES.DECISION,
async (decisionObject) => {
const { type, userId, attributes, decisionInfo } = decisionObject;
if (type === 'feature' || type === 'ab-test') {
const email = attributes.email;
if (email) {
await tajo.contacts.update(email, {
attributes: {
EXPERIMENT_NAME: decisionInfo.experimentKey || decisionInfo.featureKey,
VARIATION_NAME: decisionInfo.variationKey,
FEATURE_ENABLED: decisionInfo.featureEnabled || false,
EXPERIMENT_DATE: new Date().toISOString()
}
});
}
}
}
);

실험 결과 동기화

// 실험 결과를 가져오고 승리 세그먼트 동기화
const resultsResponse = await fetch(
`https://api.optimizely.com/v2/experiments/${experimentId}/results`,
{
headers: {
'Authorization': `Bearer ${process.env.OPTIMIZELY_ACCESS_TOKEN}`
}
}
);
const results = await resultsResponse.json();
// 변형 처리 및 연락처 세그먼트 업데이트
for (const variation of results.metrics) {
const isWinner = variation.is_improvement && variation.statistical_significance >= 0.95;
if (isWinner) {
// 승리 변형에 속한 사용자를 위한 Brevo 세그먼트 생성
console.log(`Winning variation: ${variation.variation_name}`);
}
}

기능 플래그 기반 세그먼테이션

// 사용자 세그먼테이션을 위한 기능 플래그 평가
async function syncFeatureFlags(userEmail, userId) {
const features = ['new_checkout', 'loyalty_program', 'ai_recommendations'];
const enabledFeatures = [];
for (const feature of features) {
const user = optimizelyClient.createUserContext(userId, {
email: userEmail
});
const decision = user.decide(feature);
if (decision.enabled) {
enabledFeatures.push(feature);
}
}
await tajo.contacts.update(userEmail, {
attributes: {
ENABLED_FEATURES: enabledFeatures.join(', '),
FEATURE_FLAGS_SYNCED: new Date().toISOString()
}
});
}

속도 제한

엔드포인트제한참고
REST API50 요청/분개인 액세스 토큰당
Results API10 요청/분더 높은 지연 시간, 무거운 쿼리
SDK 이벤트 디스패치10,000 이벤트/배치SDK 이벤트 프로세서를 통해
Datafile CDN무제한자동 업데이트로 캐싱됨

Results API 지연 시간

Experiment Results API는 대용량 데이터 세트를 처리하므로 응답에 30초 이상 걸릴 수 있습니다. 애플리케이션 차단을 피하려면 비동기 폴링이나 캐싱을 사용하십시오.

문제 해결

문제원인해결 방법
401 Unauthorized토큰 만료/잘못됨개인 액세스 토큰 재생성
SDK가 준비되지 않음Datafile이 로드되지 않음onReady() 프라미스가 해결될 때까지 대기
결정이 로깅되지 않음알림이 등록되지 않음결정을 내리기 전에 리스너 등록
오래된 기능 플래그Datafile 캐시자동 새로 고침을 위해 updateInterval 설정
결과 누락실험이 시작되지 않음실험 상태가 “running”인지 확인

디버그 모드

connectors:
optimizely:
debug: true
log_level: verbose
log_decisions: true
log_events: true

모범 사례

  1. 결정에 SDK 사용 - 실시간 플래그 평가에는 SDK, 관리에는 REST API 사용
  2. 이벤트 배치 처리 구현 - 네트워크 오버헤드를 줄이기 위해 SDK 이벤트 배치 처리
  3. Datafile 캐싱 - 적절한 간격으로 자동 업데이트 활성화
  4. 승리 변형 동기화 - 실험이 종료된 후 연락처 세그먼트 업데이트
  5. 타겟팅에 속성 사용 - 오디언스 매칭을 위해 이메일 및 사용자 속성 전달
  6. 실험 상태 모니터링 - 실행 중이거나 종료된 실험의 데이터만 동기화

보안

  • 개인 액세스 토큰 - REST API용 Bearer 토큰 인증
  • SDK 키 격리 - 환경별(dev, staging, prod) 별도의 SDK 키
  • 서버 측 평가 - 노출을 방지하기 위해 서버 측에서 기능 플래그 평가
  • 토큰 교체 - 개인 액세스 토큰을 주기적으로 교체
  • 최소 권한 - 쓰기 접근이 필요하지 않을 때는 읽기 전용 토큰 사용
  • 암호화된 전송 - 모든 API 및 SDK 통신에 TLS 1.2+ 사용

관련 리소스

Subscribe to updates

developer-docs

Drop your email or phone number — we'll send you what matters next.

auto-detect
AI 어시스턴트

안녕하세요! 문서에 대해 무엇이든 물어보세요.