How to access shop metafields in customer account UI extension?

When I query on full page extension, metafield value is NULL.
I confirmed it is not NULL via Postman.

const data = await query(
  `query {
    shop {
      id
      metafield(namespace: "my_namespace", key: "my_key") {
        value
      }
    }
  }`
);

I already added this in extension TOML file.

[[extensions.metafields]]
namespace = "my_namespace"
key = "my_key"

So you can access the metafield in Postman, but not in your customer account extension? Are you using the same API credentials in both, or have you made sure the metafield is accessible to all apps, if it’s a different app credential?

So you can access the metafield in Postman, but not in your customer account extension?

Correct.

Are you using the same API credentials in both?

I am calling GraphQL query directly in customer account UI extension.

have you made sure the metafield is accessible to all apps,

I saw others had similar issue which was metafield permission issue. But this is shop metafields and I am not sure how I can update permission of it :thinking:

If you check the access of the metafield like this, what do you see:

query GetMetafieldDefinitionAccess {
  metafieldDefinition(id: "gid://shopify/MetafieldDefinition/123456789") {
    id
    name
    access {
      admin
      customerAccount
      storefront
    }
  }
}

I see its metafield definition is NULL :thinking:

How did you create this metafield?

I created the metafield using metafieldSet mutation in the after_authenticate_job in my app.

This is GraphQL mutation I am using:

mutation MetafieldsSet($metafields: [MetafieldsSetInput!]!) {
  metafieldsSet(metafields: $metafields) {
    metafields {
      id
      key
      namespace
      value
    }
    userErrors {
      field
      message
      code
    }
  }
}

Please let me know if you need anything else.
Thank you!

This is a bit strange - it looks like your app doesn’t have permissions to access the metafield, even though it created it?

It’s Shop metafield. I don’t see Shop in metafield definitions list.

Correct - Shop metafields are a bit different as they’re not created from the admin

Finally, I found the solution.

Step1: Create metafield definition.

GraphQL mutation:

mutation CreateMetafieldDefinition($definition: MetafieldDefinitionInput!) {
  metafieldDefinitionCreate(definition: $definition) {
    createdDefinition {
      id
      key
      name
      namespace
    }
    userErrors {
      field
      message
      code
    }
  }
}

Variables:

{
  "definition": {
    "name": "App Environment",
    "namespace": "$app:<my-app-name>",
    "key": "app_url",
    "description": "Metadata used to store the app environment",
    "access": {
      "admin": "MERCHANT_READ",
      "storefront": "PUBLIC_READ"
    },
    "type": "single_line_text_field",
    "ownerType": "SHOP"
  }
}

Step 2: Set metafields.

GraphQL mutation:

mutation MetafieldsSet($metafields: [MetafieldsSetInput!]!) {
  metafieldsSet(metafields: $metafields) {
    metafields {
      id
      key
      namespace
      value
      createdAt
      updatedAt
    }
    userErrors {
      field
      message
      code
    }
  }
}

Variables:

{
  "metafields": [
    {
      "key": "app_url",
      "namespace": "$app:<my-app-name>",
      "type": "single_line_text_field",
      "value": "<server-url>",
      "ownerId": "gid://shopify/Shop/<shop-id>"
    }
  ]
}

Step 3: Get shop metafields using storefront API on customer account UI extension.

const response = await fetch(
  `shopify://storefront/api/2025-01/graphql.json`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: `
        query {
          shop {
            metafields(identifiers: [
              { namespace: "$app:<my-app-name>", key: "app_url" }
            ]) {
              namespace
              key
              value
            }
          }
        }
      `,
    }),
  }
);

const { data } = await response.json();
const value = data.shop.metafields?.[0]?.value;