Skip to content

Entity Profiles ​

Entity profiles let a customer save who or what they shop for — pets, babies, vehicles, plants, family members — directly on their customer account. Each profile is stored as a Shopify metaobject (save_profile) and indexed on a customer metafield (savelayer.profiles), so themes, Liquid, Functions, Flow, and dynamic-source pickers in the theme editor can all read it.

Plan requirement: Same as the rest of the customer-account channel — requires the Pro plan or above. See Customer Account.

Why this exists ​

Pet stores, baby stores, parts stores, supplement brands — any merchant whose customers shop for a specific entity benefits from persisting "who this is for." Once the profile lives on the customer record, the merchant can:

  • Render personalized lists (Saves for Rex, Saves for the truck).
  • Filter recommendations or recharge subscriptions per profile.
  • Drive Shopify Flow workflows (e.g. "remind customer when Rex's food was last ordered").
  • Use dynamic-source bindings in the theme editor without writing custom Liquid.

Data model ​

SurfaceWhere it livesOwned by
save_profile metaobjectShopify metaobjects (canonical)SaveLayer
customer.metafields.savelayer.profilesCustomer record (list.metaobject_reference)SaveLayer maintains it
save_list.profile referencesave_list metaobject (optional)Merchant or app — links a list to a profile

Each save_profile carries:

  • customer_id (required, used for ownership checks)
  • profile_name (display name — "Rex")
  • profile_type (free-form; SaveLayer ships defaults for pet, baby, vehicle, person, plant, custom)
  • attributes (JSON bag — { breed: "labrador", age: 5 })
  • created_at, updated_at, state

Customer-side identity is always resolved server-side from the SaveLayer JWT, never from a payload field. SaveLayer enforces ownership on every read or write before touching the metaobject.

API ​

All endpoints share the customer-account auth model — call /api/customer-account/auth/exchange first to mint a SaveLayer JWT, then send Authorization: Bearer <jwt> on subsequent calls. See Customer Account for the exchange flow.

GET /api/customer-account/profile/list ​

Returns the active profiles owned by the authenticated customer.

json
{
  "ok": true,
  "data": {
    "profiles": [
      {
        "id": "gid://shopify/Metaobject/123",
        "name": "Rex",
        "type": "pet",
        "attributes": { "breed": "labrador", "age": 5 },
        "createdAt": "2026-04-25T00:00:00.000Z",
        "updatedAt": "2026-04-25T00:00:00.000Z"
      }
    ]
  }
}

POST /api/customer-account/profile/create ​

json
{ "name": "Rex", "type": "pet", "attributes": { "breed": "labrador" } }

Returns { ok: true, data: { profile: { ... } } } and rebuilds customer.metafields.savelayer.profiles.

POST /api/customer-account/profile/update ​

json
{ "id": "gid://shopify/Metaobject/123", "name": "Rexford" }

Only the fields you send are changed. attributes is replaced wholesale when present.

POST /api/customer-account/profile/delete ​

json
{ "id": "gid://shopify/Metaobject/123" }

Soft-flips state=deleted, then issues a hard metaobjectDelete. The customer metafield is rebuilt to drop the reference. If the hard delete fails, the soft state still removes it from filtered queries and the metafield index.

Customer Account UI extension ​

SaveLayer ships a built-in customer-account UI extension at extensions/savelayer-customer-account-profiles/ that gives customers a CRUD surface for their profiles using the standard customer-account web components (Page, BlockStack, TextField, Select, Button, etc.). It targets the same customer-account.page.render extension target as the Saved Items extension.

Merchants can override the offered profile types via the extension's profile_types setting (comma-separated) — leave blank for the SaveLayer defaults.

Reading profiles in your theme ​

Because profiles are referenced from a customer metafield, they show up in the theme editor's dynamic-source picker. To read them in Liquid:

liquid
{% for profile in customer.metafields.savelayer.profiles.value %}
  <h3>{{ profile.profile_name }}</h3>
  <p>{{ profile.profile_type }}</p>
{% endfor %}

To associate saves with a specific profile, store the profile reference on the save_list.profile field and filter your save list query by that field.