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

Request early access

Share your first name and an email address or phone number. We will follow up with Tajo access details.

automatic detection
AI Assistant

Hi! Ask me anything about the docs.