Learn how to pass measurement data to Shopify cart line items so that the Measura app can correctly process and display measurement-based products.
This guide explains how to pass measurement data to Shopify cart line items so that the Measura app can correctly process and display measurement-based products. This is essential for mobile app builders, custom checkout integrations, and any third-party systems that need to add Measura products to a Shopify cart.
Use this guide when:
Cart line item properties fall into two categories:
Properties starting with _ are hidden from customers and used internally by the Measura app for processing. These include:
_measura_type - Measurement type_measura_amount - Measurement value and unit_measura_unit_price - Unit pricing data_measura_data - Additional measurement dataRelated:
These properties are required for the Measura app to process measurement-based products correctly, but they are not visible to customers in the cart.
Properties using localizedLabels are visible to customers in the cart. These labels are fetched from the Get app settings endpoint as part of the data.settings.localizedLabels field.
The LocalizedLabels object (returned by the app settings endpoint) contains keys for:
unitPrice - Label for unit price property nameunitPrice_{measurementType}_value_{unit} - Label for unit price property valuenetWeight, netLength, netArea, netVolume, netTime - Labels for net measurementnetWeight_value_{unit}, etc. - Labels for net measurement valuesTip
Always fetch localizedLabels from the Get app settings endpoint to ensure proper localization and formatting. Replace tokens in the label values with actual data when adding to cart.
When adding a measurement-based product to the cart, you must include the following hidden properties (starting with _) on the line item. These are used internally by the Measura app and are not visible to customers:
_measura_type - The measurement type_measura_amount - The measurement value and unit_measura_type (required)Type: String
Description: The measurement type for this product
Valid Values: weight, length, area, volume, time
{
"name": "_measura_type",
"value": "weight"
}_measura_amount (required)Type: String
Description: The measurement value and unit, space-separated
Format: "{numeric_value} {unit_label}"
Rules:
unitMeasurement.unit in variant responses){
"name": "_measura_amount",
"value": "2.5 kg"
}{
"name": "_measura_amount",
"value": "10 m"
}{
"name": "_measura_amount",
"value": "3.5 L"
}The following hidden properties are optional but can enhance the Measura app's processing. These are not visible to customers:
_measura_unit_price - Unit pricing display string_measura_data - Additional measurement data in JSON format_measura_unit_price (optional)Type: String
Description: Unit pricing display string (e.g., "$10.00/kg")
{
"name": "_measura_unit_price",
"value": "$10.00/kg"
}_measura_data (optional)Type: String (JSON)
Description: Additional measurement data in JSON format
{
"name": "_measura_data",
"value": "{\"properties\":{\"Container weight\":\"0.1 kg\"}}"
}To display measurement information to customers in the cart, add properties using the localized labels from the API. These labels are fetched from the Get app settings endpoint as part of the data.settings.localizedLabels field. These properties are visible to customers and should be formatted using the labels from localizedLabels.
LocalizedLabels are returned by the Get app settings endpoint. Fetch them using:
GET /api/v1/app-settings?locale=en
Authorization: Bearer {apiKey}The app settings response includes data.settings.localizedLabels with all available labels for the specified locale. If no locale is provided, the default locale (en) is used.
Related:
Important: Always fetch localizedLabels from the Get app settings endpoint. Do not hardcode label values, as they may vary by locale and configuration.
{
"success": true,
"data": {
"settings": {
"localizedLabels": {
"unitPrice": "Price per",
"unitPrice_weight_value_kg": "{Price} per {Quantity}kg",
"netWeight": "Net weight",
"netWeight_value_kg": "{Quantity} kg"
}
}
}
}After fetching localized labels, use them to create customer-visible cart properties. Replace tokens in the label values with actual data:
{Price} - Replace with formatted price (e.g., "$10.00"){Quantity} - Replace with quantity value without space (e.g., "5kg"). When quantity is 1, omit this token.{Quantity_With_Space} - Replace with quantity value with space (e.g., "5 kg"). When quantity is 1, omit this token.{Unit} - Replace with unit label (e.g., "kg", "m", "L")// Example: Using localizedLabels to create customer-facing properties
// First, fetch localizedLabels from the Get app settings endpoint:
// GET /api/v1/app-settings?locale=en
// Response includes: data.settings.localizedLabels
//
// Example localizedLabels from app settings:
// {
// "unitPrice": "Price per",
// "unitPrice_weight_value_kg": "{Price} per {Quantity}kg",
// "netWeight": "Net weight",
// "netWeight_value_kg": "{Quantity} kg"
// }
// Cart properties (visible to customers):
{
"name": "Price per", // from localizedLabels.unitPrice
"value": "$10.00 per 5kg" // from localizedLabels.unitPrice_weight_value_kg
// Replaced: {Price} → "$10.00", {Quantity} → "5"
},
{
"name": "Net weight", // from localizedLabels.netWeight
"value": "5 kg" // from localizedLabels.netWeight_value_kg
// Replaced: {Quantity} → "5"
}The LocalizedLabels object (returned by the Get app settings endpoint) contains dynamic keys based on enabled measurement types and units. Common patterns include:
unitPrice - Unit price property name labelunitPrice_{measurementType}_value_{unit} - Unit price value label (e.g., unitPrice_weight_value_kg)netWeight, netLength, netArea, netVolume, netTime - Net measurement labelsnetWeight_value_{unit}, etc. - Net measurement value labels (e.g., netWeight_value_kg)Important
Always fetch localizedLabels from the Get app settings endpoint and use the exact label values as the property names. The property values should be the label templates with tokens replaced with actual data.
This example includes both hidden properties (for Measura processing) and customer-facing properties (using localizedLabels):
{
"id": "gid://shopify/ProductVariant/123456789",
"quantity": 5,
"properties": [
// Hidden properties (internal, not visible to customers)
{
"name": "_measura_type",
"value": "weight"
},
{
"name": "_measura_amount",
"value": "2.5 kg"
},
// Customer-facing properties (visible to customers)
{
"name": "Price per", // from localizedLabels.unitPrice
"value": "$10.00 per 5kg" // from localizedLabels.unitPrice_weight_value_kg
},
{
"name": "Net weight", // from localizedLabels.netWeight
"value": "5 kg" // from localizedLabels.netWeight_value_kg
}
]
}{
"id": "gid://shopify/ProductVariant/987654321",
"quantity": 1,
"properties": [
// Hidden properties (internal)
{
"name": "_measura_type",
"value": "length"
},
{
"name": "_measura_amount",
"value": "10 m"
},
// Customer-facing properties
{
"name": "Net length", // from localizedLabels.netLength
"value": "10 m" // from localizedLabels.netLength_value_m
}
]
}{
"id": "gid://shopify/ProductVariant/456789123",
"quantity": 1,
"properties": [
// Hidden properties (internal)
{
"name": "_measura_type",
"value": "volume"
},
{
"name": "_measura_amount",
"value": "3.5 L"
},
{
"name": "_measura_data",
"value": "{\"properties\":{\"Container weight\":\"0.1 kg\"}}"
},
// Customer-facing properties
{
"name": "Net volume", // from localizedLabels.netVolume
"value": "3.5 L" // from localizedLabels.netVolume_value_L
}
]
}The most reliable way to get the correct unit label is from the API response. When you fetch a product or variant using the Measura API, the unitMeasurement.unit field contains the exact unit label you should use in _measura_amount.
Example API response:
{
"success": true,
"data": {
"variant": {
"id": "123456789",
"unitMeasurement": {
"unit": "kg",
"value": 1.0
}
}
}
}In this case, use "kg" as the unit label in your cart properties.
Tip
Always use the unit label from the API response rather than hardcoding values. This ensures compatibility with any unit configuration changes.
For a complete reference of all supported units, see the unit enum documentation: WeightUnit, LengthUnit, AreaUnit, VolumeUnit, and TimeUnit.
Symptoms: Cart line items are not processed as measurement-based products
Solutions:
_measura_type is one of: weight, length, area, volume, time_measura_amount has exactly one space between value and unitunitMeasurement.unit)Symptoms: Unit label is not recognized
Solutions:
kg for length type)Use the Measura API to get product information and localized labels:
// Fetch variant data
GET /api/v1/products/{productId}/variants/{variantId}
Authorization: Bearer {apiKey}
// Fetch app settings to get localizedLabels
// localizedLabels are returned in data.settings.localizedLabels
GET /api/v1/app-settings?locale=en
Authorization: Bearer {apiKey}See get specific variant and get app settings endpoint documentation.
Related:
Remember: localizedLabels are fetched from the Get app settings endpoint, not from the variant endpoint.
From the API responses, extract:
measurementType (from product or variant response)unitMeasurement.unit (the unit label to use, from variant response)unitMeasurement.value (the base unit value, from variant response)localizedLabels (from app settings response: data.settings.localizedLabels, for customer-facing properties)Calculate the actual measurement amount based on user input or your application logic.
Construct the properties array with:
_measura_type (measurement type), _measura_amount ("{calculated_value} {unit_label}"), and optional hidden propertieslocalizedLabels (from the Get app settings endpoint) to create visible properties, replacing tokens with actual valuesAdd the line item to the Shopify cart with the properties array.
This example shows how to use localizedLabels fetched from the Get app settings endpoint:
// localizedLabels should be fetched from GET /api/v1/app-settings
// Response: data.settings.localizedLabels
const addToCart = async (variantId, measurementType, value, unit, localizedLabels, price, quantity) => {
const mutation = `
mutation cartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
cartLinesAdd(cartId: $cartId, lines: $lines) {
cart {
id
}
}
}
`;
// Build hidden properties
const hiddenProperties = [
{ key: "_measura_type", value: measurementType },
{ key: "_measura_amount", value: `${value} ${unit}` }
];
// Build customer-facing properties from localizedLabels
const customerProperties = [];
if (localizedLabels.unitPrice && localizedLabels[`unitPrice_${measurementType}_value_${unit}`]) {
const unitPriceLabel = localizedLabels.unitPrice;
const unitPriceTemplate = localizedLabels[`unitPrice_${measurementType}_value_${unit}`];
const unitPriceValue = unitPriceTemplate
.replace("{Price}", price)
.replace("{Quantity}", quantity === 1 ? "" : `${quantity}${unit}`)
.replace("{Quantity_With_Space}", quantity === 1 ? "" : `${quantity} ${unit}`);
customerProperties.push({ key: unitPriceLabel, value: unitPriceValue });
}
const variables = {
cartId: cartId,
lines: [{
merchandiseId: variantId,
quantity: quantity,
attributes: [...hiddenProperties, ...customerProperties]
}]
};
// Execute mutation...
};This example shows how to use localizedLabels fetched from the Get app settings endpoint:
// First, fetch localizedLabels from GET /api/v1/app-settings
// Response includes: data.settings.localizedLabels
// Example: Adding to cart with hidden and customer-facing properties
const localizedLabels = {
unitPrice: "Price per",
unitPrice_weight_value_kg: "{Price} per {Quantity}kg",
netWeight: "Net weight",
netWeight_value_kg: "{Quantity} kg"
};
const quantity = 5;
const price = "$10.00";
const unit = "kg";
// Build properties
const properties = {
// Hidden properties (internal)
'_measura_type': 'weight',
'_measura_amount': '2.5 kg',
// Customer-facing properties
[localizedLabels.unitPrice]: localizedLabels.unitPrice_weight_value_kg
.replace("{Price}", price)
.replace("{Quantity}", quantity === 1 ? "" : `${quantity}${unit}`),
[localizedLabels.netWeight]: localizedLabels.netWeight_value_kg
.replace("{Quantity}", quantity)
.replace("{Unit}", unit)
};
fetch('/cart/add.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: variantId,
quantity: quantity,
properties: properties
})
});_measura_amount format is correct