Checkout UI Extension

Hi, hope you all are doing well. I am creating a checkout UI extension in which I am facing an issue with missing data like variables:

shopify.billingAddress: undefined, shopify.buyerIdentity: undefined, shopify.shippingAddress: undefined.

I am logged in with Gmail, but the buyerIdentity is still undefined. I also added the shipping address, but it is still undefined.

Can anyone please help me resolve this issue?

Thanks in advance.

How and where are you trying to read these variables? You shouldn’t be reading them directly. I believe that shopify prefers you to use either “React-style Hooks API (@shopify/checkout-ui-extensions-react)” or “Web components + shopify APIs (@shopify/checkout-ui-extensions)” Even if you are using the right read method, the when is also important as you need to read it after it has been entered by the customer. Being logged in with Gmail doesn’t guarantee that the information that you want exists in the required field yet. If you try and read the shipping address before the customer has entered one, or used a saved address, then the field will be empty at that point. If you use Shop pay, or another accelerated checkout method, they can skip or pre-fill some of these in ways that will come up as undefined. Maybe try looking for shopify.checkout.billingAddress instead ofshopify.billingAddress. It may exist there, even if it’s not defined at the top level.

Thanks for your response.

I am creating a checkout UI extension using preact (@shopify/ui-extensions/preact). In my code, shopify.shippingAddress exists, but its value is still undefined (please check the image below).

Also, the code is used is below. And I am not using Shop App.

Regarding your question: I am trying to read these variables directly.

// @ts-nocheck
import '@shopify/ui-extensions/preact';
import { render } from "preact";

export default async () => {
  render(<Extension />, document.body)
};

function Extension() {
  console.log(" === shopify === ", shopify)
  if (!shopify.instructions.value.metafields.canSetCartMetafields) {
    return (
      <s-banner heading="checkout-ui-block" tone="warning">
        {shopify.i18n.translate("metafieldChangesAreNotSupported")}
      </s-banner>
    );
  }

  const getStateCode = () => {
    return shopify.shippingAddress?.value?.provinceCode ?? null;
  };

  return (
    <>
      <s-paragraph>
        <s-text type="strong">Name: </s-text>
        <s-text>Jane Doe</s-text>
      </s-paragraph>
    </>
  );
}

Sorry for taking so long to get back to you. What you are seeing is actually completely normal behaviour for the new Checkout UI global API. Here’s the deal: shopify.shippingAddress is essentially a reactive container (similar to how state works in React or @preact/signals). Because of that, the object itself will always exist, but its actual .value is usually going to be undefined when the extension first loads. There are a few reasons why this happens. 1. Timing: You’re doing a console.log right when the component mounts. At that exact split second, the buyer usually hasn’t entered their address yet, so it’s naturally undefined. 2. Extension Target: If you’re putting this extension on an early checkout step (like contact info) instead of a shipping-specific step, the address hasn’t been collected yet. 3. Cart Contents: If you happen to be testing with a digital product, the checkout won’t collect a shipping address at all. How to fix it: Since shippingAddress updates dynamically as the user types or moves through the checkout, you can’t just read it once on load. You need to subscribe to its changes.

Since you’re using Preact, here’s a very common, clean pattern. You can use Preact signals combined with Shopify’s .subscribe() method to safely grab that province code and keep it updated in real-time:

import ‘@shopify/ui-extensions/preact’;
import { render } from “preact”;
import { signal } from ‘@preact/signals’;

export default () => {
render(, document.body);
};

function Extension() {
// Set the initial state (it will likely be null at first!)
const stateCode = signal(shopify.shippingAddress?.value?.provinceCode ?? null);

// Subscribe to changes so the UI updates automatically as the buyer types their address
shopify.shippingAddress?.subscribe((nextAddress) => {
stateCode.value = nextAddress?.provinceCode ?? null;
});

if (!shopify.instructions.value.metafields.canSetCartMetafields) {
return (

{shopify.i18n.translate(“metafieldChangesAreNotSupported”)}

);
}

return (

Province Code:
{/* This will update from ‘Not entered yet’ to the actual code as they type */}
{stateCode.value ?? ‘Not entered yet’}

);
}

A couple of other things to check. 1 Your .toml file. Make sure that your target in shopify.extension.toml is set to something delivery-related, like purchase.checkout.delivery-address.render-before. If you use a generic block on the very first page of checkout, the shipping info might just not exist yet. 2 Don’t trust console.log for this. Because the shopify object is reactive, your initial console.log will just print the empty starting state. It won’t magically update in your dev tools when the user types. Rendering the value directly to the screen (like in the code above) is the best way to actually see it working. Documen ts for you to refer to:

Global shopify + delivery APIs examples:
Convert additional address fields

  1. Delivery API & examples (using shopify.deliveryGroups, etc.):
    Delivery API (Checkout UI extensions)
  2. Shipping-related targets where shipping data is available:
    purchase.checkout.delivery-address.render-before
    All checkout extension targets

Hi, sorry for the late reply and I really appreciate you taking the time to write such a detailed response. Just wanted to close the loop and let you know that the issue is now resolved.

Thanks!