
Implementing Optimizely Commerce Cloud: Best Practices for SAP B2B Migration Projects
Moving from SAP Commerce (Hybris) to Optimizely Commerce Cloud is one of the more complex migration projects a B2B team can take on. SAP's deeply customizable pricing logic, condition records, and customer hierarchies don't map cleanly to any target platform, Optimizely included. But there's good news. Optimizely has made significant progress in 2024-2025 with features built specifically for B2B scenarios: a new B2B schema in ODP, improved organization modeling in Commerce Connect 13-14, and AI-powered search in Configured Commerce. These changes make the migration path clearer than it was even two years ago. This guide walks through the complete migration process, from initial discovery through post-launch monitoring. We'll cover the specific data models you need to understand, the API endpoints you'll use for bulk imports, and the architectural decisions that determine whether your migration succeeds or stalls.
Prerequisites
Before starting a SAP to Optimizely migration, ensure you have:
Technical requirements:
- Optimizely Commerce Connect 13 or 14 installed (.NET 6 environment)
- Access to Optimizely Service API (EPiServer.ServiceApi NuGet package)
- SAP Commerce database access or API credentials for data extraction
- Middleware platform for integration (SAP CPI, MuleSoft, Azure Logic Apps, or similar)
- Development, staging, and production environments configured
Team requirements:
- SAP SD/Hybris specialist familiar with your current pricing and condition logic
- .NET developer with Commerce Connect experience
- Integration architect for middleware design
- Business analyst who understands your B2B account structures and approval workflows
Documentation to gather:
- Complete list of SAP condition types in use (VK11 records)
- Customer hierarchy structure and role definitions
- Current customizations and extensions in SAP Commerce
- Order volume and historical data retention requirements
Step-by-Step Implementation
Step 1: Discovery and Assessment
Start by auditing your SAP Commerce implementation in detail. This isn't a quick exercise. Expect to spend 2-4 weeks on discovery for a mid-sized B2B operation.
1.1 Catalog and product data audit
Document every product attribute, variant structure, and classification system currently in SAP. Pay special attention to:
- Custom attributes that drive pricing or availability logic
- Product relationships (bundles, kits, accessories)
- Category hierarchies and their depth
- Media assets and their storage locations
1.2 Pricing and promotion inventory
SAP's condition-based pricing is typically the hardest part of any migration. Create a complete inventory of:
- All active condition types (PR00, K004, K005, etc.)
- Scales and brackets in use
- Customer-specific pricing agreements
- Promotional rules and their trigger conditions
Our experience shows that most SAP implementations use only 30-40% of their configured condition types regularly. Identifying which ones actually matter reduces migration scope significantly.
1.3 Customer hierarchy mapping
SAP's sold-to/ship-to/bill-to party model needs translation to Optimizely's structure:
- Sold-to party → Organization (primary)
- Ship-to party → Organization address
- Bill-to party → Organization address or separate organization
- Account group → Customer group
- Customer hierarchy → Organization parent-child relationship
- User roles (approvers, buyers) → Contact roles permissions
1.4 Gap analysis output
Create a clear document listing:
- Features that map directly (green)
- Features requiring custom development (yellow)
- Features requiring external services or significant rearchitecting (red)
Step 2: Target Architecture Design
2.1 Choose your commerce platform
Optimizely offers two B2B commerce options:
Commerce Cloud (Commerce Connect): Best when you need tight CMS integration, heavy content-driven experiences, and flexibility for custom development. This is the typical choice for SAP migrations where the existing implementation is heavily customized.
Configured Commerce: Better for teams wanting a lower-code approach with strong out-of-the-box B2B features. Monthly releases mean faster access to new capabilities, but less control over upgrade timing.
For most SAP B2B migrations, Commerce Cloud (Commerce Connect 13/14) with Optimizely CMS and ODP is the reference stack.
2.2 Integration architecture
Never connect SAP directly to Optimizely. Always use middleware:
SAP ERP/Commerce → Middleware (CPI/MuleSoft/Azure) → Optimizely Commerce Cloud
→ ODP (for personalization)Define clear integration patterns:
- Synchronous calls: Checkout, real-time inventory checks, credit validation
- Asynchronous events: Catalog updates, price list refreshes, order status syncs
2.3 Migration approach selection
Choose between:
Phased rollout: Start with catalog browsing, then enable cart functionality, then order capture. Alternatively, roll out by region or customer segment. Lower risk, longer timeline.
Big-bang cutover: Everything switches at once. Higher risk, but avoids maintaining two systems for extended periods.
Most B2B migrations benefit from a phased approach, particularly when customer training and change management are factors.
Step 3: Data Migration Execution
3.1 ETL pipeline design
Build extraction scripts that pull from SAP Commerce and transform data to Optimizely's expected format. Here's a simplified example of catalog item transformation:
public class CatalogMigrationService
{
private readonly HttpClient _serviceApiClient;
public async Task ImportProductBatch(IEnumerable<SapProduct> sapProducts)
{
var optimizelyEntries = sapProducts.Select(MapToCommerceEntry).ToList();
// Batch size recommendation: 100-500 items per request
foreach (var batch in optimizelyEntries.Chunk(250))
{
var request = new HttpRequestMessage(HttpMethod.Post, "/episerverapi/commerce/import")
{
Content = JsonContent.Create(new { Entries = batch })
};
var response = await _serviceApiClient.SendAsync(request);
response.EnsureSuccessStatusCode();
// Add delay between batches to avoid throttling
await Task.Delay(500);
}
}
private CatalogEntry MapToCommerceEntry(SapProduct sap)
{
return new CatalogEntry
{
Code = sap.MaterialNumber,
Name = sap.Description,
CatalogName = "MainCatalog",
MetaClassName = DetermineMetaClass(sap.ProductType),
// Map SAP classification to Optimizely categories
Categories = MapClassificationToCategories(sap.Classifications),
// Custom attributes
Properties = MapCustomAttributes(sap.Characteristics)
};
}
}3.2 Customer and organization import
Organizations require careful sequencing. Parent records must exist before children:
public async Task ImportOrganizationHierarchy(IEnumerable<SapCustomerHierarchy> hierarchies)
{
// Sort by hierarchy level to ensure parents are created first
var sorted = hierarchies.OrderBy(h => h.Level).ToList();
foreach (var hierarchy in sorted)
{
var org = new OrganizationDto
{
Name = hierarchy.CustomerName,
OrgCustomerId = hierarchy.SapCustomerId,
// Link to parent organization if not root level
ParentOrganizationId = hierarchy.ParentSapId != null
? await GetOptimizelyOrgId(hierarchy.ParentSapId)
: null,
// Assign customer groups for pricing segmentation
CustomerGroups = MapAccountGroupToCustomerGroups(hierarchy.AccountGroup)
};
await _serviceApiClient.PostAsync("/episerverapi/commerce/customers/organization",
JsonContent.Create(org));
}
}3.3 Price list migration
Convert SAP condition records to Optimizely price lists. Complex condition types may require a custom pricing provider:
public class SapPricingProvider : IPriceService
{
private readonly ISapPricingGateway _sapGateway;
public IPriceValue GetPrice(CatalogKey catalogKey, MarketId market, Currency currency)
{
// For complex pricing scenarios, call SAP in real-time
// Cache results aggressively to reduce latency
var cacheKey = $"{catalogKey.CatalogEntryCode}_{market}_{currency}";
if (!_cache.TryGetValue(cacheKey, out var price))
{
price = _sapGateway.CalculatePrice(
catalogKey.CatalogEntryCode,
GetCurrentOrganization(),
market,
currency);
_cache.Set(cacheKey, price, TimeSpan.FromMinutes(15));
}
return price;
}
}Step 4: B2B Feature Configuration
4.1 Organization and permissions setup
Configure the organization model to support B2B buying workflows:
// Define buyer roles within organizations
public static class BuyerRoles
{
public const string Administrator = "OrgAdmin";
public const string Purchaser = "Purchaser";
public const string Approver = "Approver";
public const string Viewer = "Viewer";
}
// Assign permissions based on role
public void ConfigureOrganizationPermissions(Organization org)
{
var permissions = new Dictionary<string, string[]>
{
[BuyerRoles.Administrator] = new[] { "ManageUsers", "ManageAddresses", "PlaceOrders", "ApproveOrders" },
[BuyerRoles.Purchaser] = new[] { "PlaceOrders", "ViewOrderHistory" },
[BuyerRoles.Approver] = new[] { "ApproveOrders", "ViewOrderHistory" },
[BuyerRoles.Viewer] = new[] { "ViewCatalog", "ViewOrderHistory" }
};
foreach (var role in permissions)
{
_organizationService.SetRolePermissions(org.OrganizationId, role.Key, role.Value);
}
}4.2 ODP integration for B2B personalization
With the 2025 B2B schema in ODP, you can model account hierarchies and run account-level targeting:
{
"business": {
"business_id": "ORG-12345",
"name": "Acme Manufacturing",
"parent_business_id": "ORG-PARENT",
"industry": "Manufacturing",
"tier": "Gold",
"attributes": {
"annual_contract_value": 500000,
"primary_region": "EMEA"
}
}
}This enables segmentation like "Show promotional pricing to Gold-tier manufacturing accounts in EMEA" without custom development.
Common Mistakes to Avoid
1. Attempting 1:1 pricing logic replication
SAP condition records can encode hundreds of rules. Trying to replicate every nuance in Optimizely leads to unmaintainable code.
Better approach: Work with business stakeholders to simplify pricing during migration. Many condition types exist for historical reasons and can be consolidated or eliminated.
2. Migrating all historical orders
Moving millions of order records extends timelines and rarely adds value. Most customers only need 1-2 years of history in the new system.
Better approach: Import recent orders (12-24 months) to Optimizely. Build a read-only view or API against the legacy SAP database for older records.
3. Synchronous integrations for everything
Calling SAP for every page view, search, or cart update creates latency and single points of failure.
We've found that teams who aggressively cache catalog and pricing data, refreshing via async events rather than real-time calls, see page load times 40-60% faster than those using synchronous patterns throughout.
4. Skipping organization hierarchy validation
Parent-child relationships must be correct before import. A misaligned hierarchy breaks permissions, pricing, and reporting.
Better approach: Run validation scripts that verify every child organization has an existing parent before bulk import. Flag orphaned records for manual review.
5. Underestimating UAT with actual customers
Internal testing rarely catches the edge cases that B2B customers encounter daily: specific contract terms, unusual approval chains, legacy account quirks.
Better approach: Recruit 5-10 key accounts for extended UAT. Give them real scenarios and monitor closely.
Testing and Verification
Automated regression suite
Build tests that run on every deployment:
[TestClass]
public class PricingMigrationTests
{
[TestMethod]
public async Task CustomerSpecificPricing_MatchesSapCalculation()
{
// Arrange
var testCases = await LoadPricingTestCases(); // From SAP export
foreach (var testCase in testCases)
{
// Act
var optimizelyPrice = await _priceService.GetPrice(
testCase.ProductCode,
testCase.CustomerOrg,
testCase.Quantity);
// Assert
Assert.AreEqual(testCase.ExpectedPrice, optimizelyPrice.Amount,
$"Price mismatch for {testCase.ProductCode} / {testCase.CustomerOrg}");
}
}
}Parallel run validation
Before cutover, run both systems simultaneously:
- Process the same orders through SAP and Optimizely
- Compare pricing, tax, and total calculations
- Document and investigate any discrepancies
Load testing scenarios
B2B operations have specific patterns to test:
- Large cart operations (100-1000 line items)
- Bulk price calculations for contract customers
- Concurrent users from the same organization
- Search performance with complex filtering
Post-migration monitoring checklist
Track these metrics after go-live:
- Order error rates (target: <0.5%)
- Cart abandonment changes vs. baseline
- Page load times (target: <3 seconds for catalog pages)
- Customer service ticket volume related to pricing or account access
- Integration failure rates (middleware logs)
Conclusion
SAP to Optimizely Commerce Cloud migrations require careful planning across three areas: data model translation (especially pricing and customer hierarchies), integration architecture (always use middleware), and B2B feature configuration (organizations, permissions, approval workflows).
The 2024-2025 updates to Optimizely's platform (Commerce Connect 13-14, the B2B schema in ODP, and improved organization modeling) have made these migrations more straightforward than they were previously. But the core challenges remain: understanding your SAP customizations deeply, making smart decisions about what to simplify versus replicate, and testing thoroughly with real customer scenarios.
Teams we work with report that the discovery phase, really understanding what SAP is doing before writing any migration code, is the single biggest factor in project success. Rushing past discovery leads to scope changes and rework that extend timelines by months.
If you're evaluating a SAP Commerce to Optimizely migration, we can help you assess your current SAP implementation, identify the specific challenges in your pricing and hierarchy setup, and build a realistic migration plan. Reach out to discuss your project specifics and get a clear picture of what the path forward looks like.
