--- 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>