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.
Using Shopify themes?
If your integration runs in Shopify theme code, use the public Storefront API on window.Measura to build these properties for you.
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_data - Canonical measurement payload (required, see MeasuraData)Related:
_measura_data is the canonical hidden field for measurement processing.
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_data - Canonical measurement payload (see MeasuraData)_measura_data (required)Type: String (JSON)
Description: Canonical measurement payload used by Measura processing
Minimum Shape: measurement.type and measurement.dimensions[0] with unit and value
Full Schema: MeasuraData object
Rules:
measurement.type must be one of: weight, length, area, volume, timemeasurement.dimensions must include at least one entrymeasurement.dimensions[0].value must be a positive number (> 0)measurement.dimensions[0].unit must match a valid unit label from the API (see Getting valid unit labels from the API){
"name": "_measura_data",
"value": "{\"measurement\":{\"type\":\"weight\",\"dimensions\":[{\"unit\":\"kg\",\"value\":2.5}]},\"unitMeasurement\":{\"unit\":\"kg\",\"value\":1},\"properties\":{\"Net weight\":\"2.5 kg\"}}"
}No additional hidden Measura properties are required beyond _measura_data.
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_data",
"value": "{\"measurement\":{\"type\":\"weight\",\"dimensions\":[{\"unit\":\"kg\",\"value\":2.5}]},\"unitMeasurement\":{\"unit\":\"kg\",\"value\":1}}"
},
// 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_data",
"value": "{\"measurement\":{\"type\":\"length\",\"dimensions\":[{\"unit\":\"m\",\"value\":10}]},\"unitMeasurement\":{\"unit\":\"m\",\"value\":1}}"
},
// 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_data",
"value": "{\"measurement\":{\"type\":\"volume\",\"dimensions\":[{\"unit\":\"L\",\"value\":3.5}]},\"unitMeasurement\":{\"unit\":\"L\",\"value\":1},\"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_data.measurement.dimensions[0].unit.
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_data exists and is valid JSONmeasurement.type is one of: weight, length, area, volume, timemeasurement.dimensions[0] includes both unit and valueunitMeasurement.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)_measura_data payloadBuild a JSON payload with at least measurement.type and measurement.dimensions[0] (unit + value), then serialize it into _measura_data.
Construct the properties array with:
_measura_data onlylocalizedLabels (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 (cartId, variantId, measurementType, value, unit, localizedLabels, price, quantity) => {
const mutation = `
mutation cartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
cartLinesAdd(cartId: $cartId, lines: $lines) {
cart {
id
}
}
}
`;
// Build canonical measura payload
const measuraData = {
measurement: {
type: measurementType,
dimensions: [{ unit, value }]
},
unitMeasurement: {
unit,
value: 1
}
};
// Build hidden properties
const hiddenProperties = [
{ key: "_measura_data", value: JSON.stringify(measuraData) }
];
// 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";
const measurementValue = 2.5;
const measuraData = {
measurement: {
type: "weight",
dimensions: [{ unit, value: measurementValue }]
},
unitMeasurement: {
unit,
value: 1
}
};
// Build properties
const properties = {
// Hidden properties (internal)
'_measura_data': JSON.stringify(measuraData),
// 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_data is valid JSON with required measurement fields