# Customer accounts

> Let customers log in on your site with Shopify's customer accounts. Covers the Shopify set-up, the key Smootify needs, login and logout, the customer's details, the customer conditions and the pages only logged-in customers can open.

Status: Ready (Smootify 2.0)  
URL: https://www.smootify.io/docs/astro/build/account  
Updated: 2026-10-21

Customers log in on your site with Shopify’s customer accounts. There is no password: Shopify sends a one-time code by email. This page sets up the Shopify side and the key Smootify needs, then covers login and logout, the customer’s details, the elements shown only to some customers, and the pages only logged-in customers can open.

> [!NOTE]
> Smootify 2.0 works with Shopify's **new customer accounts**. Shopify has deprecated its classic customer accounts and will remove them soon. You also need a Headless storefront in Shopify: see [Set up the Shopify store](https://www.smootify.io/docs/astro/start/shopify-store).

## How it fits together

What Smootify needs:

- new customer accounts turned on in Shopify;
- the client id of your Headless storefront’s Customer Account API, in the option `newCustomerAccountsPublicKey`;
- a `passwordless-login` form, where customers log in.

What is up to you:

- where the login goes: the navbar, a page of its own, or both;
- which account pages you build, and their layout. Every part of them is optional.

The parts an account can have, each with its own guide:

| Part | What it shows | Elements |
|---|---|---|
| [Addresses](https://www.smootify.io/docs/build/addresses) | saved addresses, with forms to add, edit and delete them | `customer-addresses`, `create-address`, `edit-address`, `delete-address` |
| [Orders](https://www.smootify.io/docs/build/orders) | past orders, a page for each order, and Buy again | `customer-orders`, `order-page`, `line-item`, `order-fulfillment` |
| [Subscriptions](https://www.smootify.io/docs/build/account-subscriptions) | subscriptions, a page for each one, and forms to pause, resume and cancel them | `customer-subscriptions`, `subscription-page`, `subscription-pause`, `subscription-activate`, `subscription-cancel` |
| [Customer data](https://www.smootify.io/docs/build/customer-data) | the name, customer metafields, the email subscription and store credit | `customer-user-update`, `customer-metafields-editor`, `customer-subscribe-email`, `customer-unsubscribe-email`, `store-credit` |

You do not have to build account pages at all. Shopify has its own account pages, and you can link to them from any link. Shopify gives their address under **Settings › Customer accounts**.

## 1. Turn on customer accounts in Shopify

1. In Shopify, go to **Settings › Customer accounts** and choose the new customer accounts.
2. Open the **Headless** channel and your storefront, then its **Customer Account API** settings.
3. Set the **Client type** to **Public**.
4. Turn on all its permissions.
5. Under **JavaScript origins**, add the address of your site without a slash at the end, such as `https://www.example.com`. Add `http://localhost:4321` and your `*.workers.dev` address too, so you can log in while you build and preview.
6. Under **Callback URIs**, add the address Shopify sends customers back to after the login. By default it is your home page, written the same way: `https://www.example.com`, `http://localhost:4321` and your `*.workers.dev` address.
7. Copy the **Client ID**. This is the public key Smootify needs.

Shopify’s login page shows your store’s logo and colours. You set them in Shopify’s checkout settings.

## 2. Give Smootify the key

Put the Client ID in the `userOptions` of the Smootify integration, in `astro.config.mjs`. Smootify writes them to every page before the loader: see [Install Smootify 2.0](https://www.smootify.io/docs/astro/start/install).

```js
smootify({
  siteId,
  userOptions: {
    newCustomerAccountsPublicKey: "{Customer Account API client id}",
  },
});
```

Without the key, the login does nothing and the account elements remove themselves from the page.

**Where the login lands.** After the login, Shopify sends the customer back to your home page. To send them somewhere else, set `newCustomerLoginRedirect` to that address, and add the same address to the **Callback URIs** in Shopify. With `newCustomerLoginRedirect: "same-page"`, customers go back to the page where they started the login. The callback is then your home page address.

## 3. Log in and log out

**Log in.** Add a `passwordless-login` element, and put a `<form>` inside it. The form needs only a submit button, such as “Log in”. A click takes the customer to Shopify’s login page, where they type their email and the code Shopify sends them. Then Shopify sends them back to your site, logged in.

There is no separate sign-up. A customer who has no account yet creates one in the same step, so “Log in” and “Create account” can be the same form.

**Log out.** Add a `logout-form` element, with a `<form>` and a submit button inside it. It ends the session on your site and in Shopify. The browser also forgets the cart, so the next visitor on that device starts with an empty cart.

**How long the login lasts.** The customer stays logged in until they log out or Shopify ends the session, such as when it expires. If Shopify cannot be reached for a moment, the page shows the visitor as not logged in, and the next page tries again with the same session: there is no new login to do.

**Show one or the other.** Wrap the login in an element with `customer-condition="not-logged-in"`, and the logout and account links in one with `customer-condition="logged-in"`:

```html
<div>
  <div customer-condition="not-logged-in">
    <passwordless-login>
      <form><button type="submit"><span data-state="default">Log in</span><span data-state="loading">Please wait…</span></button></form>
      <div form-done hidden>Redirecting…</div>
      <div form-fail hidden>Something went wrong</div>
    </passwordless-login>
  </div>
  <div customer-condition="logged-in">
    <div>Hi, <span customer="first-name">there</span></div>
    <logout-form>
      <form><button type="submit">Log out</button></form>
      <div form-done hidden>Logged out</div>
      <div form-fail hidden>Something went wrong</div>
    </logout-form>
  </div>
</div>
```

In a navbar, the same parts work as in [Navbar: cart, search and account](https://www.smootify.io/docs/astro/build/navbar).

## 4. Show the customer’s details

Add an attribute to a text element or a heading to fill it with a detail of the logged-in customer. These work anywhere on any page, with no wrapper.

| Attribute | What it shows |
|---|---|
| `customer="first-name"`, `customer="last-name"` | the first name, the last name |
| `customer="display-name"` | the name Shopify shows for the customer |
| `customer="email"` | the email; on a link, the link opens an email to it |
| `customer="phone"` | the phone number; on a link, the link calls it |
| `customer="defaultAddress"` | the default address, one line under the other |
| `customer="tags"` | one copy of the element per customer tag |
| `company="name"` | the company of a B2B customer |

- **Tags.** `exclude="Wholesale, Staff"` on the `customer="tags"` element leaves those tags out.
- **Company.** Every `company` element is taken out when the customer has no company.
- **Logged out.** For a visitor who is not logged in, these elements are taken out of the page. They come back after the login.
- **While it loads.** Until Smootify knows who the visitor is, these elements show as a placeholder shimmer.
- **A value that is missing.** `data-fallback="there"` on the element keeps it and shows that text when the customer has no value, such as a customer without a first name: `Hi, <span customer="first-name" data-fallback="there">name</span>`. It works on every element Smootify fills, product and metafield values included. To show or hide a whole block instead, use `customer-condition="has-names"` / `"no-names"`.

The full list is in [customer values](https://www.smootify.io/docs/astro/reference/attributes/customer). To show the customer’s metafields, see [Customer data and newsletter](https://www.smootify.io/docs/astro/build/customer-data).

```html
<div>
  <h2>Hello, <span customer="first-name">name</span></h2>
  <div customer="email">email@example.com</div>
  <div customer="defaultAddress">Default address</div>
</div>
```

## 5. Show or hide by customer

An element with `customer-condition="…"` shows only while the customer is in that state. The conditions come in pairs, one for each state:

| Condition | Shown when the customer |
|---|---|
| `logged-in` / `not-logged-in` | is logged in / is not logged in |
| `has-names` / `no-names` | has both a first and a last name / lacks one of them |
| `has-addresses` / `no-addresses` | has saved addresses / has none |
| `has-orders` / `no-orders` | has orders / has none (only on a page with a `customer-orders` list, which counts the orders) |
| `has-subscriptions` / `no-subscriptions` | has subscriptions / has none (only on a page with a `customer-subscriptions` list) |
| `email-subscribed` / `email-not-subscribed` | is subscribed to your email marketing / is not |

**Logged-out visitors.** The conditions after the first pair are for logged-in customers. Use them on account pages, or inside an element with `customer-condition="logged-in"`.

**Customer tags.** `customer-tagged="vip"` shows an element only to customers with that tag. With several tags, `customer-tagged="vip, gold"`, the customer needs all of them. Add `any="true"` to show it when the customer has at least one, or `exclusive="true"` to show it only when the customer has exactly those tags and no other. `customer-not-tagged="…"` does the opposite, and reads `any="true"` too. For a visitor who is not logged in, both are taken out of the page.

Every condition is in [customer conditions](https://www.smootify.io/docs/astro/reference/conditions/customer) and [customer tag conditions](https://www.smootify.io/docs/astro/reference/conditions/customer-tags).

> [!WARNING]
> These conditions hide elements on the page, but what they hide is still in the published page's code. Never use them to hide private information.

## 6. Pages for logged-in customers

Pages inside the `src/pages/account/` folder, such as `/account/orders`, are for logged-in customers only. A visitor who is not logged in is sent to your home page. Only the `/account` page itself and the pages inside it count: `/accounts` or `/accounting/rates` stay open to everyone.

- **Other languages.** With `locales`, the same pages in each language are covered, such as `/fr/account/orders`.
- **Pages that stay open.** A page in the folder whose address contains `login`, `register`, `reset`, `activate` or `recover` is open to everyone.
- **Where visitors go.** `accountPageRedirectTo` sends them to another address, such as `"/login"`. With `accountPageRedirectTo: "passwordless-login"`, they go straight to Shopify’s login page. That needs `newCustomerAccountsPublicKey`: without it no login can open, so they go to the home page, and in the dev server and on your `*.workers.dev` address the debugger points out the missing key.
- **Another folder.** If your account pages are in another folder, such as `src/pages/my-account/`, set it in `accountBase`, such as `accountBase: "my-account"`.

These options go in the same `userOptions` as the key:

```js
smootify({
  siteId,
  userOptions: {
    newCustomerAccountsPublicKey: "{Customer Account API client id}",
    accountPageRedirectTo: "passwordless-login",
  },
});
```

Two pages have a fixed address by default: the order page at `/account/order` and the subscription page at `/account/subscription`. See [Orders and buy again](https://www.smootify.io/docs/astro/build/orders) and [Subscriptions in the account](https://www.smootify.io/docs/astro/build/account-subscriptions). Every option is in the [options reference](https://www.smootify.io/docs/astro/reference/options).

## Common questions

- **Can I import customers from another platform?** Yes, their emails, with Shopify’s customer import. Passwords cannot be imported, and none are needed: customers log in with a one-time code sent to their email.
- **Can I change Shopify’s own account pages?** Shopify’s login page and its account pages (orders, profile) take your logo and colours, a menu and app blocks, set in Shopify’s checkout and accounts editor (**Settings › Checkout**, then **Customize**). Nothing else of their design changes.
- **Do I have to use Shopify’s account pages?** No. You can build every account page in your site, as on this page. Apps that add blocks to customer accounts, such as loyalty apps, work only in Shopify’s account pages: link to them from your pages when you need one. Return requests are built in: see [Returns and removals](https://www.smootify.io/docs/astro/build/orders#5-returns-and-removals).

## Before you publish

Log in in the dev server or on your `*.workers.dev` address to see the account pages with real data. Press Alt+Shift+D (Option+Shift+D on a Mac) there to turn on Smootify’s debugger (on a phone, add `?smootify-debug` to the address): its panel lists the account elements that are not running, and why. See [The debugger](https://www.smootify.io/docs/astro/start/debugger).

> [!STUCK]
> - **Login fails, or Shopify does not send the customer back.** Most often the Callback URIs or the JavaScript origins in Shopify do not match the site's address. Add the address exactly, as `https://www.example.com`, to both.
> - **Log in does nothing.** `newCustomerAccountsPublicKey` is missing from the `userOptions` in `astro.config.mjs`.
> - **Login works on one address and not on the other.** Each address you use, the dev server, your `*.workers.dev` one and your own domain, must be in both the JavaScript origins and the Callback URIs in Shopify.
> - **A visitor who is not logged in sees an account page.** The page is outside the `account` folder, such as `/account-orders`: move it into the folder, `/account/orders`.
> - **Back from Shopify's login, the customer is still logged out.** A second login was started in another tab before the first one finished, and only the last login started counts. Log in again from one tab.
> - **An account page sends you to the home page.** You are not logged in, and the pages in the `account` folder are for logged-in customers. Log in first, or change `accountPageRedirectTo`.
> - **`has-orders` and `no-orders` both show.** The page has no `customer-orders` list, which is what counts the orders.
> - **The default address stays empty.** The value is `customer="defaultAddress"`, in one word. `default-address` is not read.
