Skip to content
Ahmed Abbas edited this page Apr 23, 2025 · 2 revisions

Chapter 1: ConvertSDK / Core

Welcome to the Convert Javascript SDK! This guide will help you understand how to use the SDK to run A/B tests, feature flags, and personalization on your website or application.

Let's start at the very beginning. Imagine you want to test two different headlines on your homepage to see which one attracts more user sign-ups. How do you manage this experiment, show the right headline to the right user, and track the results? That's where the Convert SDK comes in, and the first piece we need to understand is the main entry point.

What is ConvertSDK / Core?

Think of the ConvertSDK object (which is built upon the Core class) as the conductor of an orchestra. It's the main starting point you'll interact with when you first use the SDK.

Just like a conductor:

  1. Gets the Music Sheet (Configuration): It takes your initial setup instructions (like your unique project key, called sdkKey) when it starts.
  2. Gathers the Musicians (Managers): It creates and organizes all the specialized helper components (we call them "Managers," like the DataManager or ExperienceManager) needed to run experiments.
  3. Starts the Performance (Initialization): It fetches the necessary experiment data from Convert servers (if you provided an sdkKey) or uses data you provide directly.
  4. Directs the Sections (Provides Context): It allows you to create specific "sessions" for each visitor to your site, ensuring they see the correct variations and their actions are tracked properly. We call these sessions Context objects.

In short, ConvertSDK / Core is the central hub that initializes everything and gives you the tools to interact with individual users.

Getting Started: Initializing the SDK

Let's tackle our headline A/B test use case. The very first step is to tell the SDK who we are and let it set itself up. We do this by creating an instance of ConvertSDK.

  1. Import the SDK: First, you need to bring the ConvertSDK class into your code.

    // In your Javascript file (e.g., main.js or app.js)
    import ConvertSDK from '@convertcom/js-sdk';
    • This line imports the main class we need from the installed SDK package.
  2. Create an Instance: Now, create a new SDK object, providing your unique sdkKey. You can find your sdkKey in your Convert account settings.

    // Replace 'YOUR_SDK_KEY' with the actual key from your Convert project
    const config = {
      sdkKey: 'YOUR_SDK_KEY'
      // You can add other configuration options here later
    };
    
    const convert = new ConvertSDK(config);
    
    console.log('Convert SDK instance created. Initializing...');
    • We define a config object containing our sdkKey.
    • new ConvertSDK(config) creates the main SDK object. This automatically starts the process of fetching your experiment data from Convert servers in the background.
  3. Wait for it to be Ready: Since fetching data takes a little time, the SDK provides a way to know when it's ready to be used.

    convert.onReady().then(() => {
      console.log('Convert SDK is ready!');
      // Now you can start creating contexts for visitors
    }).catch(error => {
      console.error('Error initializing Convert SDK:', error);
    });
    • convert.onReady() returns a Promise that resolves when the SDK has successfully fetched the initial data and is set up.
    • The .then() block runs your code after the SDK is ready.
    • The .catch() block handles any errors during initialization (e.g., invalid sdkKey, network issues).

Now the SDK is initialized! It has fetched the details about your headline A/B test (and any other experiments you have active).

Creating a Visitor Context

The ConvertSDK object itself doesn't represent a single visitor. It's the overall manager. To work with a specific visitor (like someone who just landed on your homepage), you need to create a Context object for them.

// Assuming 'convert' is your initialized SDK instance from the previous step

// Let's say a visitor arrives with ID 'user123'
const visitorId = 'user123';

// Optional: You might know some things about the visitor
const visitorAttributes = {
  browser: 'chrome',
  device: 'desktop',
  country: 'USA'
};

// Create a context for this specific visitor
const visitorContext = convert.createContext(visitorId, visitorAttributes);

if (visitorContext) {
  console.log(`Context created for visitor: ${visitorId}`);
  // In the next chapter, we'll see how to use visitorContext
  // to get experiment variations (like which headline to show).
} else {
  console.log('SDK not ready yet, could not create context.');
}
  • convert.createContext(visitorId, visitorAttributes) is the key method here. It takes a unique ID for the visitor and optional attributes.
  • It returns a new Context object, tailor-made for that visitor. We'll explore this object in detail in the next chapter.

What Happens Under the Hood?

When you call new ConvertSDK(config), a sequence of events unfolds internally:

  1. Configuration: The SDK reads the config object you provided. It sets defaults for any options you didn't specify.
  2. Manager Creation: The ConvertSDK constructor creates instances of various specialized managers:
    • LogManager: Handles logging messages.
    • EventManager: Manages internal events (like READY).
    • ApiManager: Handles communication with the Convert API (like fetching data).
    • DataManager: Stores and provides access to the fetched experiment data.
    • RuleManager: Processes targeting rules (audiences, segments).
    • BucketingManager: Assigns visitors to specific variations.
    • ExperienceManager: Helps retrieve variation details for A/B tests.
    • FeatureManager: Helps manage feature flags (covered later).
    • SegmentsManager: Evaluates visitor segments.
  3. Initialization Logic (Core.initialize):
    • If an sdkKey is present in the config, it tells the ApiManager to start fetching the configuration data from Convert's servers.
    • If a data object is directly provided in the config instead of an sdkKey, it uses that data immediately, skipping the fetch.
  4. Data Fetching (Core.fetchConfig):
    • The ApiManager makes a network request.
    • Once data arrives, it's given to the DataManager.
    • The EventManager fires the READY event (or CONFIG_UPDATED on subsequent fetches).
    • A timer is set to periodically refresh the data in the background.
  5. Ready State: The onReady() promise resolves, letting your code know it's safe to proceed.

Here's a simplified diagram of the initialization flow using sdkKey:

sequenceDiagram
    participant UserCode as Your Code
    participant SDK as ConvertSDK / Core
    participant ApiMgr as ApiManager
    participant DataMgr as DataManager
    participant EventMgr as EventManager

    UserCode->>+SDK: new ConvertSDK({ sdkKey: '...' })
    SDK->>+ApiMgr: Create ApiManager instance
    SDK->>+DataMgr: Create DataManager instance
    SDK->>+EventMgr: Create EventManager instance
    Note right of SDK: Other managers also created...
    SDK->>SDK: initialize(config)
    SDK->>+ApiMgr: getConfig() // Start fetching
    ApiMgr->>ApiMgr: Fetch data from Convert API...
    ApiMgr-->>-SDK: Returns Promise<data>
    SDK->>SDK: await data
    SDK->>+DataMgr: Set received data
    DataMgr-->>-SDK: SDK->>+EventMgr: fire(SystemEvents.READY)
    EventMgr-->>-SDK: Note left of UserCode: Meanwhile, UserCode calls onReady()
    UserCode->>SDK: onReady()
    SDK-->>UserCode: Returns Promise
    Note right of EventMgr: READY event triggers resolution
    UserCode-->>UserCode: Promise resolves, .then() block runs
Loading

Let's look at snippets of the actual code involved:

1. The ConvertSDK Constructor (index.ts)

This is where the managers are created and passed to the Core class constructor (super(...)).

// File: packages/js-sdk/index.ts

// ... imports ...
import {Core} from './src/core';
import {ApiManager} from '@convertcom/js-sdk-api';
// ... other manager imports ...
import {Config} from './src/config';

class ConvertSDK extends Core {
  constructor(config: ConfigType = <ConfigType>{}) {
    // ... config validation ...

    const configuration = Config(config); // Process config
    const loggerManager = new LogManager(/*...*/);
    const eventManager = new EventManager(/*...*/);
    const apiManager = new ApiManager(configuration, { /*...*/ }); // Create ApiManager
    const bucketingManager = new BucketingManager(/*...*/);
    const ruleManager = new RuleManager(/*...*/);
    const dataManager = new DataManager(configuration, { /*...*/ }); // Create DataManager
    // ... create other managers ...

    // Call the Core constructor with config and all managers
    super(configuration, {
      dataManager,
      eventManager,
      experienceManager,
      featureManager,
      segmentsManager,
      apiManager,
      loggerManager
    });
  }
  // ... onReady method ...
}
  • This sets up all the necessary helper ("manager") classes.
  • It then calls super(...), which is the constructor of the Core class it extends.

2. The Core Constructor and initialize (core.ts)

The Core class receives the managers and kicks off the initialization.

// File: packages/js-sdk/src/core.ts

import {ApiManagerInterface} from '@convertcom/js-sdk-api';
// ... other imports ...

export class Core implements CoreInterface {
  // ... properties like _dataManager, _apiManager, etc. ...
  private _config: Config;
  private _initialized: boolean;

  constructor(
    config: Config,
    { /* managers passed from ConvertSDK */ }
  ) {
    // Store references to all the managers
    this._dataManager = dataManager;
    this._eventManager = eventManager;
    this._apiManager = apiManager;
    // ... store other managers ...
    this._loggerManager?.trace?.('Core()', MESSAGES.CORE_CONSTRUCTOR, this);
    this.initialize(config); // Start initialization
  }

  private initialize(config: Config): void {
    this._config = config;
    if (config.sdkKey?.length) {
      // If sdkKey is provided, fetch data
      this.fetchConfig();
    } else if (config.data) {
      // If data object is provided, use it directly
      this._dataManager.data = config.data;
      this._eventManager.fire(SystemEvents.READY, null, null, true);
      this._initialized = true;
    } else {
      // Handle error: Neither sdkKey nor data provided
      this._loggerManager?.error?.(/* ... */);
    }
  }
  // ... other methods like fetchConfig, createContext ...
}
  • The constructor stores the managers it receives.
  • It calls initialize, which checks if it needs to fetch data (fetchConfig()) or use provided data.

3. Fetching Configuration (core.ts)

The fetchConfig method uses the ApiManager to get data.

// File: packages/js-sdk/src/core.ts

// Inside the Core class:
  private async fetchConfig(): Promise<void> {
    try {
      // Use the ApiManager to get config data
      const data: ConfigResponseData = await this._apiManager.getConfig();

      if (data['error']) {
         // Handle API errors
         this._loggerManager?.error?.(/* ... */);
      } else {
        // Success! Fire event and store data
        this._eventManager.fire(/* READY or CONFIG_UPDATED */);
        this.data = data;
        this._dataManager.data = data; // Update DataManager
        this._apiManager.setData(data); // Update ApiManager (optional)
        this._initialized = true;
      }
      // Schedule the next refresh
      this._fetchConfigTimerID = setTimeout(
        () => this.fetchConfig(),
        this._config?.dataRefreshInterval || DEFAULT_DATA_REFRESH_INTERVAL
      ) as any;
    } catch (error) {
      this._loggerManager?.error?.('Core.fetchConfig()', { error: error.message });
    }
  }
  • It calls this._apiManager.getConfig().
  • On success, it updates the DataManager and fires the appropriate event via the EventManager.
  • It uses setTimeout to automatically fetch updates later.

Conclusion

You've learned about the ConvertSDK / Core, the central hub for the Javascript SDK. It acts like an orchestra conductor, initializing the system with your configuration, managing all the specialized helper modules (managers), fetching necessary data, and providing the crucial createContext method to handle individual visitor interactions.

We saw how to:

  1. Import the SDK.
  2. Create an instance using your sdkKey.
  3. Wait for it to be ready using onReady().
  4. Use createContext() to get a visitor-specific object.

Now that we have our SDK initialized and know how to create a context for a visitor, the next logical step is to understand what we can do with that context.

Ready to dive deeper? Let's explore the Context object in the next chapter!

Clone this wiki locally