Disclaimer: This website requires Please enable JavaScript in your browser settings for the best experience.

HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Commerce Connect 14 + ODP

Export data from Commerce Connect 14 and import it into Optimizely Data Platform (ODP) (for Commerce Connect 14.13.0)

📘

Note

This integration exports data from Commerce Connect 14 and imports it into Optimizely Data Platform (ODP).

To integrate Commerce Connect 13 with ODP, use one of the following:

Breaking change

Commerce Connect 14.20.0

Optimizely changed MarketKey class to support import data to Amazon S3, which is required. You must configure all settings for Amazon S3 credentials.

  1. (Required) Added TrackingId property to MarketKey.

  2. Added S3Options property to MarketKey, which contains the required properties:

    1. BucketName – Amazon S3 bucket name. For example, if your Bucket URL for ODP imports is s3://zauis-incoming/W4WzcEs-ABgXorzY7h1LCQ, enter zaius-incoming.

    2. AccessKeyId – AWS Access Key ID.

    3. SecretAccessKey – AWS Secret Access Key.

    4. Region – The system name of a region like "us-east-1". Default value is us-east-1 if Region setting is empty or null.

Commerce 14.17.0

Optimizely changed MarketKey class to support multi-site and reduce the number of settings.

  1. Renamed MarketId to MarketIds to allow multiple Market IDs with one ODP account with fewer settings.
  2. Added a property called SiteId to support multi-site. SiteId value can be null or empty. When a SiteId is present:
    1. The job filters the orders by SiteId.
    2. The job filters products by catalogs that are available on SiteId.
    3. The job sends customers to every Endpoint/Access Key because customers are not related to SiteId.

ODPJobOptions

This contains settings for the ODP integration job.

NameDescriptionDefault
ExportCatalogExport products and variants to ODPtrue
ExportCustomersExport customers to ODPtrue
ExportOrdersExport orders to ODPtrue
IncludeProductsExport products to ODPtrue
ProductBatchSizeBatch size when sending products to ODP50
OrderBatchSizeBatch size when sending orders to ODP50
CustomerBatchSizeBatch size when sending customers to ODP50
MarketKeysCollection of MarketKey. These hold API URL and access key to make API calls to ODP
DisableDeltaExportRun the ODP export job with delta exportfalse

📘

Note

Due to the potential of having multiple markets and currencies, product pricing cannot be transferred to ODP and displays as $0.

Export data to ODP job

Commerce Connect version 14.13.0 contains a scheduled job called Export data to ODP to integrate Optimizely Commerce Connect with Optimizely Data Platform (ODP). This job transfers Commerce Connect data (including orders, customers, and products) to the configured ODP account. The job saves data in CSV files and sends it to Amazon S3. ODP then processes the files.

ODP requires that the CSV contains the following required fields:

  • Customer
    • commerce_cloud_id
    • first_name
    • last_name
    • name
    • email
    • city
    • country
    • state
    • street1
    • street2
    • zip
  • Product
    • product_id
    • category
    • name
    • sku
    • price
    • quantity
    • parent_product_id
    • image_url
  • Order
    • commerce_cloud_id email
    • first_name
    • last_name
    • name
    • phone
    • bill_address ship_address
    • order_id
    • total
    • discount
    • subtotal
    • tax
    • shipping
    • coupon_code
    • item_product_id
    • item_price
    • item_quantity
    • item_discount item_subtotal
    • ts

Delta exports

Commerce Connect version 14.23.0 supports delta exports for ODP, enabled by default. ODP only sends the data that has changed or has been added since the last export. Use the DisableDeltaExport option to turn off using delta exports.

Configure through code

Use the following code sample to configure the integration through code.

Before 14.20.0

services.Configure < ODPJobOptions > (o => {
  o.MarketKeys = new List < MarketKey > {
    new() {
      MarketId = "US",
        AccessKey = "key",
        EndpointUrl = "<https://api.zaius.com/>"
    }
  };
});

After 14.20.0

services.Configure<ODPJobOptions>(o =>
{
    o.MarketKeys = new List<MarketKey>
    {
        new()
        {
            SiteId = "siteId",
            MarketIds = new List<string> { "US" },
            AccessKey = "key",
            EndpointUrl = "https://api.zaius.com/",
            TrackingId = "tracking id",
            S3Options = new S3Options
            {
                BucketName = "",
                AccessKeyId = "",
                SecretAccessKey = "",
                Region = ""
            }
        }
    };
});

Configure through the configuration file

Use the following code sample to configure the integration through the configuration file.

Before 14.20.0

{  
  "EPiServer" : {  
    "Commerce" : {  
       "ODPJob": {  
        "MarketKeys": [  
          {  
            "MarketId": "US",  
            "AccessKey": "key",  
            "EndpointUrl": "https://api.zaius.com/"  
          }  
        ]  
      }  
    }  
  }  
}

After 14.20.0

{
  "EPiServer": {
    "Commerce": {
      "ODPJob": {
        "MarketKeys": [
          {
            "SiteId": "siteId",
            "MarketIds": ["US", "SWE"],
            "AccessKey": "key",
            "EndpointUrl": "https://api.zaius.com/",
            "TrackingId": "",
            "S3Options": {
              "BucketName": "",
              "AccessKeyId": "",
              "SecretAccessKey": "",
              "Region": "ADD_REGION, SEE THE FOLLOWING NOTE"
            }
          }
        ]
      }
    }
  }
}

📘

Note

You must add your Region value in the code snippet. If left as an empty string, its value defaults to us-east-1.

  • US us-east-1
  • EUeu-west-1
  • Australiaap-southeast-2

Custom fields

Create custom fields handlers

To create and populate custom fields into the ODP customers object, create an implementation of ICustomerCustomFieldsHandler.

[ServiceConfiguration(ServiceType = typeof (ICustomerCustomFieldsHandler))]
public class CustomCustomers: ICustomerCustomFieldsHandler {
  public IEnumerable < SchemaObjectCreateField > CreateFields() {
    return new [] {
      new SchemaObjectCreateField {
        Name = "mark_customers_teststring",
          DisplayName = "Mark ODP Connector string",
          PublicRead = true,
          Type = "string"
      },
      new SchemaObjectCreateField {
        Name = "mark_customers_testtimestamp",
          DisplayName = "Mark ODP Connector timestamp",
          PublicRead = true,
          Type = "timestamp"
      },
      new SchemaObjectCreateField {
        Name = "mark_customers_testinteger",
          DisplayName = "Mark ODP Connector integer",
          PublicRead = true,
          Type = "number"
      },
      new SchemaObjectCreateField {
        Name = "mark_customers_testdecimal",
          DisplayName = "Mark ODP Connector decimal",
          PublicRead = false,
          Type = "number"
      },
      new SchemaObjectCreateField {
        Name = "mark_customers_testboolean",
          DisplayName = "Mark ODP Connector boolean",
          PublicRead = false,
          Type = "boolean"
      }
    };
  }

  public Dictionary < string, object > GetFieldValues(ContactEntity contact) {
    var values = new Dictionary < string,
      object > ();
    var testString = contact.Properties.GetValue < string > ("mark_customers_teststring", null);
    if (!string.IsNullOrEmpty(testString)) {
      values.Add("mark_customers_teststring", testString);
    }

    var testTimestamp = contact.Properties.GetValue < DateTime ? > ("mark_customers_testtimestamp", null);
    if (testTimestamp != null) {
      values.Add("mark_customers_testtimestamp", testTimestamp.Value.ToString("s"));
    }

    var testInteger = contact.Properties.GetValue < int ? > ("mark_customers_testinteger", null);
    if (testInteger != null) {
      values.Add("mark_customers_testinteger", testInteger.Value);
    }

    var testDecimal = contact.Properties.GetValue < decimal ? > ("mark_customers_testdecimal", null);
    if (testDecimal != null) {
      values.Add("mark_customers_testdecimal", testDecimal.Value);
    }

    var testBoolean = contact.Properties.GetValue("mark_customers_testboolean", false);
    values.Add("mark_customers_testboolean", testBoolean);

    return values;
  }
}

To create and populate custom fields into the ODP products object. create an implementation of IProductCustomFieldsHandler.

[ServiceConfiguration(ServiceType = typeof (IProductCustomFieldsHandler))]
public class CustomProducts: IProductCustomFieldsHandler {
  public IEnumerable < SchemaObjectCreateField > CreateFields() {
    return new [] {
      new SchemaObjectCreateField {
        Name = "mark_product_teststring",
          DisplayName = "Mark ODP Connector string",
          PublicRead = true,
          Type = "string"
      },
      new SchemaObjectCreateField {
        Name = "mark_product_testtimestamp",
          DisplayName = "Mark ODP Connector timestamp",
          PublicRead = true,
          Type = "timestamp"
      },
      new SchemaObjectCreateField {
        Name = "mark_product_testinteger",
          DisplayName = "Mark ODP Connector integer",
          PublicRead = true,
          Type = "number"
      },
      new SchemaObjectCreateField {
        Name = "mark_product_testdecimal",
          DisplayName = "Mark ODP Connector decimal",
          PublicRead = false,
          Type = "number"
      },
      new SchemaObjectCreateField {
        Name = "mark_product_testboolean",
          DisplayName = "Mark ODP Connector boolean",
          PublicRead = false,
          Type = "boolean"
      }
    };
  }

  public Dictionary < string, object > GetFieldValues(EntryContentBase entry) {
    var values = new Dictionary < string,
      object > ();
    var testString = entry.GetValue("mark_product_teststring")?.ToString();
    if (!string.IsNullOrEmpty(testString)) {
      values.Add("mark_product_teststring", testString);
    }

    var testTimestamp = entry.GetValue("mark_product_testtimestamp") as DateTime ? ;
    if (testTimestamp != null) {
      values.Add("mark_product_testtimestamp", testTimestamp.Value.ToString("s"));
    }

    var testInteger = entry.GetValue("mark_product_testinteger") as int ? ;
    if (testInteger != null) {
      values.Add("mark_product_testinteger", testInteger.Value);
    }

    var testDecimal = entry.GetValue("mark_product_testdecimal") as decimal ? ;
    if (testDecimal != null) {
      values.Add("mark_product_testdecimal", testDecimal.Value);
    }

    var testBoolean = entry.GetValue("mark_product_testboolean") as bool ? ;
    if (testBoolean != null) {
      values.Add("mark_product_testboolean", testBoolean);
    }
    return values;
  }
}

These interfaces contain two methods for creating schema and populating custom fields:

  • IEnumerable CreateFields – Creates ODP custom fields.
  • Dictionary<string, object> GetFieldValues – Populates values for custom fields.

However, this requires redeploying the code.

Use the Commerce Admin UI

To improve this process, you can use the Commerce Admin UI to create custom fields using the ODP API and create mapping for custom properties (MetaFields) for products, contacts, and orders to ODP custom fields.

📘

Note

If you have multiple market keys, this feature loops through all market keys and creates the custom field.

When the job runs next time, the integration uses the mappings.

Rules to avoid issues

  • Commerce custom properties only support properties with primitive data types: DataTime, Number, Boolean, and String.

  • There are compatibility data type rules when mapping between Commerce properties and ODP custom fields.

    Commerce Connect property data typeODP custom field data type
    DateTimeTimeStamp (UNIX epoch)
    NumberNumber or String
    BooleanBoolean or String
    StringString
  • If there is any issue with mapping when you run the job, Commerce Connect logs it and skips error mapping.