API Communication & Tracking

How the SDK fetches config and sends tracking events

Welcome back! In RuleManager, we saw how the SDK acts like a bouncer, checking if visitors meet specific criteria before they can participate in an experiment. We've covered how the SDK manages visitors, experiments, features, data, bucketing, and rules internally.

But how does the SDK get the initial setup information (like the details of your experiments and those rules) from Convert's servers? And how does it report back what happened (like which variation a visitor saw, or if they completed a goal)?

The Problem: Talking to the Outside World

Imagine the Convert SDK running in your application is like a local branch office. It needs to:

  1. Get Instructions: Receive the latest operational plan (your project configuration, including experiments, features, audiences) from the headquarters (Convert servers).
  2. Send Reports: Send status updates (tracking events like "visitor A saw variation B", "visitor C completed goal X") back to headquarters so you can see the results in your Convert dashboard.

How does this local branch office (the SDK) communicate reliably with headquarters (Convert servers)?

What is ApiManager? The SDK's Messenger

Meet the ApiManager! Think of it as the dedicated messenger or communication link between the Convert SDK running in your application and the Convert backend servers.

Its primary jobs are:

  1. Fetching the Project Plan (getConfig): When the SDK starts up (ConvertSDK / Core), if you provided an sdkKey, the ApiManager is responsible for contacting the Convert servers and downloading the necessary project configuration data (all your experiments, features, rules, etc.).
  2. Sending Tracking Reports (enqueue, releaseQueue): When the SDK makes a decision (like assigning a visitor to a variation using the BucketingManager) or tracks a conversion, the DataManager tells the ApiManager about it. The ApiManager doesn't send a separate message for every single event. Instead, it acts efficiently:
    • Collects Messages: It gathers these small tracking reports into a queue.
    • Sends in Batches: It sends these collected reports back to the Convert tracking servers in batches. This is much more efficient than sending dozens of tiny messages individually.

In short, ApiManager handles all the "talking" the SDK needs to do with the external Convert platform.

How it's Used (Mostly Behind the Scenes)

Like several other managers (ExperienceManager, BucketingManager, RuleManager), you'll rarely interact directly with the ApiManager. It's mainly used internally by other core components:

  • By Core: During initialization, the Core class uses the ApiManager's getConfig() method to fetch the project configuration if an sdkKey was provided.

    Conceptually, during configuration fetching, the Core calls the ApiManager's getConfig method. If the call succeeds, the received data is processed and stored. If it fails, the error is handled appropriately.

  • By DataManager: When the DataManager records a bucketing decision or a conversion event, it doesn't send it immediately. It tells the ApiManager to add the event to its queue using enqueue().

    Conceptually, during bucketing retrieval, the DataManager first performs the bucketing logic to determine a chosen variation. It stores the decision locally via putData. Then, if tracking is enabled, it creates an event data object and calls the ApiManager's enqueue method with the visitor ID and event data.

So, ApiManager is the behind-the-scenes worker handling the communication initiated by other parts of the SDK.

Under the Hood: How Communication Works

Let's look at the two main tasks: fetching data and sending tracking.

1. Fetching Configuration (getConfig)

  • When Core calls apiManager.getConfig(), the ApiManager prepares and sends an HTTP GET request.
  • Target: It sends the request to the Convert configuration endpoint URL. The URL includes identifiers such as the sdkKey or accountId/projectId (e.g., https://cdn.convert.com/config/YOUR_SDK_KEY or https://cdn-4.convertexperiments.com/api/v1/config/{accountId}/{projectId}).
  • Response: The Convert server responds with a large JSON object containing all the details about your project (experiences, features, audiences, goals, etc.).
  • Result: The ApiManager receives this JSON data and passes it back to the Core, which then gives it to the DataManager for storage.
sequenceDiagram
    participant Core as ConvertSDK / Core
    participant ApiMgr as ApiManager
    participant ConvertAPI as Convert Config API

    Core->>+ApiMgr: getConfig()
    Note over ApiMgr: Prepare HTTP GET request for config endpoint
    ApiMgr->>+ConvertAPI: GET /config/{identifier}
    ConvertAPI-->>-ApiMgr: Respond with Project JSON data
    ApiMgr-->>-Core: Return Project JSON data

2. Sending Tracking Events (enqueue and releaseQueue)

This is a bit more complex because of the batching mechanism.

  • Step 1: Enqueue: When DataManager calls apiManager.enqueue(visitorId, eventData), the ApiManager doesn't send anything yet. It simply adds the eventData (like a conversion or bucketing event) to an internal queue associated with the visitorId. It also increments a counter for the queue length.

  • Step 2: Check Batch Conditions: After adding the event, ApiManager checks whether the queue size has reached the batchSize limit (default: 10 events). If so, it calls releaseQueue immediately.

  • Step 3: Trigger Release: How the queue is released when the batch size is not reached depends on the platform (see Platform-Specific Differences below). The key point is that accumulated events will always be flushed eventually — either by a timer or at the end of the request lifecycle.

  • Step 4: Send Batch (releaseQueue): When releaseQueue is called:

    • It copies the current contents of the queue.
    • It resets the internal queue so new events can be collected.
    • It packages the copied events into a payload suitable for the Convert tracking API.
    • It sends this payload as an HTTP POST request to the Convert tracking endpoint URL (like https://track.convert.com/track/YOUR_SDK_KEY).
sequenceDiagram
    participant DataMgr as DataManager
    participant ApiMgr as ApiManager
    participant ConvertAPI as Convert Track API

    DataMgr->>+ApiMgr: enqueue(visitor1, event1)
    Note over ApiMgr: Add event1 to queue. Queue size = 1.
    DataMgr->>+ApiMgr: enqueue(visitor2, event2)
    Note over ApiMgr: Add event2 to queue. Queue size = 2.
    DataMgr->>+ApiMgr: enqueue(visitor1, event3)
    Note over ApiMgr: Add event3 to visitor1's events. Queue size = 3.
    loop When batch is full OR flush is triggered
        ApiMgr->>ApiMgr: releaseQueue() triggered
        Note over ApiMgr: Copy queue items. Reset queue.
        Note over ApiMgr: Prepare HTTP POST payload with queued events.
        ApiMgr->>+ConvertAPI: POST /track/{identifier} (payload)
        ConvertAPI-->>-ApiMgr: Acknowledge receipt (e.g., HTTP 200 OK)
        ApiMgr-->>ApiMgr: Handle response (log success/error)
    end

This batching ensures the SDK doesn't overload the network with too many small requests, improving performance.

Key Implementation Details

1. Constructor / Initialization

The ApiManager is initialized with configuration that includes:

  • API Endpoints: The config endpoint (for fetching project data) and the track endpoint (for sending events). Defaults are provided if not specified in configuration.
  • Batch Settings: The batchSize (default: 10) controls how many events accumulate before an automatic flush.
  • SDK Key / Project ID: Used to construct API paths.
  • Tracking Toggle: Tracking can be disabled via configuration.
  • Base Tracking Payload: A template structure containing the accountId, projectId, and a visitors array that gets populated with queued events at flush time.
  • Internal Queue: An object or array that stores pending events, with methods to push new items and reset.

2. Fetching Configuration (getConfig)

The getConfig method constructs a path from the config endpoint base URL and the SDK key (or account/project identifiers), then performs an HTTP GET request. The JSON response data is extracted and returned to the caller.

3. Enqueuing Tracking Events (enqueue)

The enqueue method adds the event to the internal queue. It then checks if tracking is enabled and if the queue length has reached the batchSize. If the batch size is reached, releaseQueue is called immediately. Otherwise, the platform-specific flush mechanism handles it (timer or shutdown handler).

4. Releasing the Queue (releaseQueue)

The releaseQueue method:

  • Returns early if the queue is empty or tracking is disabled.
  • Copies the current queue items into a tracking payload that includes the base tracking information (account ID, project ID) plus the visitor events.
  • Resets the queue before sending, so new events arriving during the network request are added to a fresh queue.
  • Sends the payload as an HTTP POST to the tracking endpoint.
  • Handles errors by logging them. On success, a system event may be fired to notify other components.

Platform-Specific Differences

AspectBrowser / Node.js (JS SDK)Server-side (PHP SDK)
Queue flush trigger (non-full batch)A timer (setTimeout) starts when the first event is enqueued. If the release interval (default: 10 seconds) elapses before the batch fills, the queue is flushed automatically.No timers. A shutdown handler (register_shutdown_function) flushes all remaining events when the request ends. Under PHP-FPM, fastcgi_finish_request() sends the HTTP response to the client first, so flushing adds no user-visible latency.
Release intervalConfigurable (default: 10,000 ms). The timer is started/stopped as events are enqueued and flushed.Not applicable. Events accumulate during a single request and are sent in one batch at the very end.
HTTP clientBuilt-in HttpClient utility (uses fetch, XMLHttpRequest, or equivalent). In browsers, may use navigator.sendBeacon() for reliability when the user navigates away.PSR-18 compatible HTTP client, auto-discovered via php-http/discovery or provided via dependency injection.
Retry logicBasic error handling with logging. Retry/backoff logic is a potential future enhancement.Automatic retries on 5xx/network errors: up to 2 retries with backoff delays of 100ms and 300ms. Does NOT retry on 4xx client errors.
Timer managementstartQueue() and stopQueue() methods manage the release interval timer.No timer management methods — unnecessary in a request-scoped execution model.

Conclusion

The ApiManager is the vital communication link between the Convert SDK operating in the user's environment and the Convert backend servers. It acts as the messenger, responsible for:

  1. Fetching the project configuration (getConfig) when the SDK initializes (if using an sdkKey).
  2. Collecting and Batching tracking events (enqueue).
  3. Sending these batched events (releaseQueue) efficiently back to Convert for reporting.

While you don't usually call its methods directly, understanding the ApiManager helps clarify how the SDK gets its instructions and reports results back to your Convert dashboard. It relies on batching and platform-appropriate flush mechanisms to do this efficiently.

We've now seen how most of the core managers interact and rely on each other. But how do these components signal to each other when something important happens, like when the configuration data has been successfully fetched and the SDK is ready? For internal communication, the SDK uses an event system.

Let's explore this internal notification system next: EventManager!