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.
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.
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.
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()

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");
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
-
API Reference - full generated SDK documentation can be found here.
-
Demo recording - a 4-part walkthrough:
- Part 1 (Experiment Setup)
- Part 2 (SDK Installation & Setup)
- Part 3 (See it in action)
- Part 4 (Goal Tracking)