---
gid: b96be8d2-1a22-4aa7-850f-43de89c4d0de
title: Building metafield writes into extensions
description: Learn how to write to metafields from a Customer account UI extension.
---

import CustomerAccountUiCreate from 'app/views/partials/apps/customer-accounts/ui-extensions/create.mdx'

<Repo
  extension="react"
  href="https://github.com/Shopify/customer-account-tutorials/tree/main/react/example-customer-account--metafields--react"
/>
<Repo
  extension="javascript"
  href="https://github.com/Shopify/customer-account-tutorials/tree/main/javascript/example-customer-account--metafields--js"
/>

<Picker name="extension">
  <PickerOption name="react" />
  <PickerOption name="javascript" />
</Picker>

<Overview>
  Writing to metafields directly from the [Customer Account API](/docs/api/customer) enables you to
  store additional information about customers within Shopify, without making a separate call to
  the [GraphQL Admin API](/docs/api/admin-graphql), a third-party server, or other external resource.

  In this tutorial, you'll create a **Profile** page extension that will enable a merchant
  to collect a customer’s preferred nickname and pass that input into a metafield.

  <video autoPlay muted loop controls
          aria-label="An inline extension in the Profile page that adds a new Preferences card between the personal information card and the Addresses card">
    <source src="/assets/apps/customer-accounts/metafields-extension.webm" type="video/webm" />
  </video>

  ## Limitations

    Metafield writes are only supported on the [`Customer`](/docs/api/customer/latest/objects/Customer), [`Order`](/docs/api/customer/latest/objects/Order), [`Company`](/docs/api/customer/latest/objects/Company), and [`CompanyLocation`](/docs/api/customer/latest/objects/CompanyLocation) objects. Metafield writes are available as of the `2024-07` version of the Customer Account API.


  ## What you'll learn

  In this tutorial, you'll learn how to do the following tasks:

  - Use the GraphQL Admin API to create a metafield definition with permissions to read and write to metafields using the [Customer Account API](/docs/api/customer).
  - Create an extension that’s rendered on the customer account **Profile** page.
  - Use the Customer Account API to write data to a metafield.

</Overview>

<Requirements>
  <Requirement
    href="https://www.shopify.com/partners"
    label="Create a Partner account"
  ></Requirement>
  <Requirement
    href="/docs/apps/tools/development-stores#create-a-development-store-to-test-your-app"
    label="Create a development store"
  >
    The development store should be pre-populated with test data.
  </Requirement>
  <Requirement href="/docs/apps/build/scaffold-app" label="Scaffold an app">
    Scaffold an app that uses Shopify CLI. This tutorial is compatible with the [Remix template](/docs/apps/build/build?framework=remix).
  </Requirement>
  <Requirement href="/docs/apps/launch/protected-customer-data" label="Request access to Protected Customer Data">
    The Customer Account API requires access to Level 1 Protected Customer Data. [Request access](/docs/apps/launch/protected-customer-data#request-access-to-protected-customer-data) for your app.
  </Requirement>
</Requirements>

<StepSection>
  <Step>
     ### Create a customer account UI extension
     <Substep>
      <CustomerAccountUiCreate />
    </Substep>
  </Step>

  <Step>
    ### Configure access scopes for your app
    <Substep>
      In your app’s `shopify.app.toml` file, include the required [access scopes](/docs/apps/build/cli-for-apps/app-configuration#access_scopes). The example code needs the `write_customers` access scope to create a metafield definition on the `CUSTOMER` resource with the GraphQL Admin API.

      To read or write metafields on the `CUSTOMER` resource using the Customer Account API, the `customer_read_customers` and `customer_write_customers` scopes will be required.

      <CodeRef
        extension="javascript"
        tag="config.setup-scopes"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/shopify.app.toml" />

      <CodeRef
        extension="react"
        tag="config.setup-scopes"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/shopify.app.toml" />
    </Substep>

    <Substep>
      After updating the `shopify.app.toml` file, deploy the scope changes to your app:

      <Codeblock>
        ```bash
        shopify app deploy
        ```
      </Codeblock>
    </Substep>
  </Step>

  <Step>
    ### Create the metafield definition

    Use the GraphQL Admin API to create a metafield definition with write permissions for the Customer Account API.

    <Notice type="info">
      The GraphQL Admin API access scope corresponding to the object the metafield is defined on is required to create the metafield definition.
      In our example, the `write_customer` scope is required to define a metafield on the `Customer` object. The `write_orders` scope is required to define a metafield on the `Order` object.
    </Notice>

    <Substep>
      To create a new metafield definition on app installation, use the `afterAuth` hook that the Remix template provides.

      <CodeRef
        extension="react"
        tag="create-metafield-definition.after-auth"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/app/shopify.server.ts" />

      <CodeRef
        extension="javascript"
        tag="create-metafield-definition.after-auth"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/app/shopify.server.ts" />

    </Substep>

    <Substep>
      Begin by checking if a metafield definition exists on the object with a matching key and namespace.

      <CodeRef
        extension="react"
        tag="create-metafield-definition.get-metafield"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/app/shopify.server.ts" />

      <CodeRef
        extension="javascript"
        tag="create-metafield-definition.get-metafield"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/app/shopify.server.ts" />

      <Notice type="info">
        The `AdminApiContext` and `ShopifyRestResources` used in the `getMetafield` function need to be imported.
      </Notice>

    </Substep>

    <Substep>
      If there's no existing metafield definition, use the GraphQL Admin API's [`metafieldDefinitionCreate`](/docs/api/admin-graphql/latest/mutations/metafieldDefinitionCreate) mutation to create it.

      <CodeRef
        extension="react"
        tag="create-metafield-definition.create-metafield"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/app/shopify.server.ts" />

      <CodeRef
        extension="javascript"
        tag="create-metafield-definition.create-metafield"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/app/shopify.server.ts" />

    </Substep>
  </Step>

  <Step>
    ### Set up the targets for your extension

    Set up the targets for your customer account UI extension. [Targets](/docs/api/customer-account-ui-extensions/latest/targets) control where your extension renders in the customer account flow.

    You'll use a [block extension target](/docs/api/customer-account-ui-extensions/latest/extension-targets-overview#block-extension-targets) to render a card on the **Profile** page and to render a modal when the button is clicked.
    <Substep>

    <CodeRef
      extension="react"
      tag="setup-targets.config"
      href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/extensions/customer-preferences/shopify.extension.toml" />

    <CodeRef
      extension="javascript"
      tag="setup-targets.config"
      href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/extensions/customer-preferences/shopify.extension.toml" />

      #### Reference the targets in your configuration file

      This example code uses the [`customer-account.profile.block.render`](/docs/api/customer-account-ui-extensions/latest/targets/profile-(default)/customer-account-profile-block-render) target

      In your extension's [`shopify.extension.toml`](/docs/apps/build/app-extensions/configure-app-extensions) configuration file, create an `[[extensions.targeting]]` section with the **`target`**, an identifier that specifies where you're injecting code into Shopify, and **`module`**, the path to the file that contains the extension code.

      ---

      <Notice type="info">
        Whenever you edit your extension configuration file, you need to restart your server for the changes to take effect.
      </Notice>
    </Substep>

    <Substep>
      #### Create files for your targets

    <CodeRef
      extension="react"
      tag="setup-targets.extension"
      href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/extensions/customer-preferences/src/ProfilePreferenceExtension.tsx" />

    <CodeRef
      extension="javascript"
      tag="setup-targets.extension"
      href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/extensions/customer-preferences/src/ProfilePreferenceExtension.js" />

      Create files in your extension's `src` directory for each of your targets.

      In this example, you'll create a file for the **Profile** page extension. The filenames must match the `module` [paths you specified](#reference-the-targets-in-your-configuration-file).

    </Substep>
  </Step>

  <Step>
     ### Build the **Profile** page extension

     Use [checkout](https://shopify.dev/docs/api/checkout-ui-extensions/latest/components) and [customer account](/docs/api/customer-account-ui-extensions/latest/components) extension UI components to build the UI of your extension.

    <Substep>
      In this example, a new [`Card`](/docs/api/customer-account-ui-extensions/latest/components/card) component is added to the **Profile** page.
      The card displays the current nickname. A [`Button`](/docs/api/checkout-ui-extensions/latest/components/actions/button) component is rendered that opens a [`Modal`](/docs/api/checkout-ui-extensions/latest/components/overlays/modal) component where a customer can update their nickname. The modal contains a [`TextField`](/docs/api/checkout-ui-extensions/latest/components/forms/textfield) component where the user can input their new nickname.

      <CodeRef
        extension="react"
        tag="build-extension.ui"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/extensions/customer-preferences/src/ProfilePreferenceExtension.tsx" />
      <CodeRef
        extension="javascript"
        tag="build-extension.ui"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/extensions/customer-preferences/src/ProfilePreferenceExtension.js" />
    </Substep>

    <Substep>
      Fetch the customer's nickname metafield value by querying the Customer Account API. Display the returned nickname value in the card.

      <CodeRef
        extension="react"
        tag="build-extension.get-value"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/extensions/customer-preferences/src/ProfilePreferenceExtension.tsx" />
      <CodeRef
        extension="javascript"
        tag="build-extension.get-value"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/extensions/customer-preferences/src/ProfilePreferenceExtension.js" />
    </Substep>

    <Substep>
      [Localization](/docs/apps/build/customer-accounts/localization) can be used to translate the UI of your extension into multiple languages.
      In this example, English is the default locale by including `en.default.json` in the `locales`.

      <CodeRef
        extension="react"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/extensions/customer-preferences/locales/en.default.json" />
      <CodeRef
        extension="javascript"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/extensions/customer-preferences/locales/en.default.json" />
    </Substep>

    <Substep>
      In our example, French is also supported by providing an `fr.json` file in the `locales` directory.

      <CodeRef
        extension="react"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/extensions/customer-preferences/locales/fr.json" />
      <CodeRef
        extension="javascript"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/extensions/customer-preferences/locales/fr.json" />
    </Substep>
  </Step>

  <Step>
    ### Write the user input to your metafield

    Make a request to the [`metafieldsSet`](/docs/api/customer/latest/mutations/metafieldsSet) mutation to write the user input to the metafield.

    <Substep>
      Pass the [previously defined](#create-the-metafield-definition) `key` and `namespace` to the `metafieldsSet` mutation to identify the metafield you want to update.
      The `ownerId` is the ID of the object whose metafield you want to update. In this example, it is the ID of the current customer.
      In this case, the `value` is the new nickname that the customer has inputted.

      <CodeRef
        extension="react"
        tag="write-metafield.mutation"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/react/example-customer-account--metafields--react/extensions/customer-preferences/src/ProfilePreferenceExtension.tsx" />
    <CodeRef
        extension="javascript"
        tag="write-metafield.mutation"
        href="https://github.com/Shopify/customer-account-tutorials/blob/main/javascript/example-customer-account--metafields--js/extensions/customer-preferences/src/ProfilePreferenceExtension.js" />
    </Substep>
  </Step>

  <Step>
     ### Preview the extension

    Use the Shopify CLI to preview your extension to make sure that it works as expected.

     <Substep>
      1. In a terminal, navigate to your app directory.

      2. Either start or restart your server to build and preview your app
          <Codeblock>
            ```bash
            shopify app dev
            ```
          </Codeblock>

      3. If prompted, select a development store.

      4. Once started, press `p` or navigate to the preview or follow the preview link in the developer console.

      5. Click on the **Install your app** link to install the app on your development store.

      6. In the developer console page, click the preview link for your extension target.

      7. You will be prompted to log in to customer accounts. Once logged in, you will see your extension on the **Profile** page.

      8. Click the edit icon in the `Preferences` card to open the modal and update the nickname metafield value.

      <Notice type="info">
        You can use a different [placement reference](/docs/apps/build/customer-accounts/test#block-targets) to preview the block target in different locations on the **Profile** page.
      </Notice>

      <Troubleshooting>
          ##### Extension not rendering

          Ensure that your app is installed on the development store you're testing with.

          Check your browser's developer console for any errors that might be preventing the extension from rendering.

          ##### Metafield not updating

          If the metafield value isn't being properly persisted, for example if the value that you specified isn't being saved after a page reload, do the following:

          - Ensure that the `namespace` and `key` used to [create the metafield definition](#create-the-metafield-definition) match the values being used in the `metafieldsSet` [mutation](#write-the-user-input-to-your-metafield).
          - Check your network traffic for the response to the `metafieldsSet` mutation. The response will contain a `userErrors` field that will provide more information about what went wrong.
          - If you changed access scopes in your `shopify.app.toml` file after installing the app, then deploy the new scopes by calling `shopify app deploy` and follow the app installation link again.
          - If the metafield definition wasn't created properly, then you can force the re-creation by uninstalling the app, deleting the `/prisma/dev.sqlite` file, and reinstalling the app.

        </Troubleshooting>
    </Substep>
  </Step>
</StepSection>

<NextSteps>

  ## Tutorial complete!

    Nice work - what you just built could be used by Shopify merchants around the world! Keep the momentum going with these related tutorials and resources.

  ### Next Steps

  <CardGrid>
    <LinkCard href="/docs/api/customer/latest/mutations/metafieldsSet">
      #### Working with metafields
      Explore methods for adding and storing custom data about a Shopify resource with metafields.
    </LinkCard>

    <LinkCard href="/docs/apps/customer-accounts/best-practices/deciding-extension-placement">
      #### Extension placement
      Explore extension placement options and make informed decisions on where to position them.
    </LinkCard>

    <LinkCard href="/docs/apps/customer-accounts/best-practices/localizing-ui-extensions">
      #### Localize your extension
      Learn about localizing your customer account UI extensions for international merchants and customers.
    </LinkCard>

    <LinkCard href="/docs/api/customer-account-ui-extensions/targets">
      #### Extension targets
      Learn about the extension targets offered in customer account.
    </LinkCard>

    <LinkCard href="/docs/api/customer-account-ui-extensions/components">
      #### Customer account components
      Learn about the components you can use to build customer account UI extensions.
    </LinkCard>

     <LinkCard href="/docs/api/checkout-ui-extensions/unstable/components">
       #### Checkout components
       Learn about the checkout components you can use to build customer account UI extensions.
    </LinkCard>

     <LinkCard href="/docs/apps/customer-accounts/best-practices/ux-guidelines">
      #### UX guidelines
      Follow our UX guidelines for customer accounts to ensure a consistent and satisfying user experience.
    </LinkCard>

    <LinkCard href="https://www.figma.com/community/file/1304881365343613949/checkout-and-account-components">
      #### Figma UI kit
      Explore Figma components for checkout and account UI extensions.
    </LinkCard>
  </CardGrid>
</NextSteps>