A TypeScript-based edge computing solution that delivers A/B testing and feature flagging capabilities directly at the CDN edge, providing ultra-low latency decisions and seamless content personalization.
- Edge Mode: Automatic request interception for transparent content personalization
- Agent Mode: RESTful API endpoints for programmatic feature flag decisions
- Cloudflare Workers - Native Workers runtime support
- Vercel Edge Functions - Next.js middleware integration
- Fastly Compute@Edge - WebAssembly-optimized deployment
- Extensible Architecture - Plugin system for additional platforms
- Sub-50ms Decision Times - Cached decisions at the edge
- Automatic Failover - Graceful degradation and error recovery
- Real-time Configuration - Dynamic updates without redeployment
- Comprehensive Metrics - Built-in observability and monitoring
- Security-First Design - Request validation and content protection
- Quick Start
- Architecture Overview
- Operating Modes
- API Reference
- Platform Deployment
- Configuration
- Monitoring & Metrics
- Documentation
- Development
- Contributing
# Cloudflare Workers
npm create cloudflare@latest my-edge-agent -- --template=optimizely-edge-agent
# Vercel Edge Functions
npx create-next-app@latest my-edge-agent --template=optimizely-edge-agent
# Fastly Compute@Edge
fastly compute init --from=optimizely/edge-agent-template
// Minimal required configuration
const config = {
sdkKey: 'your-optimizely-sdk-key', // Required
enableEdgeMode: true, // Enable automatic request handling
enableAgentMode: true // Enable API endpoints
};
# Test a decision API call
curl -X POST https://your-domain.com/api/decide \
-H "Content-Type: application/json" \
-H "X-Optimizely-Enable-FEX: true" \
-H "X-Optimizely-SDK-Key: your-sdk-key" \
-d '{"userId": "user123", "flagKey": "my_feature"}'
# Test automatic edge mode (GET request)
curl https://your-domain.com/your-page
# β Automatically applies variations based on URL patterns
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Optimizely Edge Agent v2 β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ βββββββββββββββββββββββββββ β
β β Edge Mode β β Agent Mode β β
β β β β β β
β β β’ URL Matching β β β’ REST API Endpoints β β
β β β’ Auto Decisionsβ β β’ /api/decide β β
β β β’ Content Trans β β β’ /api/datafile β β
β β β’ Cache Control β β β’ /api/admin/* β β
β βββββββββββββββββββ βββββββββββββββββββββββββββ β
β β β β
β ββββββββββ΄βββββββββββββββββββββββββββββββββββββ΄βββββββββββββ β
β β Core Services Layer β β
β β β β
β β βββββββββββββββ ββββββββββββββββ βββββββββββββββββββββββ β β
β β β Decision β β Configurationβ β Storage β β β
β β β Service β β Service β β Service β β β
β β βββββββββββββββ ββββββββββββββββ βββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β β
β ββββββββββ΄βββββββββββββββββββββββββββββββββββββ΄βββββββββββββ β
β β Platform Adapters β β
β β β β
β β βββββββββββββββ ββββββββββββββββ βββββββββββββββββββββββ β β
β β β Cloudflare β β Vercel β β Fastly β β β
β β β Workers β β Edge Functionsβ β Compute@Edge β β β
β β βββββββββββββββ ββββββββββββββββ βββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Transparently intercepts web requests and serves content based on experimentation decisions:
// Edge mode intercepts requests and uses cdnVariationSettings to determine content source
// Example cdnVariationSettings from a feature flag variable:
{
"cdnVariationSettings": {
"cdnExperimentURL": "https://example.com/home", // URL pattern to match
"cdnResponseURL": "https://example.com/home-variant", // Alternative content source
"cacheKey": "home_variant_a", // Cache identifier
"cacheTTL": 3600, // Cache duration in seconds
"forwardRequestToOrigin": "true", // Whether to fetch from origin
"cacheRequestToOrigin": "true", // Whether to cache origin response
"isControlVariation": "false" // Control vs treatment indicator
}
}
When a user visits yoursite.com/home
:
- Edge Agent intercepts the request
- Evaluates the relevant feature flag(s) for this URL
- Retrieves the
cdnVariationSettings
from the decision - Based on settings, either:
- Serves content from cache (if available and not expired)
- Fetches content from the configured
cdnResponseURL
- Forwards to origin server if
forwardRequestToOrigin
is true
- Caches the response according to
cacheTTL
settings
Key Point: Edge Mode does NOT transform content. It determines which content to serve (origin vs alternative URLs) based on the cdnVariationSettings
variable in your feature flags.
Programmatic access for applications and services:
# Single flag decision
POST /api/decide
{
"flagKey": "checkout_flow",
"userId": "user123",
"attributes": { "plan": "premium" }
}
# Multiple flag decisions
POST /api/decide-for-keys
{
"flagKeys": ["feature_a", "feature_b", "feature_c"],
"userId": "user123"
}
# All flags decision
POST /api/decide-all
{
"userId": "user123",
"decideOptions": ["ENABLED_FLAGS_ONLY"]
}
Endpoint | Method | Description |
---|---|---|
/api/decide |
GET/POST | Single feature flag decision |
/api/decide-all |
GET/POST | All feature flags decisions |
/api/decide-for-keys |
GET/POST | Multiple specific flags decisions |
/api/decide-options |
GET/POST | Available decision options |
Endpoint | Method | Description |
---|---|---|
/api/datafile |
GET/PUT/POST | Optimizely datafile management |
/api/flagkeys |
GET/PUT/POST | Feature flag keys management |
/api/sdk |
GET | SDK and version information |
Endpoint | Method | Description |
---|---|---|
/api/set-forced-variation |
POST/PUT | Force specific variations |
/api/get-forced-variation |
GET/POST | Retrieve forced variations |
/api/debug |
POST | Debug configuration and state |
Complete API documentation: API Reference
# Deploy to Cloudflare
npx wrangler deploy
# Configure environment variables
npx wrangler secret put OPTIMIZELY_SDK_KEY
npx wrangler secret put OPTIMIZELY_ADMIN_TOKEN
Features: KV Store integration, Analytics Engine metrics, global edge network
// middleware.ts
import { createVercelHandler } from '@optimizely/edge-agent';
export default async function middleware(request: NextRequest) {
const handler = createVercelHandler(process.env);
return await handler.handleRequest(request);
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)']
};
Features: Next.js integration, Edge Config, global edge deployment
# Deploy to Fastly
fastly compute publish
# Configure secrets
fastly secret-store create --name optimizely-secrets
fastly secret-store-entry create --store-id=<store-id> --name=sdk-key
Features: WebAssembly performance, advanced VCL integration, enterprise features
Complete deployment guides: CDN Adapters Guide
# Required
OPTIMIZELY_SDK_KEY=your-sdk-key
# Optional - Feature Control
OPTIMIZELY_ENABLE_EDGE_MODE=true
OPTIMIZELY_ENABLE_AGENT_MODE=true
OPTIMIZELY_LOG_LEVEL=warn
# Optional - Performance
OPTIMIZELY_CACHE_TTL=300
OPTIMIZELY_AUTO_DATAFILE_UPDATES=true
# Optional - Security
OPTIMIZELY_ADMIN_TOKEN=your-admin-token
OPTIMIZELY_ENABLE_DEBUG_HEADERS=false
Configuration precedence (highest to lowest):
- HTTP Headers -
X-Optimizely-SDK-Key: override-key
- Query Parameters -
?sdkKey=test-key
- Request Body -
{"sdkKey": "body-key"}
- Environment Variables -
OPTIMIZELY_SDK_KEY=env-key
- Default Values - Built-in secure defaults
Complete configuration guide: Configuration Guide
Universal Support: DataDog, New Relic, Prometheus adapters available for Vercel & Fastly.
- Request Metrics: API calls, durations, success rates
- Decision Metrics: Flag evaluations, bucketing performance
- Cache Metrics: Hit/miss rates, storage efficiency
- Error Metrics: Classified errors with detailed context
# Quick Setup - Choose your provider
METRICS_PROVIDER=datadog # Options: prometheus, datadog, newrelic
# DataDog (Recommended)
DD_API_KEY=your-api-key
DD_ENV=production
# New Relic
NEW_RELIC_LICENSE_KEY=your-license-key
# Prometheus
PROMETHEUS_PUSH_GATEWAY_URL=http://your-pushgateway:9091
// Universal metrics interface works across all providers
metrics.recordTiming('decision_duration', 45);
metrics.incrementCounter('api_requests', { endpoint: 'decide' });
metrics.setGauge('cache.hit_rate', 0.95);
Complete metrics documentation: Metrics Guide
Our comprehensive documentation covers every aspect of the Edge Agent:
Category | Status | Description |
---|---|---|
API Reference | β Complete | All endpoints, parameters, examples |
Architecture | β Complete | System design, request lifecycle |
CDN Adapters | β Complete | Platform-specific deployment |
Configuration | β Complete | All settings and options |
Metrics | β Complete | Monitoring and observability |
- Quick Start Guide - Get running in 5 minutes
- Migration Guide - Upgrade from v1 to v2
- Troubleshooting - Common issues and solutions
- Development Guide - Local setup and contribution
- Examples - Real-world implementation patterns
- Security Guide - Best practices and considerations
# Install dependencies
npm install
# Run tests
npm test
# Run specific test suites
npm run test:unit
npm run test:integration
npm run test:e2e
# Build for all platforms
npm run build
npm run build:cloudflare
npm run build:vercel
npm run build:fastly
# Test against live deployment
curl -X POST https://your-deployment.com/api/decide \
-H "Content-Type: application/json" \
-H "X-Optimizely-Enable-FEX: true" \
-H "X-Optimizely-SDK-Key: your-key" \
-d '{"userId": "test", "flagKey": "test_flag"}'
We welcome contributions! Please see our Contributing Guide for:
- Code style and standards
- Testing requirements
- Pull request process
- Issue reporting guidelines
This project is licensed under the MIT License - see the LICENSE file for details.
- Documentation: Complete docs in
/docs-sot/
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Ready to get started? Jump to our Quick Start Guide or explore the complete documentation for in-depth guidance.