Complete Guide: Creating Custom Integrations with Convert.com
Guide to help you build integrations with Convert.com
| Author: | George F. Crewe |
IN THIS ARTICLE YOU WILL:
This guide provides a standardized approach for connecting Convert.com to your internal backend or third-party analytics platforms. It uses a stable visitor identifier so that frontend experiment exposure and backend conversions can be tied to the same visitor.
This guide uses Convert’s current Experiences Tracking API for backend conversion tracking. For standard tracking requests, the endpoint is POST https://metrics.convertexperiments.com/v1/track/{account_id}/{project_id}. SDK-key based tracking is also available through POST https://metrics.convertexperiments.com/v1/track/{sdk_key}.
1. Frontend: Implementing Bring Your Own ID (BYOID)
To ensure 100% data consistency between your backend and Convert.com, you should use your own internal identifier (like a Database User ID or a hashed email) instead of relying on Convert's default cookies.
Crucial: Sequence of Execution
The BYOID must be defined before the main Convert tracking tag loads on your page. This ensures that the very first "bucket" event recorded by Convert is already associated with your custom ID.
Correct Implementation Order:
<script>
window._conv_q = window._conv_q || [];
window._conv_q.push({
what: 'identify',
params: {
visitorId: 'YOUR_INTERNAL_USER_ID' // Replace with your actual dynamic, non-PII ID
}
});
</script>
<script type="text/javascript" src="//cdn-4.convertexperiments.com/v1/js/12345678-12345678.js"></script>
⚠️ Important:
Use a stable, opaque, non-PII value. Do not pass raw emails, phone numbers, names, or other directly identifiable personal data as the visitor ID.
2. Frontend: Extracting Data and Segments
Use Convert’s visitor-data helper methods to extract the visitor ID, active bucketing data, and visitor segments. This allows you to forward Convert’s data to third-party tools, such as Segment, Mixpanel, or GA4, using your own identifier.
const convert_utils = {
getBrowser: () => window.convert?.currentData?.segments?.browser || 'OTH',
getDevice: () => window.convert?.currentData?.segments?.devices || ['OTHDEV'],
getSource: () => window.convert?.currentData?.segments?.source || 'direct',
getVisitorType: () => window.convert?.currentData?.segments?.visitorType || 'new',
getCountry: () => window.convert?.currentData?.segments?.country || '',
getCampaign: () => window.convert?.currentData?.segments?.campaign || '',
getCustomSegments: () => window.convert?.currentData?.segments?.customSegments || []
};
// Listener: Fires when experiences are evaluated
window._conv_q = window._conv_q || [];
window._conv_q.push({
what: 'addListener',
params: {
event: 'snippet.experiences_evaluated',
handler: function() {
const visitorData = window.convert?.getCurrentVisitorData?.() || {};
const segments =
visitorData.segments ||
window.convert?.getVisitorSegments?.() ||
{};
const bucketing = Array.isArray(visitorData.bucketing)
? visitorData.bucketing
: [];
const dataPayload = {
visitorId: visitorData.visitorId,
experiences: bucketing.map(function(item) {
return {
experienceId: String(item.experienceId || ''),
variationId: String(item.variationId || '')
};
}),
segments: {
browser: segments.browser || 'OTH',
devices: segments.devices || ['OTHDEV'],
source: segments.source || 'direct',
visitorType: segments.visitorType || 'new',
country: segments.country || '',
campaign: segments.campaign || '',
customSegments: segments.customSegments || []
}
};
// Action: Forward this to your backend or third-party analytics tool.
// myAnalyticsApp.track('Convert Data', dataPayload);
// sendToBackend('/convert-context', dataPayload);
}
}
});
Store visitorId, experienceId, variationId, and relevant segments in your backend or CRM so they can be reused later when a backend conversion occurs.
3. API Mapping Table (Segment Codes)
When sending data via the Experiences Tracking API, use the supported segment fields and values.
| Category | Field | Supported Values / Format | Description |
| Browser | browser | IE, CH, FF, OP, SF, OTH |
Internet Explorer/Edge, Chrome, Firefox, Opera, Safari, Other |
| Devices | devices | ALLPH, IPH, OTHPH, ALLTAB, IPAD, OTHTAB, DESK, OTHDEV |
Phone, tablet, desktop, or other device categories |
| Source | source | campaign, search, referral, direct, ai_tool |
Traffic origin category |
| Visitor Type | visitorType | new, returning |
Visitor status |
| Country | country | Two-letter ISO country code, e.g. US, GB, DE |
Visitor country |
| Campaign | campaign | String | Campaign identifier |
| Custom Segments | customSegments | Array of custom segment IDs | Custom segment references |
4. Backend: Tracking Conversions — Experiences Tracking API
When a conversion occurs on your server, such as a processed payment, lead qualification, subscription activation, or CRM status change, use Convert’s Experiences Tracking API to send the conversion event.
API Endpoint
POST https://metrics.convertexperiments.com/v1/track/{account_id}/{project_id}
Alternative SDK-key endpoint:
POST https://metrics.convertexperiments.com/v1/track/{sdk_key}
Request Headers:
Content-Type: application/json
Request Body (JSON):
{
"accountId": "10012345",
"projectId": "10056789",
"enrichData": true,
"visitors": [
{
"visitorId": "YOUR_INTERNAL_USER_ID",
"segments": {
"browser": "CH",
"devices": ["DESK"],
"source": "direct",
"visitorType": "new",
"country": "US",
"customSegments": ["segment-id-1", "segment-id-2"]
},
"events": [
{
"eventType": "conversion",
"data": {
"goalId": "99887766",
"bucketingData": {
"11223344": "55667788"
},
"goalData": [
{ "key": "amount", "value": 99.99 },
{ "key": "productsCount", "value": 2 },
{ "key": "transactionId", "value": "TXN-12345" }
]
}
}
]
}
]
}
In bucketingData, the object key is the experienceId and the value is the variationId:
{
"experienceId": "variationId"
}
Example:
{
"100127238": "1001186427"
}
Available Goal Data Keys
Use goalData when you need to send revenue, product count, transaction IDs, or custom reporting dimensions.
| Key | Value Type | Description |
|---|---|---|
amount |
Number | Revenue amount |
productsCount |
Number | Number of products |
transactionId |
String | Transaction identifier |
customDimension1 – customDimension5 |
String or array | Custom dimension values. Array values are accepted only for customDimension1 – customDimension5; each item is limited to 32 characters, and longer values may be truncated. |
5. Backend Code Example — Python
import requests
def send_conversion_to_convert(
account_id,
project_id,
visitor_id,
experience_id,
variation_id,
goal_id,
segments=None,
goal_data=None
):
"""
Send a backend conversion event to Convert.
Args:
account_id: Convert account ID.
project_id: Convert project ID.
visitor_id: The same visitor ID used on the frontend.
experience_id: Convert experience ID.
variation_id: Convert variation ID.
goal_id: Convert goal ID.
segments: Optional visitor segment data.
goal_data: Optional goal data such as revenue or transaction ID.
"""
url = f"https://metrics.convertexperiments.com/v1/track/{account_id}/{project_id}"
event_data = {
"goalId": str(goal_id),
"bucketingData": {
str(experience_id): str(variation_id)
}
}
if goal_data:
event_data["goalData"] = goal_data
payload = {
"accountId": str(account_id),
"projectId": str(project_id),
"enrichData": True,
"visitors": [
{
"visitorId": str(visitor_id),
"segments": segments or {},
"events": [
{
"eventType": "conversion",
"data": event_data
}
]
}
]
}
response = requests.post(url, json=payload)
response.raise_for_status()
return response.status_code == 200
# Usage example
send_conversion_to_convert(
account_id="10007679",
project_id="10007855",
visitor_id="visitor-abc123",
experience_id="100127238",
variation_id="1001186427",
goal_id="100037225",
segments={
"visitorType": "new",
"browser": "CH",
"devices": ["DESK"],
"source": "direct",
"country": "US"
},
goal_data=[
{"key": "amount", "value": 149.99},
{"key": "productsCount", "value": 3},
{"key": "transactionId", "value": "ORDER-12345"}
]
)
6. Backend Code Example — Node.js
async function sendConversionToConvert({
accountId,
projectId,
visitorId,
experienceId,
variationId,
goalId,
segments = {},
goalData = []
}) {
const url = `https://metrics.convertexperiments.com/v1/track/${accountId}/${projectId}`;
const eventData = {
goalId: String(goalId),
bucketingData: {
[String(experienceId)]: String(variationId)
}
};
if (goalData.length) {
eventData.goalData = goalData;
}
const payload = {
accountId: String(accountId),
projectId: String(projectId),
enrichData: true,
visitors: [
{
visitorId: String(visitorId),
segments,
events: [
{
eventType: "conversion",
data: eventData
}
]
}
]
};
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`Convert tracking failed: ${response.status} ${errorBody}`);
}
return response.json();
}
// Usage example
sendConversionToConvert({
accountId: "10007679",
projectId: "10007855",
visitorId: "visitor-abc123",
experienceId: "100127238",
variationId: "1001186427",
goalId: "100037225",
segments: {
visitorType: "new",
browser: "CH",
devices: ["DESK"],
source: "direct",
country: "US"
},
goalData: [
{ key: "amount", value: 149.99 },
{ key: "productsCount", value: 3 },
{ key: "transactionId", value: "ORDER-12345" }
]
});
7. Backend Code Example — PHP
<?php
function sendConversionToConvert(
$accountId,
$projectId,
$visitorId,
$experienceId,
$variationId,
$goalId,
$segments = [],
$goalData = []
) {
$url = "https://metrics.convertexperiments.com/v1/track/{$accountId}/{$projectId}";
$eventData = [
"goalId" => (string) $goalId,
"bucketingData" => [
(string) $experienceId => (string) $variationId
]
];
if (!empty($goalData)) {
$eventData["goalData"] = $goalData;
}
$payload = [
"accountId" => (string) $accountId,
"projectId" => (string) $projectId,
"enrichData" => true,
"visitors" => [
[
"visitorId" => (string) $visitorId,
"segments" => $segments,
"events" => [
[
"eventType" => "conversion",
"data" => $eventData
]
]
]
]
];
$options = [
"http" => [
"header" => "Content-Type: application/json\r\n",
"method" => "POST",
"content" => json_encode($payload)
]
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
return $result !== false;
}
// Usage example
sendConversionToConvert(
"10007679",
"10007855",
"visitor-abc123",
"100127238",
"1001186427",
"100037225",
[
"visitorType" => "new",
"browser" => "CH",
"devices" => ["DESK"],
"source" => "direct",
"country" => "US"
],
[
["key" => "amount", "value" => 149.99],
["key" => "productsCount", "value" => 3],
["key" => "transactionId", "value" => "ORDER-12345"]
]
);
8. Best Practices
- Persistent Identity: Setting BYOID before the Convert tag helps ensure that bucketing and conversion events are tied to the same visitor identity.
- Use the same
visitorIdin all places: frontend identity, analytics payloads, backend storage, and backend conversion tracking. - Store Bucketing Data: When the visitor is evaluated for experiences, store the
experienceIdandvariationIdalong with the visitor ID. Backend conversions need this data to populatebucketingData. - Use
eventType: "conversion"for conversion events. - Use
goalDatafor Revenue: When tracking purchases, includegoalDataforamount,productsCount, andtransactionIdso revenue and transaction data can be attributed correctly. - Use
enrichDataCarefully: TheenrichDataflag can enrich events before they are stored for reporting, for example by using backend datastore bucketing or segments when not provided in the request. Availability may depend on the plan.
9. Troubleshooting
Conversion does not appear in reports
Check that:
The visitorId matches the same ID used when the visitor was bucketed.
The goalId belongs to the project and is attached where needed.
The experienceId and variationId are correct.
The bucketingData object maps experience ID to variation ID.
The request is sent as POST with Content-Type: application/json.
Revenue is missing
Check that:
goalData includes amount as a number.transactionId is unique for the order.
Revenue tracking is supported and configured for the relevant goal/reporting setup.
Visitor segmentation is missing
Check that:
Segments are sent under visitors[].segments.visitorType uses new or returning, not 0 or 1.devices is an array, for example ["DESK"].