Optimizely 连接器
通过 Tajo 将 Optimizely Feature Experimentation 连接到 Brevo,同步实验结果,按功能标志细分目标活动,并用 A/B 测试数据和受众洞察丰富营销自动化。
概览
| 属性 | 值 |
|---|---|
| 平台 | Optimizely |
| 类别 | 实验(自定义) |
| 设置复杂度 | 中等 |
| 官方集成 | 否 |
| 同步数据 | 实验、受众、事件、功能标志 |
| 认证方式 | 个人访问令牌 / OAuth 2.0 |
功能
- 实验同步 - 将 A/B 测试变体分配推送到 Brevo 联系人属性
- 受众定向 - 使用 Optimizely 受众进行 Brevo 活动细分
- 转化跟踪 - 追踪 Optimizely 事件并映射到 Brevo 事件追踪
- 功能标志同步 - 按已启用的功能标志细分联系人
- 结果报告 - 同步实验结果,用于实验后营销活动分析
- 多项目支持 - 将多个 Optimizely 项目连接到单个 Tajo 实例
前提条件
开始之前,请确保您已具备:
- Optimizely Feature Experimentation 账户
- 来自 Optimizely 应用设置 的个人访问令牌
- 您的 Optimizely 环境 SDK 密钥
- 具有 API 访问权限的 Brevo 账户
- 具有连接器权限的 Tajo 账户
认证
个人访问令牌
# 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 端点
| 端点 | 方法 | 描述 |
|---|---|---|
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 | 列出功能标志 |
https://api.optimizely.com/v2/features/{id} | GET | 获取功能标志 |
https://api.optimizely.com/v2/audiences | GET | 列出受众 |
https://api.optimizely.com/v2/events | GET | 列出追踪事件 |
https://logx.optimizely.com/v1/events | POST | 追踪事件(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
// 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}`); }}基于功能标志的细分
// 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() } });}速率限制
| 端点 | 限制 | 说明 |
|---|---|---|
| REST API | 50 请求/分钟 | 每个人访问令牌 |
| 结果 API | 10 请求/分钟 | 延迟较高,查询较重 |
| SDK 事件分发 | 每批 10,000 个事件 | 通过 SDK 事件处理器 |
| 数据文件 CDN | 无限制 | 带自动更新的缓存 |
结果 API 延迟
实验结果 API 处理大型数据集,响应可能需要 30 秒以上。使用异步轮询或缓存以避免阻塞应用程序。
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 401 Unauthorized | 令牌过期/无效 | 重新生成个人访问令牌 |
| SDK 未就绪 | 数据文件未加载 | 等待 onReady() Promise 解析 |
| 未记录决策 | 未注册通知 | 在做出决策前注册监听器 |
| 功能标志陈旧 | 数据文件缓存 | 设置 updateInterval 自动刷新 |
| 结果缺失 | 实验未启动 | 验证实验状态为”running” |
调试模式
connectors: optimizely: debug: true log_level: verbose log_decisions: true log_events: true最佳实践
- 使用 SDK 进行决策 - SDK 用于实时标志评估,REST API 用于管理
- 实施事件批处理 - 批量 SDK 事件以减少网络开销
- 缓存数据文件 - 以适当间隔启用自动更新
- 同步获胜变体 - 实验结束后,更新联系人细分
- 使用属性进行定向 - 传递邮箱和用户属性以进行受众匹配
- 监控实验状态 - 只同步正在运行或已结束的实验数据
安全
- 个人访问令牌 - REST API 的 Bearer 令牌认证
- SDK 密钥隔离 - 每个环境(开发、测试、生产)使用独立 SDK 密钥
- 服务端评估 - 服务器端评估功能标志以防止暴露
- 令牌轮换 - 定期轮换个人访问令牌
- 最小权限 - 不需要写入权限时使用只读令牌
- 加密传输 - 所有 API 和 SDK 通信使用 TLS 1.2+