---
title: "Metadata"
sidebarTitle: "Metadata"
description: "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 [custom fields](../../developer/core-concepts/metafields.md). Metadata is simple JSON storage (untyped, no schema), while custom fields are structured, typed, and schema-defined. Use metadata for integration data and internal tracking. Use custom fields for customer-facing custom attributes.

## Cart Metadata

You can attach metadata when creating a cart:


```typescript SDK
const cart = await client.carts.create({
  metadata: {
    utm_source: 'google',
    utm_campaign: 'summer_sale',
    referral_code: 'FRIEND20',
  },
})
```

```bash cURL
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"
    }
  }'
```


## Cart Metadata (Update)

Update metadata on an existing cart:


```typescript SDK
await client.carts.update(cart.id, {
  metadata: {
    gift_message: 'Happy Birthday!',
    preferred_delivery: 'morning',
  },
}, { spreeToken: cart.token })
```

```bash cURL
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"
    }
  }'
```


## Item Metadata

Attach metadata to individual items when adding or updating them:

### When Adding an Item


```typescript SDK
await client.carts.items.create(cart.id, {
  variant_id: 'variant_abc123',
  quantity: 1,
  metadata: {
    personalization: 'John',
    gift_wrap: true,
  },
}, { spreeToken: cart.token })
```

```bash cURL
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
    }
  }'
```


### When Updating an Item

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


```typescript SDK
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
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"
    }
  }'
```


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

## Metadata Structure

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

```json
{
  "metadata": {
    "string_value": "hello",
    "number_value": 42,
    "boolean_value": true,
    "nested_object": {
      "key": "value"
    }
  }
}
```

## Metadata vs Custom Fields

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

| | Metadata | Custom Fields |
|-|----------|------------|
| **Purpose** | Developer escape hatch — integration IDs, sync state | Merchant-defined structured attributes |
| **Schema** | Schemaless JSON — no definition required | Defined via CustomFieldDefinitions (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 custom fields, see the [Custom Fields guide](../../developer/core-concepts/metafields.md).
