Server-Side Testing with Omniconvert Explore

What is server-side testing?

Server-side A/B testing renders experiment variations directly on your web server, before the page is delivered to the client - unlike client-side testing, where variations are applied in the browser via JavaScript after the page loads.

Note

The Visual Editor and Preview are not available for server-side experiments, since there's no client-side page to visually edit.

Why use server-side testing?

Useful for deeper tests involving backend logic - pricing logic, checkout flow, algorithm changes, or anything else that isn't purely visual. It also significantly reduces the chance of flicker or visual loading issues, since nothing changes after the page has already rendered.

Explore provides an SDK to handle the experimentation logic and communication with the platform. Currently available for PHP (public package, installable via Composer), with TypeScript (Node), Java, Kotlin (Android), and Swift (iOS/macOS) also available.

Step 1 - Create the experiment

From the top left menu, open A/B Testing and select Server-Side Testing, then press Create an A/B test.

Fill in:

  • Title - the experiment's name.

  • URL - the page you're targeting.

  • Experiment Slug - a code-friendly identifier, useful for finding this experiment in your codebase.

  • Hypothesis - what you expect to happen.

Step 2 - Define variables and variations

Variables

In the Variables tab, define the information you want to transmit to your application - for example, product_title. Choose a Type for each variable.

Variations

As with a regular A/B test, create as many variations as you need. For each, specify a value for the variable(s) you've defined, and set a slug for the variation (via the pencil icon) - this is best practice, since you'll reference it in code.

Step 3 - Set the audience and segmentation

Choosing pages

Manage the pages where the experiment runs using the same URL conditions as a standard A/B test: URL is, URL is not, URL starts with, URL ends with, URL contains, URL does not contain, URL RegEx, or Page contains keyword. See Create an A/B Test for the full explanation of each.

Segment

By default, a new server-side experiment has no segment - press Select or create segment to set one.

To target all your traffic, create a segment using Count pageviews in current session → Greater than → 0.

Warning

Segments for server-side experiments are entirely separate from segments used in client-side experiments. To find them, switch from the Web section to the Server Side section under Advanced → Segments.

Device type

You can also filter by Device Type, so only visitors on a specific device are included.

Step 4 - Traffic allocation and goals

Traffic allocation

In Traffic Allocation & Goals, choose the percentage of your segment's visitors to include, then split that traffic between Control and Variation using the slider.

Goals

There are 3 default goal options: Sale, Engagement, and Bounce Rate, with Sale selected by default. Some goals require integration on your website before they'll record data. Add existing goals, create custom ones, or delete any you don't need.

You can also set a Goal Timeout - the window after which conversions stop being counted for this experiment.

Step 5 - Schedule and publish

Set the timeframe under Scheduling, with an option to be notified by email when it ends, and Excluded hours intervals for specific days or times.

Note

Scheduling dates and times are interpreted using your account's Display Timezone setting.

Choose Save & Continue or Publish.

Once your experiment is created, an API Settings section appears with an example of how to use the SDK. This example uses PHP; the same concepts apply across the other supported languages.

Step 6 - Install the SDK

For the PHP SDK we have a public package which is available here, and it can be installed easily with composer.


The command to install it is:

composer require mktz/server-side-testing-sdk

Get your API key

Click your website name to open the dropdown, then select API Credentials. If you don't have a key yet, press Generate API Key. You can rename the key's Label, then Copy it into your application.

Step 7 - Configure your application

Here's a full example configuration:

// Define app config
$userId = "900006";
$apiKey = 'xxxx';
$env = 'dev';

$storageFacade = StorageFacadeFactory::createWithDriver(
new RedisStorageDriver(new RedisConnection(new Redis(), new RedisConnectionConfig("127.0.0.1", 6379)))
);

$httpClient = new HttpClient($apiKey, 'https://app.omniconvert.com/', $env === 'dev');

$sessionParams = (new SessionParams())
->setReferrerUrl('https://www.omniconvert.com/')
->setReferrerDomain('www.omniconvert.com')
->setReferrerType('referral')
->setLandingUrl('https://www.omniconvert.com/')
->setDeviceType('desktop')
->setGa4TrackingId('G-000000000')
;
$userProvider = new UserProvider($storageFacade, $userId, $sessionParams);
$clientConfig = new ClientConfig($storageFacade);

// Step 2 - Initialize the client
$client = new ExploreClient(
$httpClient,
$storageFacade,
$userProvider,
$clientConfig
);

$context = ContextBuilder::create()
->url('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'])
->referrerType("referral")
->referrer("https://www.omniconvert.com/")
->ip("127.0.0.1")
->custom("vip_user", "yes")
->utm([
'source' => 'this_source',
'medium' => 'this_medium',
'campaign' => 'campaign_name',
'content' => 'content',
'term' => 'term',
])
->userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
->language("en-US")
->deviceType("desktop")
->resolution("1728x1117")
->browser("Chrome")
->browserLanguage("en-US")
->browserVersion("120.0.0.0")
->os("macOS")
->build()
;

What each part does

  • User ID - a unique identifier for the visitor. Use your own database's user ID if the visitor is logged in, or fall back to a PHP session ID or similar.

  • Storage - a Redis connection used to store visited experiments, user history, and cached experiment configuration, so the SDK doesn't need to call Explore on every request.

  • HTTP Client - handles communication with Explore, using your API Key, the endpoint, and a cache bypass flag.

  • Development: enable cache bypass, since the SDK caches responses for up to 5 minutes by default:

    $httpClient = new HttpClient($apiKey, "https://app.omniconvert.com/", $env === 'dev');
  • Production: disable cache bypass for better performance:

    $httpClient = new HttpClient($apiKey);
  • Session Parameters - optional context about the visitor's session; may be required depending on your use case. All parameters can be found here.

  • User Provider - built from the Storage, User ID, and Session Parameters above.

  • Context - parameters describing the current request: URL, referrer, IP, browser info, and more.

Step 8 - Get a decision from the SDK

Once the setup is complete, ask the SDK to make a decision: based on the previous parameters, which experiment should be shown to the user.

The SDK needs to process all the context and compare it to the experiment information you have set up, then provide a list of experiments to apply to the user:

$decisionList = $client->decide($context);

This returns a list of experiments and variations to apply. The SDK handles bucketing, segmentation, and audience matching for you - you only need to implement the resulting experiment logic:

$decisionList[0]->getVariation()
Note

The id or slug fields returned can be used as feature flags in your code, letting you conditionally apply changes per segment. The response also includes the experiment's defined variables with their resolved values, ready to use directly.

Step 9 - Track events and goals

The SDK provides helper functions for tracking pageviews, sale goals, and custom goals:

// Trigger goal with product SKUs
$details = [
"transaction" => "1555",
'skus' => ['PROD123', 'PROD456', 'PROD789']
];
$tracker->track("sale", 111, $details); // Required

// Track custom goal
$tracker->track("custom_goal", "custom_value");
Note

Explore only starts collecting data once the corresponding goal has actually been created in the platform.

Logging and debugging

Use the static getLogs function to retrieve SDK logs, which explain why an experiment was or wasn't selected for a given visitor - covering traffic allocation, evaluation, audience targeting, and bucketing decisions.

$logs = DefaultLogger::getLogs(DefaultLogger::LOG_LEVEL_KEY_ALL);
LoggerDumper::dump($logs);

Further resources

Updated