# Metafields

The Metafields API reads metafields from storefront JavaScript. It covers what Liquid cannot: Liquid resolves metafields while the page renders, and only for the objects that page already has, such as `product.metafields` on a product page. These endpoints run at any moment in the browser and take object ids, so you can read the metafields of any product, collection or the shop itself — after the page has loaded, in a script that never sees the Liquid context, or for several objects in one request.

For what metafields are and how to define them, see [Metafields overview](/docs/theme/theme-features/custom-data/metafields/overview). For the Liquid side, see [Use metafields in Liquid](/docs/theme/theme-features/custom-data/metafields/using-metafields-in-liquid).

Both endpoints are open to anonymous visitors.

All Ajax API requests should use [locale-aware URLs](/docs/theme/references/ajax-api/#locale-aware-urls) to give visitors a consistent experience.

## List the metafields of one kind of object

```text
GET /{locale}/api/front/metafields/{owner_resource}/list
```

Read the metafields of one kind of object as a flat list. `owner_resource` takes `shop`, `product`, `product_variant` or `collection`.

What comes back depends on how many `owner_ids` you send and whether you narrow the field with `namespace` and `key`:

| To read | `owner_ids` | `namespace` + `key` |
| --- | --- | --- |
| One metafield | one id | one pair |
| All metafields of one object | one id | leave out |
| The same field on several objects | repeat the parameter once per id | one pair |
| All metafields of several objects | repeat the parameter once per id | leave out |

`limit` and `page` only page through the result; they do not change which metafields are selected.

### Example request

**Example request**

```javascript
const params = new URLSearchParams({
  namespace: 'custom',
  key: 'manual_test',
  limit: '10'
});
params.append('owner_ids', '14a309ec-b966-4cf9-a9bb-33baa821fdbc');
params.append('owner_ids', 'f934ce3e-02c2-4e97-8412-19221eedbffd');

fetch(window.SHOPLAZZA.routes.root + '/api/front/metafields/product/list?' + params)
  .then((response) => response.json())
  .then((data) => {
    // do something...
  });
```

### Request parameters

- `owner_resource` string

  The kind of object: `shop`, `product`, `product_variant` or `collection`.
- `owner_ids` string

  The id of the object to read. Repeat the parameter to read several objects. For `shop`, this is the store id.
- `namespace` string

  Return only metafields in this namespace.
- `key` string

  Return only the metafield with this key. Use it together with `namespace`.
- `definition_id` string

  Return only the metafields created from this metafield definition. It is the same id that `definition_ids` takes on the batch query endpoint.
- `limit` number

  The number of metafields to return.
- `page` number

  The page of metafields to return, starting at 1. `0` is treated as `1`.

### Response

The `total`, `remain`, `page`, `total_page` and `have_next` fields stay at their zero values even when metafields are returned.

**Schema | Example**

- `data` object

  The response payload.

  - `metafields` object[]

    List of metafields.

    *   Array \[

    - `id` string

      ID of the metafield.
    - `store_id` number

      ID of the store the object belongs to.
    - `owner_id` string

      ID of the resource the metafield is attached to.
    - `owner_resource` string

      Resource type the metafield is attached to, for example `product`.
    - `namespace` string

      Namespace that groups the metafield.
    - `key` string

      Key of the metafield, unique within its namespace.
    - `value` string

      Value of the metafield; its data type is decided by `type`.
    - `type` string

      Value type of the metafield, for example `single_line_text_field`.
    - `description` string

      Description of the metafield.
    - `created_at` string

      Creation time, in ISO-8601 format.
    - `updated_at` string

      Last update time, in ISO-8601 format.
    *   \]
  - `total` number

    Total number of metafields matched.
  - `remain` number
  - `page` number

    Current page number.
  - `total_page` number

    Total number of pages.
  - `have_next` boolean

    Whether a next page is available.
- `msg` string

  Result message returned with the response.
- `state` number

  Request result flag; `success` or `0` means the request succeeded.

```json
{
  "data": {
    "metafields": [
      {
        "id": "676328500579297095",
        "store_id": 2446407,
        "owner_id": "14a309ec-b966-4cf9-a9bb-33baa821fdbc",
        "owner_resource": "product",
        "namespace": "custom",
        "key": "manual_test",
        "value": "222222222",
        "type": "single_line_text_field",
        "description": "",
        "created_at": "2026-08-10T07:28:25Z",
        "updated_at": "2026-08-10T07:28:25Z"
      },
      {
        "id": "686766315775468871",
        "store_id": 2446407,
        "owner_id": "f934ce3e-02c2-4e97-8412-19221eedbffd",
        "owner_resource": "product",
        "namespace": "custom",
        "key": "manual_test",
        "value": "333333333",
        "type": "single_line_text_field",
        "description": "",
        "created_at": "2026-09-08T02:44:09Z",
        "updated_at": "2026-09-08T02:44:09Z"
      }
    ],
    "total": 0,
    "remain": 0,
    "page": 0,
    "total_page": 0,
    "have_next": false
  },
  "msg": "请求成功",
  "state": 0
}
```

**Read a single metafield**

There is no endpoint that returns one metafield by its id. To read a single metafield of any object, call this endpoint with the object's `owner_resource`, one `owner_ids` value, and the metafield's `namespace` and `key`. `data.metafields` then holds exactly one entry. Compare it with the example request above, which reads the same field on two products. This example reads one metafield of one product; use `shop`, `product_variant` or `collection` in the path for the other kinds of object:

```javascript
const params = new URLSearchParams({
  owner_ids: '14a309ec-b966-4cf9-a9bb-33baa821fdbc',
  namespace: 'custom',
  key: 'manual_test'
});

fetch(window.SHOPLAZZA.routes.root + '/api/front/metafields/product/list?' + params)
  .then((response) => response.json())
  .then((data) => {
    const metafield = data.data.metafields[0];
    console.log(metafield ? metafield.value : 'not set');
  });
```

The batch endpoint below does the same when `unique_keys` holds one `namespace` and `key` pair. Metafields cannot be created or changed from the storefront; use the [Metafield REST API](/api/metafield) for that.

## Query the metafields of several objects

```text
POST /{locale}/api/front/v2/metafields/{owner_resource}/query
```

Read the metafields of several objects in one request and get them back grouped by object. `owner_resource` takes `shop`, `product` or `collection`; any other value is rejected with `422` and `{"errors":["unsupported owner_resource"]}`.

Pick the metafields either by namespace and key with `unique_keys`, or by definition with `definition_ids`. Exactly one of the two must be present: sending neither or both is rejected with `422` and `{"errors":["exactly one of unique_keys or definition_ids is required"]}`.

For `owner_resource` `shop` you can leave `owner_ids` out, because the store is the only possible owner.

### Example request

**Example request**

```javascript
const data = {
  owner_ids: ['14a309ec-b966-4cf9-a9bb-33baa821fdbc'],
  unique_keys: [
    { namespace: 'custom', key: 'manual_test' }
  ]
};

fetch(window.SHOPLAZZA.routes.root + '/api/front/v2/metafields/product/query', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
  .then((response) => response.json())
  .then((data) => {
    // do something...
  });
```

### Request parameters

**Schema | Example**

- `owner_resource` string

  The kind of object: `shop`, `product` or `collection`.
- `owner_ids` string[]

  The ids of the objects to read. Optional when `owner_resource` is `shop`.
- `unique_keys` object[]

  The metafields to read, each an object with a `namespace` and a `key`.

  *   Array \[

  - `namespace` string
  - `key` string
  *   \]
- `definition_ids` string[]

  The metafield definitions to read. Send either this or `unique_keys`, not both.

```json
{
  "owner_ids": [
    "14a309ec-b966-4cf9-a9bb-33baa821fdbc"
  ],
  "unique_keys": [
    {
      "namespace": "custom",
      "key": "manual_test"
    }
  ]
}
```

### Response

**Schema | Example**

- `data` object

  The response payload.

  - `owner_metafields` object[]

    Metafields grouped by the resource they are attached to.

    *   Array \[

    - `owner_id` string

      ID of the resource the metafield is attached to.
    - `metafields` object[]

      List of metafields.

      *   Array \[

      - `id` string

        ID of the metafield.
      - `store_id` number

        ID of the store the object belongs to.
      - `owner_id` string

        ID of the resource the metafield is attached to.
      - `owner_resource` string

        Resource type the metafield is attached to, for example `product`.
      - `namespace` string

        Namespace that groups the metafield.
      - `key` string

        Key of the metafield, unique within its namespace.
      - `value` string

        Value of the metafield; its data type is decided by `type`.
      - `type` string

        Value type of the metafield, for example `single_line_text_field`.
      - `description` string

        Description of the metafield.
      - `created_at` string

        Creation time, in ISO-8601 format.
      - `updated_at` string

        Last update time, in ISO-8601 format.
      - `definition_id` string

        ID of the metafield definition the metafield is bound to.
      *   \]
    *   \]
- `msg` string

  Result message returned with the response.
- `state` number

  Request result flag; `success` or `0` means the request succeeded.

```json
{
  "data": {
    "owner_metafields": [
      {
        "owner_id": "14a309ec-b966-4cf9-a9bb-33baa821fdbc",
        "metafields": [
          {
            "id": "676328500579297095",
            "store_id": 2446407,
            "owner_id": "14a309ec-b966-4cf9-a9bb-33baa821fdbc",
            "owner_resource": "product",
            "namespace": "custom",
            "key": "manual_test",
            "value": "222222222",
            "type": "single_line_text_field",
            "description": "",
            "created_at": "2026-08-10T07:28:25Z",
            "updated_at": "2026-08-10T07:28:25Z",
            "definition_id": "676319747943433287"
          }
        ]
      }
    ]
  },
  "msg": "请求成功",
  "state": 0
}
```
