Optimizely Connector
เชื่อมต่อ Optimizely Feature Experimentation กับ Brevo ผ่าน Tajo เพื่อซิงค์ผลการทดสอบ กำหนดเป้าหมายแคมเปญตาม feature flag segments และเพิ่มความสมบูรณ์ให้กับระบบอัตโนมัติทางการตลาดด้วยข้อมูล A/B test และข้อมูลเชิงลึก audience
ภาพรวม
| คุณสมบัติ | ค่า |
|---|---|
| แพลตฟอร์ม | Optimizely |
| หมวดหมู่ | Experimentation (แบบกำหนดเอง) |
| ความซับซ้อนในการตั้งค่า | ปานกลาง |
| การผสานรวมอย่างเป็นทางการ | ไม่ |
| ข้อมูลที่ซิงค์ | การทดสอบ Audiences เหตุการณ์ Feature Flags |
| วิธีการยืนยันตัวตน | Personal Access Token / OAuth 2.0 |
ฟีเจอร์
- การซิงค์การทดสอบ - ส่งการกำหนด variation ของ A/B test ไปยังแอตทริบิวต์ผู้ติดต่อ Brevo
- การกำหนดเป้าหมาย audience - ใช้ Optimizely audiences สำหรับการแบ่งกลุ่มแคมเปญ Brevo
- การติดตาม conversion - ติดตามเหตุการณ์ Optimizely และแมปกับการติดตามเหตุการณ์ Brevo
- การซิงค์ feature flag - แบ่งกลุ่มผู้ติดต่อตาม feature flags ที่เปิดใช้งาน
- รายงานผล - ซิงค์ผลการทดสอบสำหรับแคมเปญการตลาดหลังการวิเคราะห์
- รองรับหลายโปรเจกต์ - เชื่อมต่อหลาย Optimizely projects กับ Tajo instance เดียว
ข้อกำหนดเบื้องต้น
ก่อนเริ่มต้น ตรวจสอบให้แน่ใจว่าคุณมี:
- บัญชี Optimizely Feature Experimentation
- Personal Access Token จาก Optimizely App Settings
- SDK key สำหรับ environment Optimizely ของคุณ
- บัญชี Brevo ที่มีสิทธิ์เข้าถึง API
- บัญชี Tajo ที่มีสิทธิ์ connector
การยืนยันตัวตน
Personal Access Token
# Generate at https://app.optimizely.com/v2/accountsettings/tokensexport OPTIMIZELY_ACCESS_TOKEN=your_personal_access_tokenexport OPTIMIZELY_SDK_KEY=your_sdk_keyexport TAJO_API_KEY=your_tajo_api_keyexport BREVO_API_KEY=your_brevo_api_key// All REST API requests use Bearer token authconst headers = { 'Authorization': `Bearer ${process.env.OPTIMIZELY_ACCESS_TOKEN}`, 'Content-Type': 'application/json'};การยืนยันตัวตน SDK
// For feature flag evaluation, use the SDKconst optimizelySDK = require('@optimizely/optimizely-sdk');
const optimizelyClient = optimizelySDK.createInstance({ sdkKey: process.env.OPTIMIZELY_SDK_KEY, datafileOptions: { autoUpdate: true, updateInterval: 60000 // 1 minute }});
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 * * *" # Every 2 hours
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_DATEAPI Endpoints
| Endpoint | เมธอด | คำอธิบาย |
|---|---|---|
https://api.optimizely.com/v2/projects | GET | แสดงรายการโปรเจกต์ |
https://api.optimizely.com/v2/experiments | GET | แสดงรายการการทดสอบ |
https://api.optimizely.com/v2/experiments/{id} | GET | ดูรายละเอียดการทดสอบ |
https://api.optimizely.com/v2/experiments/{id}/results | GET | ดูผลการทดสอบ |
https://api.optimizely.com/v2/features | GET | แสดงรายการ feature flags |
https://api.optimizely.com/v2/features/{id} | GET | ดู feature flag |
https://api.optimizely.com/v2/audiences | GET | แสดงรายการ audiences |
https://api.optimizely.com/v2/events | GET | แสดงรายการเหตุการณ์ที่ติดตาม |
https://logx.optimizely.com/v1/events | POST | ติดตามเหตุการณ์ (SDK endpoint) |
ตัวอย่างโค้ด
เริ่มต้น Connector
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
// Track experiment decisions and sync to Brevoconst optimizelyClient = optimizelySDK.createInstance({ sdkKey: process.env.OPTIMIZELY_SDK_KEY});
await optimizelyClient.onReady();
// Register a decision notification listeneroptimizelyClient.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() } }); } } });ซิงค์ผลการทดสอบ
// Fetch experiment results and sync winning segmentsconst resultsResponse = await fetch( `https://api.optimizely.com/v2/experiments/${experimentId}/results`, { headers: { 'Authorization': `Bearer ${process.env.OPTIMIZELY_ACCESS_TOKEN}` } });
const results = await resultsResponse.json();
// Process variations and update contact segmentsfor (const variation of results.metrics) { const isWinner = variation.is_improvement && variation.statistical_significance >= 0.95;
if (isWinner) { // Create a Brevo segment for users in the winning variation console.log(`Winning variation: ${variation.variation_name}`); }}การแบ่งกลุ่มตาม Feature Flag
// Evaluate feature flags for user segmentationasync 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() } });}ขีดจำกัดอัตรา
| Endpoint | ขีดจำกัด | หมายเหตุ |
|---|---|---|
| REST API | 50 req/นาที | ต่อ personal access token |
| Results API | 10 req/นาที | Latency สูงกว่า queries หนักกว่า |
| SDK Event Dispatch | 10,000 เหตุการณ์/batch | ผ่าน SDK event processor |
| Datafile CDN | ไม่จำกัด | Cache พร้อม auto-updates |
Latency ของ Results API
Experiment Results API ประมวลผล datasets ขนาดใหญ่และอาจใช้เวลา 30+ วินาทีในการตอบสนอง ใช้ async polling หรือ caching เพื่อหลีกเลี่ยงการบล็อกแอปพลิเคชันของคุณ
การแก้ไขปัญหา
| ปัญหา | สาเหตุ | วิธีแก้ |
|---|---|---|
| 401 Unauthorized | Token หมดอายุ/ไม่ถูกต้อง | สร้าง Personal Access Token ใหม่ |
| SDK ไม่พร้อม | Datafile ไม่ได้โหลด | รอ promise onReady() ให้ resolve |
| ไม่มี decisions ที่บันทึก | Notification ไม่ได้ลงทะเบียน | ลงทะเบียน listener ก่อนทำ decisions |
| Feature flags เก่า | Datafile cache | ตั้งค่า updateInterval สำหรับ auto-refresh |
| ผลหายไป | การทดสอบยังไม่เริ่ม | ตรวจสอบสถานะการทดสอบว่า “running” |
โหมด Debug
connectors: optimizely: debug: true log_level: verbose log_decisions: true log_events: trueแนวทางปฏิบัติที่ดีที่สุด
- ใช้ SDK สำหรับ decisions - ใช้ SDK สำหรับการประเมิน flag แบบเรียลไทม์ REST API สำหรับการจัดการ
- ใช้ event batching - Batch SDK events เพื่อลด network overhead
- Cache the datafile - เปิดใช้ auto-update พร้อมช่วงเวลาที่เหมาะสม
- ซิงค์ variations ที่ชนะ - หลังจากการทดสอบสิ้นสุด อัปเดต contact segments
- ใช้ attributes สำหรับการกำหนดเป้าหมาย - ส่งอีเมลและ user attributes สำหรับการจับคู่ audience
- ตรวจสอบสถานะการทดสอบ - ซิงค์เฉพาะข้อมูลจากการทดสอบที่กำลังดำเนินการหรือสิ้นสุดแล้ว
ความปลอดภัย
- Personal Access Tokens - การยืนยันตัวตน Bearer token สำหรับ REST API
- การแยก SDK key - SDK keys แยกต่างหากต่อ environment (dev, staging, prod)
- การประเมินฝั่งเซิร์ฟเวอร์ - ประเมิน feature flags ฝั่งเซิร์ฟเวอร์เพื่อป้องกันการเปิดเผย
- การหมุนเวียน token - หมุนเวียน Personal Access Tokens เป็นระยะ
- สิทธิ์ขั้นต่ำ - ใช้ tokens แบบ read-only เมื่อไม่ต้องการสิทธิ์การเขียน
- การส่งข้อมูลที่เข้ารหัส - TLS 1.2+ สำหรับการสื่อสาร API และ SDK ทั้งหมด