> ## Documentation Index
> Fetch the complete documentation index at: https://spreecommerce.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Metadata

> How to store and retrieve custom metadata on carts, orders, and line items

The Store API supports storing arbitrary key-value **metadata** on carts (orders) and line items. Metadata is useful for tracking custom information like gift messages, attribution data, or integration-specific fields.

<Note>
  Metadata is different from [metafields](/developer/core-concepts/metafields). Metadata is simple JSON storage (untyped, no schema), while metafields are structured, typed, and schema-defined. Use metadata for integration data and internal tracking. Use metafields for customer-facing custom attributes.
</Note>

## Cart Metadata

You can attach metadata when creating a cart:

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  const cart = await client.carts.create({
    metadata: {
      utm_source: 'google',
      utm_campaign: 'summer_sale',
      referral_code: 'FRIEND20',
    },
  })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl -X POST 'http://localhost:3000/api/v3/store/carts' \
    -H 'X-Spree-Api-Key: pk_xxx' \
    -H 'Content-Type: application/json' \
    -d '{
      "metadata": {
        "utm_source": "google",
        "utm_campaign": "summer_sale",
        "referral_code": "FRIEND20"
      }
    }'
  ```
</CodeGroup>

## Cart Metadata (Update)

Update metadata on an existing cart:

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  await client.carts.update(cart.id, {
    metadata: {
      gift_message: 'Happy Birthday!',
      preferred_delivery: 'morning',
    },
  }, { spreeToken: cart.token })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl -X PATCH 'http://localhost:3000/api/v3/store/carts/cart_xxx' \
    -H 'X-Spree-Api-Key: pk_xxx' \
    -H 'X-Spree-Token: <order_token>' \
    -H 'Content-Type: application/json' \
    -d '{
      "metadata": {
        "gift_message": "Happy Birthday!",
        "preferred_delivery": "morning"
      }
    }'
  ```
</CodeGroup>

## Item Metadata

Attach metadata to individual items when adding or updating them:

### When Adding an Item

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  await client.carts.items.create(cart.id, {
    variant_id: 'variant_abc123',
    quantity: 1,
    metadata: {
      personalization: 'John',
      gift_wrap: true,
    },
  }, { spreeToken: cart.token })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl -X POST 'http://localhost:3000/api/v3/store/carts/cart_xxx/items' \
    -H 'X-Spree-Api-Key: pk_xxx' \
    -H 'X-Spree-Token: <order_token>' \
    -H 'Content-Type: application/json' \
    -d '{
      "variant_id": "variant_abc123",
      "quantity": 1,
      "metadata": {
        "personalization": "John",
        "gift_wrap": true
      }
    }'
  ```
</CodeGroup>

### When Updating an Item

Updating metadata **merges** with existing values rather than replacing them:

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  await client.carts.items.update(cart.id, 'li_xyz789', {
    metadata: {
      personalization: 'Jane', // Updates existing key
      engraving: 'With Love',  // Adds new key
    },
  }, { spreeToken: cart.token })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl -X PATCH 'http://localhost:3000/api/v3/store/carts/cart_xxx/items/li_xyz789' \
    -H 'X-Spree-Api-Key: pk_xxx' \
    -H 'X-Spree-Token: <order_token>' \
    -H 'Content-Type: application/json' \
    -d '{
      "metadata": {
        "personalization": "Jane",
        "engraving": "With Love"
      }
    }'
  ```
</CodeGroup>

<Info>
  Metadata values can be any JSON-serializable type: strings, numbers, booleans, arrays, or nested objects.
</Info>

## Metadata Structure

Metadata is stored as a flat JSON object. You can use any keys and values:

```json theme={"theme":"night-owl"}
{
  "metadata": {
    "string_value": "hello",
    "number_value": 42,
    "boolean_value": true,
    "nested_object": {
      "key": "value"
    }
  }
}
```

## Metadata vs Metafields

Spree has two permanent, complementary systems for custom data — **metadata for machines, metafields for humans**.

|                | Metadata                                                  | Metafields                                             |
| -------------- | --------------------------------------------------------- | ------------------------------------------------------ |
| **Purpose**    | Developer escape hatch — integration IDs, sync state      | Merchant-defined structured attributes                 |
| **Schema**     | Schemaless JSON — no definition required                  | Defined via MetafieldDefinitions (typed, validated)    |
| **Validation** | None                                                      | Type-specific validation                               |
| **Visibility** | Write-only in Store API, readable in Admin API            | Configurable (admin-only or public)                    |
| **Admin UI**   | JSON preview                                              | Dedicated form fields                                  |
| **Best for**   | Integration data, tracking, attribution, write-and-forget | Product specs, custom attributes, customer-facing data |
| **API access** | Write via Store API, read via Admin API                   | Read/write via both APIs                               |

Both systems are here to stay. For more details on metafields, see the [Metafields guide](/developer/core-concepts/metafields).
