Cart Transform: Expand Operation
Replace bundled products in the cart with their individual components
Overview
The Expand Lines block replaces bundled products in the cart with their individual components. The customer sees one line item in their cart, but the system processes it as containing multiple components.
- Product bundles — break down bundle products into their individual items
- Kit products — expand kits to show individual components with custom pricing
- Custom component products — transform products with attached component data into separate line items
- Dynamic pricing — apply per-variant pricing from metafield mappings
Two Methods
Components can come from two sources, and both can be used together:
- Function Studio configuration — define components directly in the block using the visual editor
- Cart line properties — attach component data to cart lines via the
_componentsproperty (set by your theme, app, or storefront)
Setup
Open your cart transform function
Navigate to the function you want to edit in Function Studio
Add the Expand Lines block
Click Add Action and select Expand Lines from the action list
Configure the block
Set the options described in the Settings section below
Settings
Cart Line Groups
Required
Select which groups of cart lines should be expanded. Groups must be defined earlier in your function using a Define Cart Line Groups block.
Component Items
Define the component items that will be added to the selected cart line. For each component:
Component Variant
Required
Select the product variant that will be added to the cart.
Quantity
How many of this component per bundle item (default: 1). When the bundled item has a quantity greater than 1, component quantities are automatically multiplied.
Component Price Override
Set a fixed price for this component, or leave at 0 to use the original product price. Hidden when Apply Bundle Discount is enabled — component prices are then controlled by the bundle discount instead.
Read From Attributes
Optional
When enabled, the block reads component data from the _components cart line property in addition to any components configured in Function Studio. See Cart Line Properties Configuration below.
Apply Bundle Discount
When enabled, a percentage discount is applied to the entire expanded bundle. Individual component price overrides are hidden — the discount applies to the bundle total instead.
Bundle Price Adjustment
Shown when Apply Bundle Discount is enabled
The percentage discount to apply to the bundle (0–100%). This field supports two modes:
- Static value — enter a fixed percentage (e.g., 10%)
- Linked value — click the link icon to connect the discount to a metafield, cart attribute, or line property. This allows different products to have different bundle discount percentages.
Note
Linking this field requires the Advanced plan.
Bundle Image
Optional
Custom image for the expanded bundle product.
Bundle Title
Optional
Custom display title for the expanded bundle.
Cart Line Properties Configuration
You can configure expansion by adding component data directly to your cart lines using the _components property. Enable Read from attributes in the block settings to use this method.
Components JSON Structure
The _components attribute should contain a JSON array of component objects:
[
{
"id": "12345",
"price": "29.99",
"qty": 2,
"properties": {
"color": "Red",
"size": "Large"
}
},
{
"id": "67890",
"price": "15.50",
"qty": 1,
"properties": {
"material": "Cotton"
}
}
]
Component Fields
id
Required
Product variant ID for the component. Must be the numeric part of the Shopify variant GID — e.g., "12345" from gid://shopify/ProductVariant/12345.
price
Optional
Fixed price per unit for this component. If omitted, defaults to 0. This becomes the component’s unit price in the expanded cart.
qty
Optional
Quantity of this component per bundled item. If omitted, defaults to 1.
properties
Optional
Custom key-value pairs for the component. Converted to line item attributes in the expanded cart. Keys and values must be strings.
Object Format with Per-Line Overrides
Instead of a plain array, you can use an object format that includes per-line overrides for the bundle image, title, and discount percentage. The system auto-detects which format you’re using.
{
"image": "https://cdn.shopify.com/bundle-image.jpg",
"title": "Custom Bundle Title",
"percentageDecrease": 20,
"items": [
{"id": "12345", "price": "29.99", "qty": 2, "properties": {"color": "Red"}},
{"id": "67890", "price": "19.99", "qty": 1}
]
}
image
Optional
Bundle image URL for this specific cart line. Overrides the global bundle image configured in Function Studio.
title
Optional
Bundle title for this specific cart line. Overrides the global bundle title.
percentageDecrease
Optional
Bundle percentage decrease for this specific cart line (e.g., 20 means 20% off). Overrides the bundle discount configured in Function Studio. Set to 0 to explicitly remove the discount for this line.
items
Required
Component items using the same format as the array format described above.
Setting the Components Property
The _components property can be set through various methods:
In Product Forms (Liquid Templates)
<input type="hidden" name="properties[_components]" value='[{"id":"12345","price":"29.99","qty":2}]'>
Via Ajax Cart API
{
"id": "12345",
"qty": 1,
"properties": {
"_components": '[{"id":"12345","price":"29.99","qty":2}]'
}
}
How It Works
Weighted Price Allocation
When you use both component-level fixed prices and a bundle discount percentage, Shopify doesn’t allow combining these directly. Function Studio automatically handles this by using a weighted price allocation algorithm:
Calculate total
The system sums all component prices (unit price × quantity)
Apply discount
The percentage discount is applied to the total
Distribute proportionally
The discounted total is distributed across components based on their original price weight
Set final prices
Each component’s final price is set to their allocated share
Example:
- Component A: $60 (weight: 60%)
- Component B: $40 (weight: 40%)
- Bundle discount: 10%
- Discounted total: $90
- Component A final price: $54 (60% of $90)
- Component B final price: $36 (40% of $90)
Dynamic Component Quantities
When the bundled item has a quantity greater than 1, component quantities are automatically multiplied:
- Bundle in cart: Quantity 3
- Component configuration: Quantity 2 per bundle
- Result: 6 total components (3 × 2)
Combined Configuration Sources
When both Function Studio components and cart line properties are used, the system combines components from both sources. Function Studio components are added first, then any components from the _components property.
Variant Price Mapping
The Variant Price Mapping block parses a CSV metafield into a reusable mapping variable. Place it before an Expand Lines block, then select the output variable in the Expand block’s Price Mapping dropdown to drive both the component list and component prices from the CSV.
When price mapping is used with expansion, the CSV defines which components to add (by variant ID) and their per-unit prices — replacing or augmenting components configured in Function Studio.
Block Settings
Variable Name
Required
Name of the output variable that stores the parsed mapping (e.g., priceMapping). This is what appears in the Price Mapping dropdown of downstream blocks.
Metafield
Required
The product or variant metafield containing the CSV mapping data. Must be a string-type metafield.
Mapping Levels
Optional
An ordered list of fields used to build the lookup key. Common examples:
- Market ID — different component prices per Shopify market
- Currency code — different prices per currency
- Parent variant ID — different components per bundle parent
At runtime, each level is resolved and the values are joined in order (no separator) to form the key that’s matched against the first column of the CSV.
CSV Format
For Expand Lines, each CSV line uses a 4-part format separated by pipes (|):
<level_combo>|<variant_id>|<qty_range>|<price>
level_combo— the resolved mapping-level values, joined in the configured order. Must match exactly.variant_id— numeric Shopify variant ID of the component to add (e.g.,52592015212808fromgid://shopify/ProductVariant/52592015212808).qty_range— eithermin-max(inclusive) or a singleminvalue (interpreted asminto unlimited). Matched against the cart line quantity of the bundle.price— per-unit component price as a decimal number.
All matching rows for a given level_combo + qty_range are added as components — so one CSV block can expand a bundle into many components at once.
Note
Each mapped component is added with quantity 1 — the qty_range column matches the bundle’s cart quantity to select which rows apply, it doesn’t set the component quantity. This differs from components configured directly in Function Studio, whose quantities are multiplied by the bundle quantity.
Note
Lines that don’t have exactly 4 parts are skipped. This lets you store both l_expand (4-part) and l_update (3-part) mappings in the same metafield.
Example Metafield Value
Bundle expansion keyed by parent variant ID — one mapping level resolving to the bundle parent variant (101904318728):
101904318728|52592015212808|1|9.99
101904318728|52592015245576|1|14.99
101904318728|52592015278344|1|4.99
When a bundle with parent variant 101904318728 is in the cart, it expands into three components at the listed per-unit prices.
Quantity-aware component pricing — component price changes at quantity 5+:
101904318728|52592015212808|1-4|9.99
101904318728|52592015212808|5|7.99
101904318728|52592015245576|1-4|14.99
101904318728|52592015245576|5|11.99
Two mapping levels — parent variant plus market ID, concatenated into the key column:
101904318728US|52592015212808|1|9.99
101904318728EU|52592015212808|1|8.50
Tip
CSV content is typically stored in a multi-line string metafield. The block trims whitespace on each line and ignores blank lines.
Examples
Example 1: Static Components (Function Studio)
A “Starter Kit” bundle expands into its individual components.
Create a cart line group
Add a “Define Cart Line Groups” block with group name STARTER_KITS
Add the Expand block
Select Expand Lines and set Cart Line Groups to STARTER_KITS
Add components
Add T-shirt variant (qty 1, $25.99), Cap variant (qty 1, $15.99), and Stickers variant (qty 2, $5.99)
Result
Bundle item is replaced with a single line item containing all 3 components with combined pricing
Example 2: Dynamic Components from Cart Properties
Products with a _components property are automatically expanded.
Create a cart line group
Add a “Define Cart Line Groups” block with group name COMPONENT_BUNDLES
Add the Expand block
Select Expand Lines, set Cart Line Groups to COMPONENT_BUNDLES, and enable Read from attributes
Leave Component Items empty
Components come from the cart line’s _components property
Result
Each bundle is expanded using the component data attached to the cart line
Example 3: Dynamic Bundle Discount from Metafield
Different bundle products have different discount percentages stored in a variant metafield.
Set up metafields
Create a variant metafield custom.bundle_discount (type: number_decimal) and set values per variant
Create the group and block
Add a “Define Cart Line Groups” block for bundles, then an “Expand Lines” block
Enable bundle discount
Turn on Apply Bundle Discount, then click the link icon next to the discount field and select custom.bundle_discount
Result
Each bundle product is expanded with its own discount percentage pulled from the variant metafield
Example 4: Bundle Components Driven by a Price Mapping CSV
A single metafield defines both the component list and component pricing for each bundle parent.
Store the CSV on the parent variant
Add a variant metafield custom.bundle_mapping (type: multi-line text) on the bundle parent variant, with content like:
101904318728|52592015212808|1|9.99 101904318728|52592015245576|1|14.99 101904318728|52592015278344|1|4.99
Add a Variant Price Mapping block
Set Variable Name to priceMapping, select the custom.bundle_mapping metafield, and add one Mapping Level resolving to the parent variant ID
Add the Expand block
Create a cart line group for the bundle parents, add an Expand Lines block, and set Price Mapping to priceMapping. Leave Component Items empty — components come from the CSV
Result
Each bundle is expanded into the components listed in its CSV rows, priced at the values from the CSV
Best Practices
Component Setup
- Ensure all component variants exist and are published in your store
- Consider inventory management — component products may need separate stock tracking
- Test with different cart quantities to verify component multiplication
Pricing Strategy
- Use percentage discounts to incentivize bundles over individual purchases
- When using linked fields for the discount, ensure the linked field always resolves to a valid number between 0 and 100
- Use Price Mapping when you need per-variant component pricing that can be updated without redeploying the function
Customer Experience
- Use meaningful bundle titles so customers understand what they’re purchasing
- Provide a bundle image that represents the combined items
- The customer sees one line item — individual component prices are not visible
Important Considerations
Product Availability
- All component variants must exist in your store
- Components must be available (not archived or deleted)
- Consider inventory levels for component products
Cart Behavior
- Original bundle items are completely replaced by the expanded bundle
- All components are merged into a single line item in the cart
- Cart totals reflect the combined pricing of all components
- Individual component prices are not visible to customers
Data Format Requirements
- Cart properties must contain valid JSON
- Component IDs must be the numeric part of Shopify variant GIDs (e.g.,
12345fromgid://shopify/ProductVariant/12345) - Property keys and values must be strings
- Quantities must be positive numbers
Plan Requirements
- Linking the Bundle Price Adjustment field to a metafield or attribute requires the Advanced plan
Troubleshooting
Expansion Not Working
- Check your groups — review conditions in your line item groups
- Verify variant IDs — ensure all component variant IDs exist in your store
- Start simple — begin with basic expansion and add complexity gradually
Cart Properties Issues
- Check JSON format — ensure the
_componentsproperty contains valid JSON - Verify variant IDs — make sure all component IDs are correct numeric IDs
- Enable Read from attributes — the toggle must be on for cart properties to be read
- Test the property — add the property to a test cart and verify it’s set correctly
Pricing Problems
- Verify price format — prices in
_componentsJSON should be strings (e.g.,"29.99") - Check bundle discounts — confirm discount percentages are between 0 and 100
Components Not Appearing
- Check group matching — verify your cart items match the group conditions
- Review component data — ensure component variants are available and not archived
- Test step by step — use the function tester to see which components are being processed