Edge Support

Learn how to configure the VWO FE JavaScript SDK for edge computing environments like Cloudflare Workers, Vercel Edge Functions, and AWS Lambda@Edge.

Overview

Modern edge platforms such as Cloudflare Workers, Vercel Edge Functions, and AWS Edge runtimes are optimized for low-latency, short-lived execution. While these environments provide excellent performance, they introduce unique challenges for SDK initialization and configuration management.

The VWO Feature Experimentation (FE) JavaScript SDK is fully compatible with edge environments. However, to achieve optimal performance and avoid unnecessary network calls, settings management must be handled differently than in traditional long-running servers.

Supported edge platforms include:

  • Cloudflare Workers
  • Vercel Edge Functions
  • AWS Lambda@Edge
  • Netlify Edge Functions
  • Deno Deploy
  • Fastly Compute@Edge
  • and other similar edge environments

This document explains:

  1. Why default SDK initialization can be inefficient on edge
  2. How to fetch, cache, and reuse settings
  3. How to use explicit settings injection
  4. How to leverage the getSettings / setSettings storage connector APIs
  5. Recommended patterns for enterprise-scale deployments

For further details on the VWO FE JavaScript SDK, including specific configuration examples and advanced usage, refer to the VWO JavaScript SDK Documentation.

Default SDK Initialization (Not Recommended for Edge)

By default, the SDK fetches settings during initialization:

await VWO.init({
  sdkKey: 'SDK_KEY',
  accountId: 'ACCOUNT_ID'
});

What Happens Internally

  • SDK makes a network request to VWO servers
  • Settings are fetched on every worker execution
  • No reuse unless the runtime keeps the worker warm

Impact

  • Redundant network calls
  • Increased tail latency
  • Inefficient for high-traffic edge workloads

Why Edge Environments Need Special Handling

Edge platforms introduce several behavioral constraints that impact any SDK performing remote calls (like tracking events):

  1. Stateless, Ephemeral Execution:
    1. Each invocation starts from a clean slate.
    2. In-memory variables may not persist.
    3. Persistence must rely on external storage (KV, Redis, etc.).
    4. Any pending asynchronous operations (e.g., tracking calls) can be terminated early if not awaited properly.
  2. Strict Execution Time Budgets:
    1. Many edge runtimes terminate execution immediately after returning a response, unless you explicitly signal that work is still pending.
    2. Cold starts are common
  3. Non-blocking HTTP Requests:
    1. All tracking calls are asynchronous and risk being dropped if the runtime ends the execution loop early.

Therefore, edge runtimes must explicitly flush tracking events before your function exits.


SDK Configuration for Edge Environments

Use the edgeConfig option when initializing the VWO SDK inside any edge runtime.

Parameter: edgeConfig

The edgeConfig option should only be used in serverless/edge environments (e.g., Cloudflare Workers, Vercel Edge Functions, AWS Lambda@Edge).

ParameterDescriptionTypeDefaultRecommended Value in Edge
shouldWaitForTrackingCallsEnsures SDK waits for async tracking operationsBooleantruetrue

Why It Matters

With edgeConfig, core methods like getFlag, trackEvent, and setAttribute resolve quickly, while the actual tracking calls are deferred and handled when you call flushEvents.

🚧

Important Note

When using edgeConfig, you must call await flushEvents() at the end of your code flow to send tracking events to VWO for reporting purposes.


Essential Rule for Edge Environments

Always call vwoClient.flushEvents() before your function exits.

If events are not flushed, they may be dropped entirely.

Edge platforms provide different mechanisms to wait for async operations:

  • Cloudflare Workers: ctx.waitUntil(vwoClient.flushEvents)
  • Vercel Edge / Fastly: waitUntil(vwoClient.flushEvents)
  • Other platforms: standard await vwoClient.flushEvents()

Quick Start Configuration

Looking for platform-specific setup instructions?

Example Configuration

Here's how you can configure the SDK to work properly in an edge environment:

const { init } = require('vwo-fme-node-sdk');

// Initialize VWO client with Edge environment support
async function main() {
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
    // Edge configuration for serverless environments
    edgeConfig: {
      shouldWaitForTrackingCalls: true
    }
  });

  const userContext = { id: 'unique_user_id' };

  // Check if feature is enabled for the user
  const flag = await vwoClient.getFlag('feature_key', userContext);

  if (flag.isEnabled()) {
    console.log('Feature is enabled!');
    // Get feature variable
    const value = flag.getVariable('feature_variable', 'default_value');
    console.log('Variable value:', value);
  }

  // Track an event
  await vwoClient.trackEvent('event_name', userContext);

  // IMPORTANT: Flush events before function exits
  await vwoClient.flushEvents();
}

main();

Code Breakdown

  • init({ edgeConfig: { shouldWaitForTrackingCalls: true } }): Configures the SDK for edge environments.
  • getFlag, trackEvent, and setAttribute: These methods return much faster when using edgeConfig.
  • flushEvents(): Required - Call this at the end of your function to send all tracking events.
  • Graceful fallback for variables: Always provide a default value to getVariable() to handle missing configurations.

Flushing Events in Edge Environments

When using edgeConfig, you must call flushEvents() at the end of your function to send tracking events to VWO.

Basic Usage

// At the end of your edge function, before returning
await vwoClient.flushEvents();

Recommended Approach for Edge: Cached Settings

Key Idea

Fetch settings once, cache them, and reuse them across SDK initializations.

This can be achieved in two ways:

  • Explicit settings injection
  • Custom storage connector with getSettings / setSettings

Option 1: Explicit SDK Settings Injection

VWO supports initializing the SDK with pre-fetched settings, completely skipping the network call.

Reference: https://developers.vwo.com/v2/docs/fme-explicit-sdk-fetch-settings

Example

Fetch and Cache Settings (One-Time or Periodic)

const response = await fetch(
  `https://dev.visualwebsiteoptimizer.com/server-side-settings?a=${ACCOUNT_ID}&i=${SDK_KEY}`
);

const settings = await response.json();

// Store in KV, Redis, etc.
await KV.put(`vwo_settings_${ACCOUNT_ID}_${SDK_KEY}`, JSON.stringify(settings));

Initialize SDK with Cached Settings

const cachedSettings = await KV.get(`vwo_settings_${ACCOUNT_ID}_${SDK_KEY}`);

await init({
  accountId: ACCOUNT_ID,
  sdkKey: SDK_KEY,
  settings: JSON.parse(cachedSettings)
});

Benefits

  • Zero network calls during request handling.
  • Predictable latency.
  • Full control over refresh strategy.

When to Use

  • You already have a background job or cron job.
  • You want explicit control over the settings lifecycle.
  • Highly regulated or locked-down environments.

Lifecycle

  • VWO Settings API
  • Fetch Once (Background / Cron / First Request)
  • Store in Edge KV / Redis / Durable Store
  • Inject into SDK on init()

Option 2 (Recommended): Custom Storage Connector with getSettings / setSettings

To simplify settings management, the FE SDK now supports settings persistence directly via the storage connector.

Reference: https://developers.vwo.com/v2/docs/fme-javascript-storage#how-to-implement-a-custom-storage-connector

Why This Is Better

  • No manual settings injection needed
  • SDK automatically:
    • Reads cached settings via getSettings
    • Stores fetched settings via setSettings
  • Cleaner, more maintainable integration
  • Ideal for enterprise edge deployments

Lifecycle

  • SDK initializes
  • SDK calls getSettings()
  • If settings exist → use them
  • If not → fetch from VWO servers
  • SDK calls setSettings() to persist them

Platform-Specific Guidance

Cloudflare Workers

Cloudflare worker terminates execution immediately after returning a response. Use ctx.waitUntil() to keep async work alive. To know more about waitUntil, refer to the official docs here

export default {
  async fetch(request, env, ctx) {
    const vwoClient = await init({
      accountId: env.VWO_ACCOUNT_ID,
      sdkKey: env.VWO_SDK_KEY,
      edgeConfig: {
        shouldWaitForTrackingCalls: true,
      },
    });

    const userContext = { id: 'user123' };
    
    // Your application logic
    const flag = await vwoClient.getFlag('feature_key', userContext);
    await vwoClient.trackEvent('event_name', userContext);
    
    // CRITICAL: Flush events using ctx.waitUntil in Cloudflare
    ctx.waitUntil(vwoClient.flushEvents());
    
    return new Response('OK');
  }
}

Vercel

Similar to Cloudflare, Vercel Edge requires waitUntil(). To know more about waitUntil(), check the official docs here.

import { init } from 'vwo-fme-node-sdk';
import { waitUntil } from '@vercel/functions';

export default async function handler(req, res) {
    const vwoClient = await init({
      accountId: '123456',
      sdkKey: '32-alpha-numeric-sdk-key',
      edgeConfig: {
        shouldWaitForTrackingCalls: true,
      },
    });

    const userContext = { id: 'user123' };
    
    // Your application logic
    const flag = await vwoClient.getFlag('feature_key', userContext);
    await vwoClient.trackEvent('event_name', userContext);
    
    // CRITICAL: Flush events using waitUntil in vercel
    waitUntil(vwoClient.flushEvents());
    
    return res.status(200).json({status: 'success'})
  }
}

Other Edge Environments

If the platform does not provide “background work” helpers, simply await the flush call::

export default async function handler(request) {
  const vwoClient = await init({
    accountId: '123456',
    sdkKey: '32-alpha-numeric-sdk-key',
    edgeConfig: {
      shouldWaitForTrackingCalls: true,
    },
  });

  const userContext = { id: 'user123' };
  const flag = await vwoClient.getFlag('feature_key', userContext);
  await vwoClient.trackEvent('event_name', userContext);

  // REQUIRED: Flush events before returning
  await vwoClient.flushEvents();

  return new Response('OK');
}

Example: Edge KV-Based Storage Connector

Custom Storage Connector

const storageConnector = {
  async getSettings(accountId, sdkKey) {
    const key = `vwo_settings_${accountId}_${sdkKey}`;
    const cached = await KV.get(key);
    return cached ? JSON.parse(cached) : null;
  },

  async setSettings({ settings }) {
    const key = `vwo_settings_${settings.accountId}_${settings.sdkKey}`;
    await KV.put(key, JSON.stringify(settings), {
      expirationTtl: 3600 * 12 // 12 hours
    });
  }
};

SDK Initialization

await init({
  accountId: ACCOUNT_ID,
  sdkKey: SDK_KEY,
  storage: storageConnector
});

Best Practices

  • ✔ Use edgeConfig: Optimizes performance and defers tracking calls for batch flushing.
  • ✔ Always call flushEvents(): Ensures event delivery before function termination.
  • ✔ Use Cloudflare/Vercel waitUntil(): Prevents event loss after response is returned.
  • ✔ Reuse the SDK instance: Place initialization at the module level to reduce cold-start overhead.
  • ✔ Keep user IDs stable: User identity consistency ensures correct bucketing.
  • ✔ Monitor execution time: Most edge runtimes enforce 50ms–100ms budgets.
  • ✔ Add error handling: Wrap flush calls in try/catch (optional but recommended).

By following this guide, you can confidently deploy the VWO FE JavaScript SDK to distributed, edge platforms while preserving the integrity of your feature flagging and experimentation data.