---
title: "Optimizely Connector"
description: "Complete Optimizely integration guide for syncing experiment results, feature flags, and audience data with Brevo through Tajo."
url: https://tajo.io/docs/connectors/custom/optimizely/
markdown: https://tajo.io/docs/connectors/custom/optimizely.md
lang: en-US
robots: noindex
---

# Optimizely Connector

Connector status: Planned Not built yet. Tajo does not run this connector today.

| Source field | Destination field | Sample value |
| --- | --- | --- |
| `record.id` | `source_id` | `record_1042` |
| `record.updated_at` | `updated_at` | `2026-10-18T08:00:00Z` |
| `record.value` | `value` | `sample_value` |

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

| Property | Value |
| --- | --- |
| **Platform** | Optimizely |
| **Category** | Experimentation (Custom) |
| **Setup Complexity** | Medium |
| **Official Integration** | No |
| **Data Synced** | Experiments, Audiences, Events, Feature Flags |
| **Auth Method** | Personal 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](https://app.optimizely.com/v2/accountsettings/tokens)
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

```bash
# 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
```

```javascript
// All REST API requests use Bearer token auth
const headers = {
  'Authorization': `Bearer ${process.env.OPTIMIZELY_ACCESS_TOKEN}`,
  'Content-Type': 'application/json'
};
```

### SDK Authentication

```javascript
// 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

```yaml
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

```yaml
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

| Endpoint | Method | Description |
| --- | --- | --- |
| `https://api.optimizely.com/v2/projects` | GET | List projects |
| `https://api.optimizely.com/v2/experiments` | GET | List experiments |
| `https://api.optimizely.com/v2/experiments/{id}` | GET | Get experiment details |
| `https://api.optimizely.com/v2/experiments/{id}/results` | GET | Get experiment results |
| `https://api.optimizely.com/v2/features` | GET | List feature flags |
| `https://api.optimizely.com/v2/features/{id}` | GET | Get feature flag |
| `https://api.optimizely.com/v2/audiences` | GET | List audiences |
| `https://api.optimizely.com/v2/events` | GET | List tracked events |
| `https://logx.optimizely.com/v1/events` | POST | Track events (SDK endpoint) |

## Code Examples

### Initialize Connector

```javascript
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

```javascript
// 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

```javascript
// 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

```javascript
// 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

| Endpoint | Limit | Notes |
| --- | --- | --- |
| REST API | 50 req/min | Per personal access token |
| Results API | 10 req/min | Higher latency, heavier queries |
| SDK Event Dispatch | 10,000 events/batch | Via SDK event processor |
| Datafile CDN | Unlimited | Cached 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

| Issue | Cause | Solution |
| --- | --- | --- |
| 401 Unauthorized | Token expired/invalid | Regenerate Personal Access Token |
| SDK not ready | Datafile not loaded | Wait for `onReady()` promise to resolve |
| No decisions logged | Notification not registered | Register listener before making decisions |
| Stale feature flags | Datafile cache | Set `updateInterval` for auto-refresh |
| Missing results | Experiment not started | Verify experiment status is “running” |

### Debug Mode

```yaml
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

## Related Resources

- [PostHog Connector](https://tajo.io/docs/connectors/custom/posthog)
- [Segment Connector](https://tajo.io/docs/connectors/custom/segment)
- [Customer Sync Skill](https://tajo.io/docs/skills/data-sync/customer-sync)
- [Optimizely Feature Experimentation Documentation](https://docs.developers.optimizely.com/feature-experimentation/docs)

## 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

| Repository | Commit | Languages / formats | Files |
| --- | --- | --- | --- |
| [optimizely/agent](https://github.com/optimizely/agent) | 7841ece | Go (124), Python (30), Markdown (12), YAML (8), sh (8), YAML (5) | 206 |

### Integration Shape

```mermaid
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

- [optimizely/agent](https://github.com/optimizely/agent)
- [Vendor documentation](https://docs.developers.optimizely.com/)
