Skip to main content
Customer Portal v2 templates can use Shopify data in two ways:
  • Use Shopify’s Storefront API from custom template JavaScript to fetch storefront product and collection data.
  • Read and update selected Shopify customer metafields through the Firmhouse Shopify API proxy.
Use these features when a portal page needs a richer storefront experience, personalized account fields, loyalty data, preferences, or other Shopify customer data that is not part of the standard Firmhouse subscription data.

Before you start

These features are available when the Shopify subscriptions app is configured for the Firmhouse project. You also need access to Customer Portal in the Firmhouse sidebar so you can manage Customer Portal v2 settings and edit templates.

Use the Shopify Storefront API

Customer Portal v2 includes Liquid tags that output the Shopify store domain and the Storefront API public access token for the project. Use these tags in a template when you want to make client-side requests to Shopify’s Storefront GraphQL API:
<script>
  const shopifyDomain = "{% shopify_store_domain %}";
  const storefrontToken = "{% shopify_storefront_access_token %}";
  const storefrontEndpoint = `https://${shopifyDomain}/api/2026-01/graphql.json`;
</script>
You can then fetch products, collections, filters, or other Storefront API data from your custom template JavaScript.
<script>
  const shopifyDomain = "{% shopify_store_domain %}";
  const storefrontToken = "{% shopify_storefront_access_token %}";
  const storefrontEndpoint = `https://${shopifyDomain}/api/2026-01/graphql.json`;

  fetch(storefrontEndpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Shopify-Storefront-Access-Token": storefrontToken
    },
    body: JSON.stringify({
      query: `{
        products(first: 10) {
          nodes {
            id
            title
            handle
          }
        }
      }`
    })
  })
    .then((response) => response.json())
    .then((data) => console.log(data));
</script>
The Storefront API token is a public Shopify storefront token. Do not use it for Shopify Admin API operations or for secret server-side credentials.

Rotate the storefront token

Firmhouse caches the Storefront API token and exposes it to Customer Portal v2 templates with {% shopify_storefront_access_token %}. To rotate the token:
  1. Open Customer Portal in the Firmhouse sidebar.
  2. Stay on the Overview page.
  3. Find Shopify storefront token.
  4. Click Rotate token.
Rotating the token invalidates the previous token. Review custom template JavaScript if you have copied the token outside the Customer Portal template system.

Allow customer metafields

The Shopify API proxy only allows customer metafields that are explicitly listed in the Customer Portal settings. To allow metafields:
  1. Open Customer Portal in the Firmhouse sidebar.
  2. Stay on the Overview page.
  3. Find Shopify API proxy.
  4. Enter allowed keys as a space-separated list in namespace.key format.
  5. Save the settings.
For example:
custom.preferences custom.loyalty_tier
Only the listed keys can be read or updated from Customer Portal v2.

Read a customer metafield

Customer Portal v2 templates include a shopify_customer_metafields_url Liquid variable. Use it as the same-origin endpoint for reading and updating allowed Shopify customer metafields. This endpoint is scoped to the Shopify customer linked to the current subscription.
<script>
  const metafieldsUrl = "{{ shopify_customer_metafields_url }}";

  fetch(`${metafieldsUrl}?namespace=custom&key=loyalty_tier`)
    .then((response) => response.json())
    .then((metafield) => {
      console.log(metafield.value);
    });
</script>
When the metafield exists, the response includes:
{
  "namespace": "custom",
  "key": "loyalty_tier",
  "value": "gold",
  "type": "single_line_text_field"
}
When the metafield does not exist yet, the response returns the requested namespace and key with null values.

Update a customer metafield

Use a PATCH request to update an allowed customer metafield.
<script>
  const metafieldsUrl = "{{ shopify_customer_metafields_url }}";
  const csrfToken = document.querySelector("meta[name='csrf-token']").content;

  fetch(metafieldsUrl, {
    method: "PATCH",
    headers: {
      "Content-Type": "application/json",
      "X-CSRF-Token": csrfToken
    },
    body: JSON.stringify({
      namespace: "custom",
      key: "preferences",
      value: "weekly_updates",
      type: "single_line_text_field"
    })
  })
    .then((response) => response.json())
    .then((metafield) => {
      console.log(metafield.value);
    });
</script>
If you omit type, Firmhouse uses single_line_text_field.

Troubleshooting

The Storefront API token is empty Check that the Shopify subscriptions app is configured for the project. The metafield request returns forbidden Check that the metafield is listed under Customer Portal > Overview > Shopify API proxy. The allowed key must match the requested namespace.key exactly. The metafield request says no Shopify customer is linked The current Firmhouse subscription must be linked to a Shopify customer before Customer Portal v2 can read or update Shopify customer metafields. The update request fails Check that the request includes namespace, key, and value. For PATCH requests from custom JavaScript, also include the X-CSRF-Token header from the page’s CSRF meta tag.