Optimizely Connector

Connect Optimizely Feature Experimentation to Brevo through Tajo to sync experiment results, target campaigns by feature flag segments, and enrich marketing automations with A/B test data and audience insights.

Overview

PropertyValue
PlatformOptimizely
CategoryExperimentation (Custom)
Setup ComplexityMedium
Official IntegrationNo
Data SyncedExperiments, Audiences, Events, Feature Flags
Auth MethodPersonal Access Token / OAuth 2.0

Features

  • Experiment sync - Push A/B test variation assignments to Brevo contact attributes
  • Audience targeting - Use Optimizely audiences for Brevo campaign segmentation
  • Conversion tracking - Track Optimizely events and map to Brevo event tracking
  • Feature flag sync - Segment contacts by enabled feature flags
  • Results reporting - Sync experiment results for post-analysis marketing campaigns
  • Multi-project support - Connect multiple Optimizely projects to a single Tajo instance

Prerequisites

Before you begin, ensure you have:

  1. An Optimizely Feature Experimentation account
  2. A Personal Access Token from Optimizely App Settings
  3. An SDK key for your Optimizely environment
  4. A Brevo account with API access
  5. A Tajo account with connector permissions

Authentication

Personal Access Token

Terminal window
# Generate at 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
// All REST API requests use Bearer token auth
const headers = {
'Authorization': `Bearer ${process.env.OPTIMIZELY_ACCESS_TOKEN}`,
'Content-Type': 'application/json'
};

SDK Authentication

// For feature flag evaluation, use the SDK
const 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();

Configuration

Basic Setup

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

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 Endpoints

EndpointMethodDescription
https://api.optimizely.com/v2/projectsGETList projects
https://api.optimizely.com/v2/experimentsGETList experiments
https://api.optimizely.com/v2/experiments/{id}GETGet experiment details
https://api.optimizely.com/v2/experiments/{id}/resultsGETGet experiment results
https://api.optimizely.com/v2/featuresGETList feature flags
https://api.optimizely.com/v2/features/{id}GETGet feature flag
https://api.optimizely.com/v2/audiencesGETList audiences
https://api.optimizely.com/v2/eventsGETList tracked events
https://logx.optimizely.com/v1/eventsPOSTTrack events (SDK endpoint)

Code Examples

Initialize 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'
});

Sync Experiment Decisions to Brevo

// Track experiment decisions and sync to Brevo
const optimizelyClient = optimizelySDK.createInstance({
sdkKey: process.env.OPTIMIZELY_SDK_KEY
});
await optimizelyClient.onReady();
// Register a decision notification listener
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()
}
});
}
}
}
);

Sync Experiment Results

// Fetch experiment results and sync winning segments
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();
// Process variations and update contact segments
for (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-Based Segmentation

// Evaluate feature flags for user segmentation
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()
}
});
}

Rate Limits

EndpointLimitNotes
REST API50 req/minPer personal access token
Results API10 req/minHigher latency, heavier queries
SDK Event Dispatch10,000 events/batchVia SDK event processor
Datafile CDNUnlimitedCached with auto-updates

Results API Latency

The Experiment Results API processes large datasets and can take 30+ seconds to respond. Use async polling or caching to avoid blocking your application.

Troubleshooting

IssueCauseSolution
401 UnauthorizedToken expired/invalidRegenerate Personal Access Token
SDK not readyDatafile not loadedWait for onReady() promise to resolve
No decisions loggedNotification not registeredRegister listener before making decisions
Stale feature flagsDatafile cacheSet updateInterval for auto-refresh
Missing resultsExperiment not startedVerify experiment status is “running”

Debug Mode

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

Best Practices

  1. Use the SDK for decisions - Use the SDK for real-time flag evaluation, REST API for management
  2. Implement event batching - Batch SDK events to reduce network overhead
  3. Cache the datafile - Enable auto-update with appropriate intervals
  4. Sync winning variations - After experiments conclude, update contact segments
  5. Use attributes for targeting - Pass email and user attributes for audience matching
  6. Monitor experiment status - Only sync data from running or concluded experiments

Security

  • Personal Access Tokens - Bearer token authentication for REST API
  • SDK key isolation - Separate SDK keys per environment (dev, staging, prod)
  • Server-side evaluation - Evaluate feature flags server-side to prevent exposure
  • Token rotation - Rotate Personal Access Tokens periodically
  • Minimal permissions - Use read-only tokens when write access is not needed
  • Encrypted transport - TLS 1.2+ for all API and SDK communications

Open-Source Implementation Map

This section is derived from official or public repository material discovered for the Optimizely connector. Use it as the engineering companion to the setup guide above: it shows where the API surface lives, what implementation assets exist, and how Tajo should translate them into reliable Brevo sync behavior.

Repository Snapshot

RepositoryCommitLanguages / formatsFiles
optimizely/agent7841eceGo (124), Python (30), Markdown (12), YAML (8), sh (8), YAML (5)206

Integration Shape

graph LR
Source["Optimizely API / repository"] --> Auth["Auth and scopes"]
Source --> Objects["Objects, events, and schemas"]
Auth --> Tajo["Tajo connector runtime"]
Objects --> Tajo
Tajo --> Brevo["Brevo contacts, attributes, lists, campaigns"]
Tajo --> Ops["Backfill, cursor, retries, logs"]

What To Reuse

  • Optimizely Agent
  • This repository houses the Optimizely Agent service for use with Optimizely Feature Experimentation and Optimizely Full Stack (legacy).
  • Get Started
  • Refer to the Agent’s developer documentation for detailed instructions on getting started with using the SDK.
  • Requirements

Tajo Revamp Checklist

  • Keep authentication setup aligned with the vendor docs and the public repository’s current API shape.
  • Map primary resources into explicit Tajo sync objects with stable external IDs.
  • Prefer cursor-based or updated-at incremental sync where the API exposes it; otherwise document the fallback.
  • Treat webhook handlers as idempotent and replay-safe, especially for order, contact, ticket, and campaign events.
  • Capture pagination, rate limits, retry headers, and partial-failure behavior in connector smoke tests.
  • Keep examples small and runnable against sandbox or test-mode accounts.

Sources

Subscribe to updates

developer-docs

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

auto-detect
AI Assistant

Hi! Ask me anything about the docs.