Appearance
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
| Surface | Where it lives | Owned by |
|---|---|---|
save_profile metaobject | Shopify metaobjects (canonical) | SaveLayer |
customer.metafields.savelayer.profiles | Customer record (list.metaobject_reference) | SaveLayer maintains it |
save_list.profile reference | save_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 forpet,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 filter saves to a specific profile, store the profile reference on save_list.profile when the list is created and filter your save list query by that field.