---
title: Store metafields on Shop users
description: Store custom data on Shop users as metafields and read it from Shopify Functions and Checkout UI extensions.
source_url:
  html: https://shopify.dev/docs/api/shop/guides/use-cases/metafields
  md: https://shopify.dev/docs/api/shop/guides/use-cases/metafields.md
---

# Store metafields on Shop users

After a buyer authenticates through Sign in with Shop and you've exchanged a consent token for an access token, you can store custom data on the user with metafields. This data is available in Shop Pay checkouts and readable from Checkout UI extensions and Shopify Functions.

**Developer preview:**

The Shop platform is in early access. Features and APIs may change before general availability.

***

## What you'll learn

You'll create, set, and read custom data on Shop users through a simple membership program:

* Create a `MetafieldDefinition` to structure your data using the Shop Partners API.
* Set a metafield on a user using the Shop Users API.
* Create a discount Function that reads your metafield to offer members a discount.

***

## Requirements

* A [Shop app](https://shopify.dev/docs/api/shop/guides/creating-a-client) with a client ID and secret.
* A user who has connected to your app through Sign in with Shop.
* An app extension that can create Functions.

***

## Introduction

The Shop User is Shopify's cross-merchant buyer model (where the person it represents is referred to as the Shopper). The data in the Shop User model is owned by the Shopper and controlled by Shopify. As a Partner, you can access data the Shopper has granted you, or data you own and have stored on the Shop User, like metafields.

If you have used metafields on other types this will be familiar to you, but there are a few restrictions because this data lives on the Shopper:

* All Shop User metafields are `structured`: they must be backed by a definition.
* All Shop User metafields are private, by default, to the Partner that created them. Your app-reserved namespace is implicitly used for data privacy.

***

## Step 1: Use the Shop Partners API to create a Metafield​Definition

For this membership example, you'll create a simple boolean field. You can use any of the supported [metafield types](https://shopify.dev/docs/apps/build/custom-data/metafields/list-of-data-types).

Use your [client credentials](https://shopify.dev/docs/api/shop/guides/creating-a-client) and HTTP Basic Authentication with the [Shop Partners API](https://shopify.dev/docs/api/shop-partners/latest). The app that creates the definition is automatically granted the Admin access policy on it; you can grant additional access policies later if you need other apps to read or write the same field.

**One-time setup:**

You only need to do this step once per definition. It declares the shape of the data and establishes access control over every metafield of that definition.

Endpoint: `https://shop.app/api/latest/partners/graphql.json`

## GraphQL Mutation

```graphql
mutation DefineMetafield($definition: MetafieldDefinitionCreateInput!) {
  metafieldDefinitionCreate(definition: $definition) {
    createdDefinition {
      key
      type {
        name
        category
      }
      description
    }
    userErrors {
      field
      message
    }
  }
}
```

## GraphQL Variables

```json
{
  "definition": {
    "key": "my-membership",
    "name": "My Membership",
    "description": "Presence of this field indicates that the current buyer has a membership to the My Membership Program",
    "type": "boolean"
  }
}
```

**Protect your client secret:**

Client credentials must only be used from a trusted server, never from a browser, mobile app, Shopify Function, or Checkout UI extension. Load them from a secret manager or environment variable rather than embedding them in source.

Sharing this definition with another app (via an additional access policy) effectively shares Shopper-owned data with that app. Treat each grant as a privacy decision, not a convenience.

***

## Step 2: Get a user access token

To write a metafield onto a specific Shop User, you need an access token scoped to that Shopper. Use the `fetchTokensForUser` mutation on the Shop Partners API, authenticating with your client credentials over HTTP Basic Authentication.

This mutation has two modes; you'll typically use the second one after the first exchange.

### Step 2a: First-time exchange (consent token)

The first time a Shopper authenticates to your app through Sign in with Shop on a merchant's storefront, that flow gives you a signed `consentToken` (a short-lived JWT) representing the Shopper's delegated consent to your app. Exchange it for a user access token and a `publicId` you can store and re-use.

**Where the consent token comes from:**

You only get a `consentToken` as the result of a Shopper completing a Sign in with Shop flow with your app on a merchant's storefront. Don't construct one yourself, and don't accept one from arbitrary input.

Endpoint: `https://shop.app/api/latest/partners/graphql.json`

## GraphQL Mutation

```graphql
mutation FetchTokensForUser($consentToken: String, $publicId: String) {
  fetchTokensForUser(consentToken: $consentToken, publicId: $publicId) {
    publicId
    accessToken
    refreshToken
    expiresIn
    tokenType
    scope
    userErrors {
      field
      message
    }
  }
}
```

## GraphQL Variables

```json
{
  "consentToken": "<JWT from the Sign in with Shop flow>"
}
```

Persist the returned `publicId` against your own record of this Shopper. You won't need the `consentToken` again; use `publicId` for every subsequent token exchange.

### Step 2b: Subsequent exchanges (public​Id)

Once you have a `publicId` for a Shopper, use the same mutation with `publicId` instead of `consentToken` to mint a fresh access token whenever you need one.

## GraphQL Variables

```json
{
  "publicId": "<stored publicId for this Shopper>"
}
```

Exactly one of `consentToken` or `publicId` should be provided per call.

### Handling the returned tokens

Use the `accessToken` as a Bearer token in Step 3. Treat both tokens like any other user-scoped credential:

* Keep them server-side. Never expose them to the storefront, browser, Shopify Function, or Checkout UI extension.
* Never log the access or refresh token (including in error reports or analytics).
* Store refresh tokens encrypted at rest and scope them per-Shopper.

***

## Step 3: Set the Metafield on the User

With the user access token from Step 2, call `metafieldsSet` on the [Shop Users API](https://shopify.dev/docs/api/shop-users/latest) to set the value of your metafield on this Shopper. Authenticate with `Authorization: Bearer <accessToken>`, not your client credentials. You can set multiple metafields in one call by passing more entries in the `metafields` array.

The `identifier.key` matches the `key` you chose in Step 1. The namespace is implicit, your app's reserved namespace is used automatically, so you don't need to specify it.

Endpoint: `https://shop.app/api/latest/users/graphql.json`

## GraphQL Mutation

```graphql
mutation SetMetafield($metafields: [MetafieldSetInput!]!) {
  metafieldsSet(metafields: $metafields) {
    metafields {
      value
      ownerId
      definition {
        key
        type {
          name
        }
        description
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

## GraphQL Variables

```json
{
  "metafields": [
    {
      "identifier": {"key": "my-membership"},
      "value": "true"
    }
  ]
}
```

Always check `userErrors` on the response: if validation fails (invalid value for the definition's `type`, missing definition, namespace conflict, etc.), the `metafields` array comes back empty rather than raising. If your `value` derives from buyer-controlled input, validate it against the definition's `type` server-side before calling `metafieldsSet`, as values written here can later flow into Functions and Checkout UI extensions.

***

## Step 4: Read the Metafield from a Shopify Function

Now that the metafield is set on the Shopper, you can read it during checkout from a Shopify Function or a Checkout UI extension. Both must be owned by an app created by a Partner.

**Try it on a development store:**

Local development against Shop User metafields in checkout is not currently supported. To exercise this end-to-end, install your app on a development store and test against it directly.

### Discount Function input query

For our membership example, we'll write a Function that grants a discount to any Shopper whose `my-membership` metafield is set. Functions declare the data they need through an input query at `extensions/<your-function>/src/run.graphql`.

## extensions/my-membership-discount/src/run.GraphQL

```graphql
query Input {
  cart {
    buyerIdentity {
      shopUser {
        metafield(key: "my-membership") {
          value
        }
      }
    }
  }
}
```

When the Function runs, `cart.buyerIdentity.shopUser.metafield.value` will be `"true"` for members and `null` for everyone else. Use that to decide whether to return a discount in your Function's `run` handler.

Add any other fields your `run` handler needs — for example, `cart.lines { id quantity }` for a per-line discount, or `cart.deliveryGroups` for a free-shipping discount. The available selections depend on the Function target you're building against; see the [Shopify Functions reference](https://shopify.dev/docs/api/functions) for the full input schema for each target.

### Reading the same metafield from a Checkout UI extension

Checkout UI extensions declare the metafields they want to load in their `shopify.extension.toml`. Add a `[[extensions.metafields]]` block for each metafield you need. The `$app` namespace resolves to your app's reserved namespace, the same one your definition was created under.

## extensions/checkout-ui/shopify.extension.toml

```toml
# Loads metafields on checkout resources, including the cart,
# products, customers, and more. Learn more:
# https://shopify.dev/docs/api/checkout-ui-extensions/unstable/configuration#metafields


[[extensions.metafields]]
namespace = "$app"
key = "my-membership"
```

The metafield is then available to the extension through the standard checkout extension APIs.

***

## Next steps

* Browse the full list of [metafield types](https://shopify.dev/docs/apps/build/custom-data/metafields/list-of-data-types) you can use in your definitions.
* Learn more about [Shopify Functions](https://shopify.dev/docs/api/functions) and [Checkout UI extensions](https://shopify.dev/docs/api/checkout-ui-extensions).
* Review the [Shop Partners API](https://shopify.dev/docs/api/shop-partners/latest) and [Shop Users API](https://shopify.dev/docs/api/shop-users/latest) references.

***