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.
The Shop platform is in early access. Features and APIs may change before general availability.
The Shop platform is in early access. Features and APIs may change before general availability.
Anchor to What you'll learnWhat you'll learn
You'll create, set, and read custom data on Shop users through a simple membership program:
- Create a
MetafieldDefinitionto 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.
Anchor to RequirementsRequirements
- A Shop app 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.
Anchor to IntroductionIntroduction
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.
Anchor to Step 1: Use the Shop Partners API to create a MetafieldDefinitionStep 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.
Use your client credentials and HTTP Basic Authentication with the Shop Partners API. 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.
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.
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 Variables
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.
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.
Anchor to Step 2: Get a user access tokenStep 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.
Anchor to Step 2a: First-time exchange (consent token)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.
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.
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 Variables
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.
Anchor to Step 2b: Subsequent exchanges (publicId)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
Exactly one of consentToken or publicId should be provided per call.
Anchor to Handling the returned tokensHandling 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.
Anchor to Step 3: Set the Metafield on the UserStep 3: Set the Metafield on the User
With the user access token from Step 2, call metafieldsSet on the Shop Users API 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 Variables
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.
Anchor to Step 4: Read the Metafield from a Shopify FunctionStep 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.
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.
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.
Anchor to Discount Function input queryDiscount 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
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 for the full input schema for each target.
Anchor to Reading the same metafield from a Checkout UI extensionReading 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
The metafield is then available to the extension through the standard checkout extension APIs.
Anchor to Next stepsNext steps
- Browse the full list of metafield types you can use in your definitions.
- Learn more about Shopify Functions and Checkout UI extensions.
- Review the Shop Partners API and Shop Users API references.