Cart integration guide

Learn how to pass measurement data to Shopify cart line items so that the Measura app can correctly process and display measurement-based products.

Overview

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.

When to use this guide

Use this guide when:

  • Building a mobile app that integrates with Measura products
  • Creating a custom checkout experience
  • Integrating third-party systems with Measura
  • Programmatically adding measurement-based products to cart

Property types: hidden vs customer-facing

Cart line item properties fall into two categories:

Hidden properties (internal)

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 data

Related:

These properties are required for the Measura app to process measurement-based products correctly, but they are not visible to customers in the cart.

Customer-facing properties

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 name
  • unitPrice_{measurementType}_value_{unit} - Label for unit price property value
  • netWeight, netLength, netArea, netVolume, netTime - Labels for net measurement
  • netWeight_value_{unit}, etc. - Labels for net measurement values

Tip

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.

Required hidden properties (internal)

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

1. _measura_type (required)

Type: String

Description: The measurement type for this product

Valid Values: weight, length, area, volume, time

{
  "name": "_measura_type",
  "value": "weight"
}

2. _measura_amount (required)

Type: String

Description: The measurement value and unit, space-separated

Format: "{numeric_value} {unit_label}"

Rules:

  • Must contain exactly one space between the value and unit
  • Value must be a positive number (> 0)
  • Unit label must match a valid unit for the measurement type (see Getting valid unit labels from the API)
  • The unit label must exactly match the label returned by the API (from 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"
}

Optional hidden properties (internal)

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

3. _measura_unit_price (optional)

Type: String

Description: Unit pricing display string (e.g., "$10.00/kg")

{
  "name": "_measura_unit_price",
  "value": "$10.00/kg"
}

4. _measura_data (optional)

Type: String (JSON)

Description: Additional measurement data in JSON format

{
  "name": "_measura_data",
  "value": "{\"properties\":{\"Container weight\":\"0.1 kg\"}}"
}

Customer-facing cart properties

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.

Fetching localized labels from app settings

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"
      }
    }
  }
}

Using localized labels in cart properties

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"
}

Available localized label keys

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 label
  • unitPrice_{measurementType}_value_{unit} - Unit price value label (e.g., unitPrice_weight_value_kg)
  • netWeight, netLength, netArea, netVolume, netTime - Net measurement labels
  • netWeight_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.

Complete examples

Example 1: Adding a weight-based product

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
    }
  ]
}

Example 2: Adding a length-based product

{
  "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
    }
  ]
}

Example 3: Adding a volume-based product with container weight

{
  "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
    }
  ]
}

Getting valid unit labels from the API

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.

Common pitfalls and troubleshooting

Issue: Measurement data not being recognized

Symptoms: Cart line items are not processed as measurement-based products

Solutions:

  1. Verify _measura_type is one of: weight, length, area, volume, time
  2. Verify _measura_amount has exactly one space between value and unit
  3. Verify the unit label exactly matches the API response (unitMeasurement.unit)
  4. Verify the numeric value is positive (> 0)

Issue: Invalid unit error

Symptoms: Unit label is not recognized

Solutions:

  1. Check that the unit label matches exactly (case-sensitive)
  2. Verify the unit is valid for the measurement type (e.g., don't use kg for length type)
  3. Get the unit label from the API response rather than hardcoding

Integration workflow

Step 1: Fetch product/variant data and app settings

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.

Step 2: Extract measurement data and localized labels

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)

Step 3: Calculate measurement amount

Calculate the actual measurement amount based on user input or your application logic.

Step 4: Build cart line item properties

Construct the properties array with:

  • Hidden properties: _measura_type (measurement type), _measura_amount ("{calculated_value} {unit_label}"), and optional hidden properties
  • Customer-facing properties: Use localizedLabels (from the Get app settings endpoint) to create visible properties, replacing tokens with actual values

Step 5: Add to cart

Add the line item to the Shopify cart with the properties array.

Shopify cart API integration

Using Shopify Storefront API

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...
};

Using Shopify AJAX API

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
  })
});

Testing your integration

  1. Test with API data: Use real product/variant data from the Measura API
  2. Verify properties: Check that all required properties are present
  3. Validate format: Ensure _measura_amount format is correct
  4. Test different types: Test with all measurement types (weight, length, area, volume, time)
  5. Test edge cases: Test with decimal values, different units, and boundary values