Documentation Index Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
Use this file to discover all available pages before exploring further.
Cart Transform Functions
Cart transform functions allow your app to modify cart contents before checkout. Use them to automatically apply discounts, merge similar items, split bundles, add free gifts, or implement complex pricing logic.
How It Works
Function Manifest
{
"handle" : "my-cart-app" ,
"name" : "Cart Transformer" ,
"version" : "1.0.0" ,
"functions" : {
"cart_transform" : {
"handle" : "cart-rules" ,
"name" : "Cart Transformation Rules" ,
"config" : {
"enableBundling" : true ,
"freeGiftThreshold" : 5000 ,
"freeGiftProductId" : "prod_gift123"
}
}
}
}
interface CartTransformInput {
cart : {
items : CartItem [];
subtotal : number ;
total : number ;
currency : string ;
discountCodes : string [];
attributes : Record < string , string >;
};
customer : {
id : string ;
email : string ;
tags : string [];
ordersCount : number ;
} | null ;
shop : {
id : string ;
currency : string ;
};
}
interface CartItem {
id : string ; // Cart line item ID
variantId : string ;
productId : string ;
title : string ;
variantTitle : string ;
quantity : number ;
price : number ; // Unit price in cents
originalPrice : number ; // Price before any transforms
sku : string ;
weight : number ;
properties : Record < string , string >;
discountAllocations : DiscountAllocation [];
}
Output Schema
interface CartTransformOutput {
operations : CartOperation [];
}
type CartOperation =
| {
update : {
cartItemId : string ;
price ?: number ; // New price in cents
title ?: string ; // Override title
properties ?: Record < string , string >;
}
}
| {
merge : {
sourceCartItemIds : string []; // Items to merge
title : string ; // Merged item title
price : number ; // Total price
properties ?: Record < string , string >;
}
}
| {
split : {
cartItemId : string ;
items : SplitItem [];
}
}
| {
add : {
variantId : string ;
quantity : number ;
price ?: number ; // Override price (0 for free)
properties ?: Record < string , string >;
}
}
| {
remove : {
cartItemId : string ;
}
};
interface SplitItem {
variantId : string ;
quantity : number ;
price : number ;
title ?: string ;
properties ?: Record < string , string >;
}
Operations
Update Item
Modify an existing cart item:
{
operations : [
{
update: {
cartItemId: 'item_123' ,
price: 1999 , // New price
title: 'Special Edition T-Shirt' ,
properties: {
discount_reason: 'VIP pricing'
}
}
}
]
}
Merge Items
Combine multiple items into a bundle:
{
operations : [
{
merge: {
sourceCartItemIds: [ 'item_shirt' , 'item_pants' , 'item_belt' ],
title: 'Complete Outfit Bundle' ,
price: 8999 , // Bundle price (vs individual total of $119.97)
properties: {
bundle_type: 'outfit' ,
discount: '25% off'
}
}
}
]
}
Split Item
Break an item into component parts:
{
operations : [
{
split: {
cartItemId: 'item_bundle' ,
items: [
{
variantId: 'variant_shirt' ,
quantity: 1 ,
price: 2999 ,
title: 'Bundle Item: T-Shirt'
},
{
variantId: 'variant_hat' ,
quantity: 1 ,
price: 1999 ,
title: 'Bundle Item: Hat'
}
]
}
}
]
}
Add Item
Add a new item to the cart:
{
operations : [
{
add: {
variantId: 'variant_gift' ,
quantity: 1 ,
price: 0 , // Free gift
properties: {
_gift: 'true' ,
gift_message: 'Free gift with $50+ order!'
}
}
}
]
}
Remove Item
Remove an item from the cart:
{
operations : [
{
remove: {
cartItemId: 'item_invalid'
}
}
]
}
Example Implementations
Free Gift with Purchase
function transformCart ( input , config ) {
const operations = [];
const { cart } = input ;
const threshold = config . freeGiftThreshold || 5000 ;
const giftProductId = config . freeGiftProductId ;
// Check if cart qualifies for free gift
const qualifies = cart . subtotal >= threshold ;
// Check if gift is already in cart
const existingGift = cart . items . find (
item => item . properties ?. _free_gift === 'true'
);
if ( qualifies && ! existingGift ) {
// Add free gift
operations . push ({
add: {
variantId: giftProductId ,
quantity: 1 ,
price: 0 ,
properties: {
_free_gift: 'true' ,
_gift_message: `Free gift with orders over $ ${ threshold / 100 } !`
}
}
});
} else if ( ! qualifies && existingGift ) {
// Remove gift if no longer qualifying
operations . push ({
remove: {
cartItemId: existingGift . id
}
});
}
return { operations };
}
Automatic Bundle Pricing
function transformCart ( input , config ) {
const operations = [];
const { cart } = input ;
// Define bundle combinations
const bundles = [
{
name: 'Complete Skincare Set' ,
products: [ 'prod_cleanser' , 'prod_toner' , 'prod_moisturizer' ],
discount: 0.20 // 20% off when bought together
},
{
name: 'Workout Essentials' ,
products: [ 'prod_shorts' , 'prod_shirt' , 'prod_socks' ],
discount: 0.15
}
];
for ( const bundle of bundles ) {
// Find items that match this bundle
const matchingItems = cart . items . filter (
item => bundle . products . includes ( item . productId )
);
// Check if all bundle products are present
const hasAllProducts = bundle . products . every (
productId => matchingItems . some ( item => item . productId === productId )
);
if ( hasAllProducts ) {
const originalTotal = matchingItems . reduce (
( sum , item ) => sum + ( item . price * item . quantity ), 0
);
const bundlePrice = Math . round ( originalTotal * ( 1 - bundle . discount ));
operations . push ({
merge: {
sourceCartItemIds: matchingItems . map ( item => item . id ),
title: bundle . name ,
price: bundlePrice ,
properties: {
_bundle: 'true' ,
original_price: originalTotal . toString (),
savings: ` ${ bundle . discount * 100 } % off`
}
}
});
}
}
return { operations };
}
Volume Pricing / Quantity Breaks
function transformCart ( input , config ) {
const operations = [];
const { cart } = input ;
// Define quantity break pricing
const quantityBreaks = {
'prod_tshirt' : [
{ minQty: 1 , priceEach: 2499 },
{ minQty: 3 , priceEach: 2199 },
{ minQty: 6 , priceEach: 1999 },
{ minQty: 12 , priceEach: 1799 }
]
};
for ( const item of cart . items ) {
const breaks = quantityBreaks [ item . productId ];
if ( ! breaks ) continue ;
// Find applicable tier
const applicableTier = [ ... breaks ]
. reverse ()
. find ( tier => item . quantity >= tier . minQty );
if ( applicableTier && applicableTier . priceEach < item . price ) {
const savings = ( item . price - applicableTier . priceEach ) * item . quantity ;
operations . push ({
update: {
cartItemId: item . id ,
price: applicableTier . priceEach ,
properties: {
... item . properties ,
_volume_discount: 'true' ,
original_price: item . price . toString (),
tier: ` ${ applicableTier . minQty } + @ $ ${ ( applicableTier . priceEach / 100 ). toFixed ( 2 ) } each`
}
}
});
}
}
return { operations };
}
VIP Customer Pricing
function transformCart ( input , config ) {
const operations = [];
const { cart , customer } = input ;
if ( ! customer ) return { operations };
// VIP tiers
const vipDiscounts = {
'vip_gold' : 0.15 ,
'vip_silver' : 0.10 ,
'vip_bronze' : 0.05
};
// Find customer's VIP tier
const vipTag = customer . tags . find ( tag => tag . startsWith ( 'vip_' ));
const discount = vipDiscounts [ vipTag ];
if ( ! discount ) return { operations };
// Apply VIP pricing to all items
for ( const item of cart . items ) {
// Skip items already on sale or marked non-discountable
if ( item . properties ?. _no_discount === 'true' ) continue ;
if ( item . price < item . originalPrice ) continue ;
const vipPrice = Math . round ( item . price * ( 1 - discount ));
operations . push ({
update: {
cartItemId: item . id ,
price: vipPrice ,
properties: {
... item . properties ,
_vip_price: 'true' ,
original_price: item . price . toString (),
discount_tier: vipTag
}
}
});
}
return { operations };
}
Product Substitution
function transformCart ( input , config ) {
const operations = [];
const { cart } = input ;
// Define substitutions (e.g., for out-of-stock items)
const substitutions = {
'variant_old_sku' : {
newVariantId: 'variant_new_sku' ,
reason: 'Product updated to new version'
},
'variant_discontinued' : {
newVariantId: 'variant_replacement' ,
reason: 'Original item discontinued, replaced with equivalent'
}
};
for ( const item of cart . items ) {
const substitution = substitutions [ item . variantId ];
if ( ! substitution ) continue ;
// Remove old item and add substitute
operations . push ({
remove: { cartItemId: item . id }
});
operations . push ({
add: {
variantId: substitution . newVariantId ,
quantity: item . quantity ,
properties: {
... item . properties ,
_substituted: 'true' ,
substitution_reason: substitution . reason ,
original_variant: item . variantId
}
}
});
}
return { operations };
}
Split Bundle into Components
function transformCart ( input , config ) {
const operations = [];
const { cart } = input ;
// Find bundles that need to be split for fulfillment
for ( const item of cart . items ) {
if ( item . productId !== 'prod_mystery_box' ) continue ;
// Mystery box contains 3 random items
const boxContents = getBoxContents ( item . variantId );
operations . push ({
split: {
cartItemId: item . id ,
items: boxContents . map (( content , index ) => ({
variantId: content . variantId ,
quantity: item . quantity ,
price: 0 , // Individual items show as $0
title: `Mystery Box Item ${ index + 1 } ` ,
properties: {
_from_bundle: item . id ,
bundle_name: 'Mystery Box'
}
}))
}
});
}
return { operations };
}
Cart Display
After transformations, the cart shows modified items:
Your Cart
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Complete Skincare Set ← Merged bundle
Cleanser + Toner + Moisturizer
$79.99 ($99.97) Save 20%
T-Shirt x 6 ← Volume pricing
$19.99 each ($24.99)
Bulk discount: 6+ items
FREE GIFT: Travel Bag ← Auto-added gift
$0.00
Free with orders $50+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Subtotal: $199.93
You saved: $35.95
Property Conventions
Use underscore-prefixed properties for internal data:
Property Purpose _free_giftMarks auto-added free items _bundleMarks merged bundle items _from_bundleLinks split items to original bundle _volume_discountMarks items with quantity pricing _vip_priceMarks VIP-discounted items _no_discountPrevents additional discounts _substitutedMarks substituted items
Properties starting with underscore are hidden from customers but accessible in Liquid templates and order data.
Error Handling
function transformCart ( input , config ) {
try {
const operations = [];
// Your transformation logic
// Validate operations
for ( const op of operations ) {
if ( op . update && ! cart . items . find ( i => i . id === op . update . cartItemId )) {
// Skip invalid operations
continue ;
}
// Add valid operations
}
return { operations };
} catch ( error ) {
console . error ( 'Cart transform error:' , error );
return { operations: [] }; // No changes on error
}
}
Best Practices
Don’t make unexpected changes. Merging items or changing prices should be transparent to the customer.
When applying discounts, store the original price in properties so it can be displayed as a strikethrough.
Test with single items, large quantities, mixed carts, and empty carts.
Don't remove customer items
Only remove items added by your function (like expired free gifts). Never remove customer-added items.
Ensure running the same transform twice produces the same result. Check for existing modifications.
Cart transforms run on every cart update. Keep logic fast and efficient.
See Also