---
title: Metafields API
description: >-
  Surface app-owned metafields from your extension config and write cart
  metafields during checkout.
api_version: 2026-07-rc
source_url:
  html: >-
    https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/target-apis/platform-apis/metafields-api
  md: >-
    https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/target-apis/platform-apis/metafields-api.md
---

# Metafields API

**Requires access to \[protected customer data]\(/docs/apps/store/data-protection/protected-customer-data) for some properties.:**

The Metafields API provides access to [app-owned metafields](https://shopify.dev/docs/apps/build/metafields#app-owned-metafields) and the ability to write cart metafields. Use this API to read metafield values that your app owns and that you've configured in `shopify.extension.toml`, and to apply changes to cart metafields during checkout.

Cart metafields written with `applyMetafieldChange()` are shared across all extensions. Changes made by one extension are visible to others.

### Use cases

* **Read app-owned metafields**: Access metafield values defined in your extension configuration to personalize the checkout experience.
* **Store data on the cart**: Save custom key-value pairs to the cart that persist through the checkout flow and carry over to the resulting order.
* **Clear stored cart data**: Remove a previously written cart metafield when the buyer changes their selection or the data is no longer needed.

### Support Targets (33)

### Supported targets

* [purchase.​address-autocomplete.​format-suggestion](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/address#format-a-selected-suggestion-)
* [purchase.​address-autocomplete.​suggest](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/address#suggest-address-completions-)
* [purchase.​checkout.​actions.​render-before](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/navigation#navigation-target)
* [purchase.​checkout.​block.​render](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/block#block-target)
* [purchase.​checkout.​cart-line-item.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/order-summary#line-item-targets)
* [purchase.​checkout.​cart-line-list.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/order-summary#checkout-cart-line-list-)
* purchase.​checkout.​chat.​render
* [purchase.​checkout.​contact.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/information#information-target)
* [purchase.​checkout.​delivery-address.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/shipping#render-after-delivery-address-)
* [purchase.​checkout.​delivery-address.​render-before](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/shipping#delivery-address-targets)
* [purchase.​checkout.​footer.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/footer#footer-target)
* [purchase.​checkout.​header.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/header#header-target)
* [purchase.​checkout.​payment-method-list.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/payment#render-after-payment-methods-)
* [purchase.​checkout.​payment-method-list.​render-before](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/payment#payment-targets)
* [purchase.​checkout.​pickup-location-list.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/local-pickup#render-after-pickup-locations-)
* [purchase.​checkout.​pickup-location-list.​render-before](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/local-pickup#location-list-targets)
* [purchase.​checkout.​pickup-location-option-item.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/local-pickup#location-option-item-target)
* [purchase.​checkout.​pickup-point-list.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/pickup-points#render-after-pickup-points-)
* [purchase.​checkout.​pickup-point-list.​render-before](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/pickup-points#pickup-points-targets)
* [purchase.​checkout.​reductions.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/order-summary#checkout-reductions-after-)
* [purchase.​checkout.​reductions.​render-before](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/order-summary#reductions-targets)
* [purchase.​checkout.​shipping-option-item.​details.​render](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/shipping#shipping-option-item-targets)
* [purchase.​checkout.​shipping-option-item.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/shipping#render-after-shipping-option-)
* [purchase.​checkout.​shipping-option-list.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/shipping#render-after-shipping-options-)
* [purchase.​checkout.​shipping-option-list.​render-before](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/checkout/shipping#shipping-option-list-targets)
* [purchase.​thank-you.​announcement.​render](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/thank-you/announcement#thank-you-announcement-)
* [purchase.​thank-you.​block.​render](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/thank-you/block#block-target)
* [purchase.​thank-you.​cart-line-item.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/thank-you/order-summary#line-item-targets)
* [purchase.​thank-you.​cart-line-list.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/thank-you/order-summary#thank-you-cart-line-list-)
* purchase.​thank-you.​chat.​render
* [purchase.​thank-you.​customer-information.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/thank-you/information#information-target)
* [purchase.​thank-you.​footer.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/thank-you/footer#footer-target)
* [purchase.​thank-you.​header.​render-after](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/targets/thank-you/header#header-target)

### Properties

The [`shopify` global object](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc#target-apis-define-what-your-extension-does) provides metafield data for the current checkout. Access the following properties on `shopify` to read [app-owned metafields](https://shopify.dev/docs/apps/build/metafields#metafield-ownership) and checkout metafields. Available to `purchase` extension targets.

* **appMetafields**

  **SubscribableSignalLike\<AppMetafieldEntry\[]>**

  **required**

  The metafields requested in the [`shopify.extension.toml`](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/configuration) file. These metafields are updated when there's a change in the merchandise items being purchased by the customer.

  App owned metafields are supported and are returned using the `$app` format. The fully qualified reserved namespace format such as `app--{your-app-id}[--{optional-namespace}]` isn't supported. See [app owned metafields](https://shopify.dev/docs/apps/build/custom-data/ownership#reserved-prefixes) for more information.

  [](https://shopify.dev/apps/store/data-protection/protected-customer-data)Requires access to [protected customer data](https://shopify.dev/docs/apps/store/data-protection/protected-customer-data).

### SubscribableSignalLike

Represents a reactive signal interface that provides both immediate value access and subscription-based updates. Enables real-time synchronization with changing data through the observer pattern. This interface extends \`ReadonlySignalLike\` with deprecated fields that are still supported for backwards compatibility.

* current

  The current value of the signal. Equivalent to \`.value\`, accessing this property subscribes to changes when used in a reactive context.

  ```ts
  T
  ```

* destroy

  Cleans up the subscription and releases any resources held by this signal. After calling \`destroy()\`, the signal stops receiving updates from the main thread.

  ```ts
  () => Promise<void>
  ```

* subscribe

  Subscribes to value changes and calls the provided function whenever the value updates. Returns an unsubscribe function to clean up the subscription. Use to automatically react to changes in the signal's value.

  ```ts
  (fn: (value: T) => void) => () => void
  ```

* value

  The current value of the signal. This property provides immediate access to the current value without requiring subscription setup. Use for one-time value checks or initial setup.

  ```ts
  T
  ```

### AppMetafieldEntry

An entry that pairs a Shopify resource with one of its \[metafields]\(/docs/apps/build/custom-data/metafields). Each entry contains a \`target\` identifying which resource the metafield belongs to and a \`metafield\` object with the actual data.

* metafield

  The metafield data, including the namespace, key, value, and content type. Use the \`namespace\` and \`key\` together to uniquely identify the metafield within its resource.

  ```ts
  AppMetafield
  ```

* target

  The Shopify resource that this metafield is attached to, including the resource type (such as \`'product'\` or \`'customer'\`) and its globally-unique ID. {% include /apps/checkout/privacy-icon.md %} Requires access to \[protected customer data]\(/docs/apps/store/data-protection/protected-customer-data) when the type is \`customer\`, \`company\` or \`companyLocation\`.

  ```ts
  AppMetafieldEntryTarget
  ```

### AppMetafield

Represents a custom \[metafield]\(/docs/apps/build/custom-data/metafields) attached to a resource such as a product, variant, customer, or shop.

* key

  The identifier for the metafield within its namespace, such as \`'ingredients'\` or \`'shipping\_weight'\`.

  ```ts
  string
  ```

* namespace

  The namespace that the metafield belongs to. Namespaces group related metafields and prevent naming collisions between different apps. App owned metafield namespaces are returned using the \`$app\` format. See \[app owned metafields]\(/docs/apps/build/custom-data/ownership#reserved-prefixes) for more information.

  ```ts
  string
  ```

* type

  The metafield's \[type name]\(/docs/apps/build/custom-data/metafields/list-of-data-types), such as \`'single\_line\_text\_field'\` or \`'json'\`. This is the full type identifier, whereas \`valueType\` is a simplified category.

  ```ts
  string
  ```

* value

  The value of a metafield, stored as a string regardless of the underlying type. For JSON metafields, parse the string to access structured data.

  ```ts
  string
  ```

* valueType

  The metafield's information type. - \`'boolean'\`: A true or false value. - \`'float'\`: A decimal number value. - \`'integer'\`: A whole number value. - \`'json\_string'\`: A JSON-encoded string value. - \`'string'\`: A plain text value.

  ```ts
  'boolean' | 'float' | 'integer' | 'json_string' | 'string'
  ```

### AppMetafieldEntryTarget

The Shopify resource that a metafield is attached to. Each entry identifies a specific resource by its type and globally-unique ID, so you can trace where the data comes from.

* id

  The globally-unique identifier of the Shopify resource, in \[GID]\(/docs/api/usage/gids) format. Use this value to match the metafield to a specific resource in your extension or when querying the \[Storefront API]\(/docs/api/storefront).

  ```ts
  string
  ```

* type

  The kind of Shopify resource this metafield belongs to: - \`'customer'\`: The customer who placed the order. - \`'product'\`: A product in the merchant's catalog. - \`'shop'\`: The merchant's shop. - \`'shopUser'\`: A staff member or collaborator account on the shop. - \`'variant'\`: A specific variant of a product. - \`'company'\`: A \[B2B]\(/docs/apps/build/b2b) company associated with the order. - \`'companyLocation'\`: A location belonging to a \[B2B]\(/docs/apps/build/b2b) company. - \`'cart'\`: The cart associated with the checkout. {% include /apps/checkout/privacy-icon.md %} Requires level 1 access to \[protected customer data]\(/docs/apps/store/data-protection/protected-customer-data) when the type is \`customer\`, \`company\` or \`companyLocation\`.

  ```ts
  | 'customer'
      | 'product'
      | 'shop'
      | 'shopUser'
      | 'variant'
      | 'company'
      | 'companyLocation'
      | 'cart'
  ```

### Methods

The [`shopify` global object](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc#target-apis-define-what-your-extension-does) provides methods to modify cart metafields. Access the following methods on `shopify` to apply metafield changes. Available to `purchase.checkout` extension targets.

* **applyMetafieldChange**

  **(change: MetafieldChange) => Promise\<MetafieldChangeResult>**

  **required**

  Creates, updates, or removes a cart metafield on the checkout. On success, the [`metafields`](https://shopify.dev/docs/api/checkout-ui-extensions/2026-07-rc/apis/metafields#properties-propertydetail-metafields) property updates to reflect the change.

  Cart metafields are copied to order metafields at order creation time if there's a matching order metafield definition with the [`cart to order copyable`](https://shopify.dev/docs/apps/build/metafields/use-metafield-capabilities#cart-to-order-copyable) capability enabled.

  **Note:** This method returns an error if the \<a href="/docs/api/checkout-ui-extensions/2026-07-rc/apis/cart-instructions#properties-propertydetail-instructions">cart instruction\</a> \<code>\<span class="PreventFireFoxApplyingGapToWBR">metafields.can\<wbr/>Set\<wbr/>Cart\<wbr/>Metafields\</span>\</code> is false, or the buyer is using an accelerated checkout method, such as Apple Pay or Google Pay.

### MetafieldChange

The input for \`applyMetafieldChange()\`. Use the \`type\` property to specify the operation. - \`MetafieldRemoveCartChange\` (\`type: 'removeCartMetafield'\`): Removes an existing cart \[metafield]\(/docs/apps/build/custom-data/metafields). - \`MetafieldUpdateCartChange\` (\`type: 'updateCartMetafield'\`): Creates or updates a cart metafield.

```ts
MetafieldRemoveCartChange | MetafieldUpdateCartChange
```

### MetafieldRemoveCartChange

Removes a cart \[metafield]\(/docs/apps/build/custom-data/metafields). Pass this to \`applyMetafieldChange()\` to delete a metafield by key and namespace.

* key

  The name of the metafield to remove.

  ```ts
  string
  ```

* namespace

  The namespace of the metafield to remove.

  ```ts
  string
  ```

* type

  Identifies this as a cart metafield removal. Set this when creating a change to delete an existing metafield by key and namespace.

  ```ts
  'removeCartMetafield'
  ```

### MetafieldUpdateCartChange

Creates or updates a cart \[metafield]\(/docs/apps/build/custom-data/metafields). Pass this to \`applyMetafieldChange()\` to set a metafield value. If a metafield with the provided key and namespace doesn't already exist, then it gets created.

* metafield

  The metafield data to set on the cart. If a metafield with this key and namespace already exists, then its value is replaced.

  ```ts
  { key: string; namespace?: string; value: string; type: string; }
  ```

* type

  Identifies this as a cart metafield creation or update. Set this when creating a change to set a metafield value.

  ```ts
  'updateCartMetafield'
  ```

### MetafieldChangeResult

The result of calling \`applyMetafieldChange()\`. Use the \`type\` property to determine whether the change succeeded or failed.

```ts
MetafieldChangeResultSuccess | MetafieldChangeResultError
```

### MetafieldChangeResultSuccess

The result of a successful metafield change. The \`type\` property is \`'success'\`.

* type

  Indicates that the metafield change was applied successfully.

  ```ts
  'success'
  ```

### MetafieldChangeResultError

The result of a failed metafield change. Check the \`message\` property for details about what went wrong.

* message

  A message that explains the error. This message is useful for debugging. It isn't localized and shouldn't be displayed to the buyer. Render your own localized error text rather than displaying this message to the buyer.

  ```ts
  string
  ```

* type

  Indicates that the metafield change couldn't be applied. Check the \`message\` property for details.

  ```ts
  'error'
  ```

### Available Preact hooks

The following Preact hooks provide a convenience wrapper that makes it easier to perform common tasks without writing your own logic.

## use​App​Metafields(**[filters](#useappmetafieldsgeneratedtype-propertydetail-filters)**​)

Returns the metafields configured with `shopify.extension.toml`.

### Parameters

* **filters**

  **AppMetafieldFilters**

  **Default: {}**

### Returns

* **AppMetafieldEntry\[]**

### AppMetafieldFilters

* id

  ```ts
  string
  ```

* key

  ```ts
  string
  ```

* namespace

  To filter for app owned metafields, use the \`$app\` format. The fully qualified reserved namespace format such as \`app--{your-app-id}\[--{optional-namespace}]\` is not supported. See \[app owned metafields]\(/docs/apps/build/custom-data/ownership#reserved-prefixes) for more information.

  ```ts
  string
  ```

* type

  ```ts
  'customer' | 'product' | 'shop' | 'shopUser' | 'variant' | 'company' | 'companyLocation' | 'cart'
  ```

Examples

### Examples

* #### Read app-owned metafields

  ##### Description

  Access metafields defined in \`shopify.extension.toml\` that are owned by your app. This example uses the \`$app\` namespace, which gives your app exclusive control over the metafield's structure, data, and permissions. See \[app-owned metafields]\(/docs/apps/build/custom-data/ownership#reserved-prefixes) for configuration details.

  ##### jsx

  ```jsx
  import '@shopify/ui-extensions/preact';
  import {render} from 'preact';

  import {useAppMetafields} from '@shopify/ui-extensions/checkout/preact';

  export default function extension() {
    render(<Extension />, document.body);
  }

  function Extension() {
    const [energyRating] = useAppMetafields({
      namespace: '$app',
      key: 'energy-rating',
      type: 'product',
    }).filter(
      (entry) =>
        entry.target.id ===
        shopify.target.value.merchandise.id,
    );

    return (
      energyRating && (
        <s-text>
          Energy rating:{' '}
          {energyRating.metafield.value}
        </s-text>
      )
    );
  }
  ```

  ##### TOML

  ```toml
  # other configs omitted

  [[extensions.metafields]]
  # tip: you can use $app:some-namespace to further segment your data
  namespace = "$app"
  key = "energy-rating"
  ```

* ####

  ##### Description

  Save custom data to the cart for use later in the order flow. This example checks \`canSetCartMetafields\` before rendering a save button, then calls \`shopify.applyMetafieldChange()\` with the \`updateCartMetafield\` type to store a gift message preference.

  ##### jsx

  ```jsx
  import '@shopify/ui-extensions/preact';
  import {render} from 'preact';

  export default function extension() {
    render(<Extension />, document.body);
  }

  function Extension() {
    const canSet =
      shopify.instructions.value.metafields
        .canSetCartMetafields;

    async function savePreference() {
      const result =
        await shopify.applyMetafieldChange({
          type: 'updateCartMetafield',
          metafield: {
            namespace: '$app:preferences',
            key: 'gift-message',
            type: 'single_line_text_field',
            value: 'Happy birthday!',
          },
        });

      if (result.type === 'error') {
        console.error(result.message);
      }
    }

    if (!canSet) {
      return null;
    }

    return (
      <s-button onClick={savePreference}>
        Save gift message
      </s-button>
    );
  }
  ```

***

## Best practices

* **Check cart instructions before writing**: Use `instructions.metafields.canSetCartMetafields` and `instructions.metafields.canDeleteCartMetafield` from the [Cart Instructions API](https://shopify.dev/docs/api/checkout-ui-extensions/apis/cart-instructions) to verify that metafield operations are permitted before calling `applyMetafieldChange`.
* **Use the `$app` namespace for app-owned data**: Metafields under the `$app` namespace are exclusively controlled by your app. Other extensions can't read or modify them, making this the safest place to store app-specific data.

***

## Limitations

* Cart metafield changes aren't available when the buyer uses an accelerated checkout method such as Apple Pay or Google Pay.

***
