-
Notifications
You must be signed in to change notification settings - Fork 1
CodeExamples
Complete PHP code examples for all SDK methods.
A Context ties all SDK actions to a specific visitor. A unique visitorId is required for deterministic bucketing.
use ConvertSdk\Interfaces\ContextInterface;
$context = $sdk->createContext(
'visitor-unique-id',
[
'country' => 'US',
'language' => 'en',
]
);As long as the visitorId and experience configuration remain the same, bucketing stays consistent. To ensure consistency even when configuration changes, provide a persistent DataStore (see Configuration).
Every context method that runs experiences or features accepts an optional BucketingAttributes object:
use OpenAPI\Client\BucketingAttributes;
$attributes = new BucketingAttributes([
'locationProperties' => ['url' => '/pricing'],
'visitorProperties' => ['plan' => 'pro'],
'updateVisitorProperties' => true,
'enableTracking' => true,
'environment' => 'staging',
'typeCasting' => true,
'experienceKeys' => ['specific-experience-key'],
]);| Property | Type | Description |
|---|---|---|
locationProperties |
?array |
Key-value pairs used for evaluating experience locations |
visitorProperties |
?array |
Key-value pairs used for evaluating experience audiences (overwrites same keys from context creation) |
updateVisitorProperties |
?bool |
Whether to permanently update in-memory visitor properties |
enableTracking |
?bool |
Whether to track bucketing events immediately (default: true) |
environment |
?string |
Override environment for this call |
typeCasting |
?bool |
Auto-convert feature variable values to the variable's defined type (default: true) |
experienceKeys |
?array |
Limit feature evaluation to specific experiences only |
Loops through each active experience, evaluates targeting rules, and returns the selected variation for each.
use ConvertSdk\DTO\BucketedVariation;
use OpenAPI\Client\BucketingAttributes;
/** @var BucketedVariation[] $variations */
$variations = $context->runExperiences();
// With attributes:
$variations = $context->runExperiences(new BucketingAttributes([
'locationProperties' => ['url' => '/pricing'],
'visitorProperties' => ['plan' => 'pro'],
'enableTracking' => true,
]));Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$attributes |
BucketingAttributes|null |
No | See BucketingAttributes above |
Returns: BucketedVariation[]
Evaluates a single experience by its key.
use ConvertSdk\DTO\BucketedVariation;
use OpenAPI\Client\BucketingAttributes;
/** @var BucketedVariation|null $variation */
$variation = $context->runExperience('experience-key');
// With attributes:
$variation = $context->runExperience('experience-key', new BucketingAttributes([
'locationProperties' => ['url' => '/'],
'visitorProperties' => ['country' => 'US'],
]));Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$experienceKey |
string |
Yes | The experience's unique key |
$attributes |
BucketingAttributes|null |
No | See BucketingAttributes above |
Returns: BucketedVariation|null — null when the visitor is not bucketed (rule mismatch, inactive experience, etc.)
use ConvertSdk\ConvertSDK;
use ConvertSdk\DTO\BucketedVariation;
$sdk = ConvertSDK::create([
'sdkKey' => 'your-sdk-key',
]);
if ($sdk->isReady()) {
$context = $sdk->createContext('visitor-unique-id');
/** @var BucketedVariation|null $variation */
$variation = $context->runExperience('experience-key');
if ($variation !== null) {
echo $variation->experienceKey; // 'experience-key'
echo $variation->variationKey; // e.g. 'variation-1'
}
}Pass BucketingAttributes to scope bucketing to a specific location:
use OpenAPI\Client\BucketingAttributes;
$variation = $context->runExperience('checkout-flow', new BucketingAttributes([
'locationProperties' => ['page' => '/checkout'],
]));Features are resolved through variations of relevant experiences.
Returns all features with their status and variable values for the visitor.
use ConvertSdk\DTO\BucketedFeature;
use OpenAPI\Client\BucketingAttributes;
/** @var BucketedFeature[] $features */
$features = $context->runFeatures();
// With attributes:
$features = $context->runFeatures(new BucketingAttributes([
'locationProperties' => ['url' => '/dashboard'],
'visitorProperties' => ['tier' => 'premium'],
'typeCasting' => true,
]));Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$attributes |
BucketingAttributes|null |
No | See BucketingAttributes above |
Returns: BucketedFeature[]
Returns a single feature's status and variable values for the visitor.
use ConvertSdk\DTO\BucketedFeature;
use ConvertSdk\Enums\FeatureStatus;
use OpenAPI\Client\BucketingAttributes;
/** @var BucketedFeature|null $feature */
$feature = $context->runFeature('feature-key');
// With attributes and experience filter:
$feature = $context->runFeature('feature-key', new BucketingAttributes([
'locationProperties' => ['url' => '/settings'],
'visitorProperties' => ['role' => 'admin'],
'typeCasting' => true,
'experienceKeys' => ['specific-experience-key'],
]));Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$key |
string |
Yes | The feature's unique key |
$attributes |
BucketingAttributes|null |
No | See BucketingAttributes above |
Returns: BucketedFeature|null
use ConvertSdk\ConvertSDK;
use ConvertSdk\DTO\BucketedFeature;
use ConvertSdk\Enums\FeatureStatus;
$sdk = ConvertSDK::create([
'sdkKey' => 'your-sdk-key',
]);
if ($sdk->isReady()) {
$context = $sdk->createContext('visitor-unique-id');
/** @var BucketedFeature|null $feature */
$feature = $context->runFeature('feature-key');
if ($feature !== null && $feature->status === FeatureStatus::Enabled) {
echo 'Feature is enabled';
print_r($feature->variables);
}
}$features = $context->runFeatures();
foreach ($features as $feature) {
echo "{$feature->featureKey}: {$feature->status->value}\n";
foreach ($feature->variables as $key => $value) {
echo " {$key} = {$value}\n";
}
}Sends a conversion event for a goal. The decision is made against the goal's configured triggering rules.
use ConvertSdk\DTO\ConversionAttributes;
use ConvertSdk\DTO\GoalData;
use ConvertSdk\Enums\GoalDataKey;
$context->trackConversion('goal-key', new ConversionAttributes(
ruleData: [
'action' => 'buy',
],
conversionData: [
new GoalData(GoalDataKey::Amount, 10.3),
new GoalData(GoalDataKey::ProductsCount, 2),
new GoalData(GoalDataKey::TransactionId, 'transaction-unique-id'),
],
conversionSetting: [
'forceMultipleTransactions' => false,
],
));Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$goalKey |
string |
Yes | The goal's unique key |
$attributes |
ConversionAttributes|null |
No | Conversion attributes (see Return Types) |
Returns: RuleError|bool|null — null on success, false if goal not found or rule failed, RuleError enum on rule mismatch.
$result = $context->trackConversion('signup-completed');If a goal has targeting rules, pass ruleData to evaluate them:
use ConvertSdk\DTO\ConversionAttributes;
$context->trackConversion('checkout-goal', new ConversionAttributes(
ruleData: ['page_type' => 'checkout', 'cart_value' => 100],
));use ConvertSdk\DTO\ConversionAttributes;
use ConvertSdk\DTO\GoalData;
use ConvertSdk\Enums\GoalDataKey;
$context->trackConversion('purchase-completed', new ConversionAttributes(
conversionData: [
new GoalData(GoalDataKey::Amount, 99.99),
new GoalData(GoalDataKey::ProductsCount, 3),
new GoalData(GoalDataKey::TransactionId, 'txn-abc-123'),
],
));When conversionData is present, the SDK sends two events: a conversion event and a transaction event (with the goal data).
By default, each goal fires once per visitor. For recurring transactions (e.g., subscription renewals), override deduplication:
use ConvertSdk\DTO\ConversionAttributes;
use ConvertSdk\DTO\GoalData;
use ConvertSdk\Enums\GoalDataKey;
use ConvertSdk\Enums\ConversionSettingKey;
$context->trackConversion('subscription-renewal', new ConversionAttributes(
conversionData: [
new GoalData(GoalDataKey::Amount, 29.99),
new GoalData(GoalDataKey::TransactionId, 'renewal-456'),
],
conversionSetting: [
ConversionSettingKey::ForceMultipleTransactions->value => true,
],
));| Scenario | Conversion Event | Transaction Event |
|---|---|---|
| First trigger, no goal data | Sent | Not sent |
| First trigger, with goal data | Sent | Sent |
| Repeat trigger, no force | Not sent | Not sent |
| Repeat trigger, force=true, no goal data | Not sent | Not sent |
| Repeat trigger, force=true, with goal data | Not sent | Sent |
Evaluates segment rules and updates custom segments in the user context.
$context->runCustomSegments(['segment-key-1', 'segment-key-2'], [
'ruleData' => ['enabled' => true],
]);Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$segmentKeys |
string[] |
Yes | List of segment keys to evaluate |
$attributes |
?array |
No | Associative array with ruleData key-value pairs for segment matching |
Returns: ?array — The matched custom segments, or null if none matched.
Permanently updates the visitor's default segments for reporting. Only the following properties are included in Convert Reports:
browserdevicessourcecampaignvisitorTypecountry
$context->setDefaultSegments([
'country' => 'US',
'browser' => 'chrome',
'devices' => 'desktop',
]);Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$segments |
array |
Yes | Key-value pairs merged with the initial visitor properties |
Returns: void
$context->setAttribute('weather', 'rainy');Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$key |
string |
Yes | The attribute key |
$value |
mixed |
Yes | The attribute value |
Returns: void
Merges with existing attributes.
$context->setAttributes([
'weather' => 'rainy',
'plan' => 'enterprise',
]);Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$attributes |
array |
Yes | Key-value pairs merged with existing visitor properties |
Returns: void
Permanently updates all visitor properties used in audience evaluation via the data store.
$context->updateVisitorProperties('visitor-unique-id', [
'weather' => 'rainy',
'plan' => 'enterprise',
]);Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$visitorId |
string |
Yes | The visitor ID |
$visitorProperties |
array |
Yes | Key-value pairs merged with the stored visitor properties |
Returns: void
Visitor properties can also be updated inline when calling any experience/feature method:
use OpenAPI\Client\BucketingAttributes;
$variation = $context->runExperience('experience-key', new BucketingAttributes([
'visitorProperties' => ['weather' => 'rainy'],
'updateVisitorProperties' => true,
]));Find a single entity in the project configuration by its key.
use ConvertSdk\Enums\EntityType;
$experience = $context->getConfigEntity('experience-key', EntityType::Experience->value);Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$key |
string |
Yes | Entity key |
$entityType |
string |
Yes | An EntityType enum value — one of: audience, location, segment, feature, goal, experience, variation
|
Returns: array — The matching entity data.
Find a single entity in the project configuration by its numeric id.
use ConvertSdk\Enums\EntityType;
$variation = $context->runExperience('experience-key');
if ($variation !== null) {
$changes = $variation->changes;
foreach ($changes as $change) {
if (isset($change['data']['feature_id'])) {
$feature = $context->getConfigEntityById(
(string) $change['data']['feature_id'],
EntityType::Feature->value
);
}
}
}Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$id |
string |
Yes | Entity ID (as string) |
$entityType |
string |
Yes | Same values as getConfigEntity above |
Returns: array — The matching entity data.
The SDK batches tracking events and sends them in network requests (configured via events.batch_size). You can manually flush all pending queues at any time.
Key difference from the JavaScript SDK:
releaseQueues()is synchronous and returnsvoid, not aPromise. The PHP SDK also registers aregister_shutdown_functionhandler that automatically flushes queues when the PHP process ends.
// From context
$context->releaseQueues();
// With a reason (for debugging)
$context->releaseQueues('page-exit');
// From SDK instance
$sdk->flush();Context releaseQueues() Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
$reason |
?string |
No | Custom message for debugging |
Returns: void
The SDK registers a shutdown function during ConvertSDK::create():
register_shutdown_function(static function () use ($apiManager): void {
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request(); // Send response to client before flushing
}
$apiManager->releaseQueue('shutdown');
});This ensures that:
- In PHP-FPM environments, the response is sent to the client first (
fastcgi_finish_request()), then queued events are flushed without blocking the response. - In CLI or other SAPI environments, queues are flushed when the script exits.
You do not need to call releaseQueues() manually in typical PHP-FPM request lifecycles. Manual release is useful for long-running processes or when you need immediate delivery.
The SDK emits events that you can subscribe to for logging, analytics integrations, or debugging.
Use the on() method on the SDK instance. The callback receives two arguments: $args (event data) and $err (exception or null).
use ConvertSdk\ConvertSDK;
use ConvertSdk\Enums\EntityType;
use ConvertSdk\Enums\SystemEvents;
$sdk = ConvertSDK::create([
'sdkKey' => 'your-sdk-key',
]);
// Ready event
$sdk->on(SystemEvents::Ready, function (mixed $args, mixed $err): void {
if ($err !== null) {
error_log('SDK initialization failed: ' . $err->getMessage());
return;
}
echo "SDK is ready\n";
});
// Bucketing event (e.g., for analytics integration)
$sdk->on(SystemEvents::Bucketing, function (mixed $args, mixed $err): void {
if ($err !== null) {
error_log('Bucketing error: ' . $err->getMessage());
return;
}
$visitorId = $args['visitorId'] ?? null;
$experienceKey = $args['experienceKey'] ?? null;
$variationKey = $args['variationKey'] ?? null;
$featureKey = $args['featureKey'] ?? null;
// Log or send to analytics
error_log("Bucketed: visitor={$visitorId} experience={$experienceKey} variation={$variationKey}");
});
// Conversion event
$sdk->on(SystemEvents::Conversion, function (mixed $args, mixed $err): void {
if ($err !== null) {
error_log('Conversion error: ' . $err->getMessage());
return;
}
$visitorId = $args['visitorId'] ?? null;
$goalKey = $args['goalKey'] ?? null;
error_log("Conversion: visitor={$visitorId} goal={$goalKey}");
});
// Config updated event
$sdk->on(SystemEvents::ConfigUpdated, function (mixed $args, mixed $err): void {
if ($err !== null) {
error_log('Config update error: ' . $err->getMessage());
return;
}
echo "Configuration has been refreshed\n";
});Note: Events registered with
on()that are flagged as deferred (e.g.,Ready) will fire immediately if the event already occurred before the listener was registered.
| Enum Case | String Value | Triggered By | Callback Data |
|---|---|---|---|
SystemEvents::Ready |
ready |
SDK initialization complete |
[] (empty array), with error as second arg on failure |
SystemEvents::Bucketing |
bucketing |
Running experience(s) | ['visitorId' => string, 'experienceKey' => string, 'variationKey' => string] |
| Running feature(s) | ['visitorId' => string, 'experienceKey' => string, 'featureKey' => string, 'status' => string] |
||
SystemEvents::Conversion |
conversion |
Tracking a conversion | ['visitorId' => string, 'goalKey' => string] |
SystemEvents::LocationActivated |
location.activated |
Location rules matched | Location data |
SystemEvents::LocationDeactivated |
location.deactivated |
Location rules no longer matched | Location data |
SystemEvents::ConfigUpdated |
config.updated |
Configuration refreshed | [] |
SystemEvents::Segments |
segments |
Segments evaluated | Segment data |
SystemEvents::Audiences |
audiences |
Audiences evaluated | Audience data |
SystemEvents::ApiQueueReleased |
api.queue.released |
Event queue flushed to Tracking API | Queue data |
Copyrights © 2026 All Rights Reserved by Convert Insights, Inc.
Getting Started
PHP SDK
- Quickstart
- Installation
- Initialization
- Configuration
- Return Types & DTOs
- Code Examples
- Segments Manager
Core Concepts
- Experiences & Variations
- Feature Flags
- Bucketing Algorithm
- Rule Evaluation
- Segments
- Data Management
- Event System
- API Communication
How-To Guides
- Running Experiences
- Running Features
- Tracking Conversions
- Visitor Context
- Persistent DataStore
- Troubleshooting
Contributing