# Skin and formula data

Chapter 7 of the Derma user guide.

Derma's signature features read structured data you keep in Shopify: two **metaobject definitions** (Ingredient and Clinical study) and a set of **product metafields** in the `derma` namespace. Nothing here is required. Every feature hides itself cleanly when its data is missing, and in the theme editor a dashed note says what it needs.

The tables below say which feature reads each field.

## Step 1: create the Ingredient definition

In Shopify admin go to **Settings › Custom data › Metaobjects › Add definition**. Name it **Ingredient**; its type must be exactly `ingredient`. Add these fields (the key is what the theme reads, so match it exactly):

| Field key | Type | Notes |
| --- | --- | --- |
| `name` | Single line text | Required. The name shown on cards, such as Niacinamide. Set it as the definition's display name. |
| `inci` | Single line text | The INCI name used to find this ingredient in a product's ingredient list, such as Niacinamide. Separate several names with `/` to match any of them (Ascorbic Acid / Sodium Ascorbyl Phosphate). |
| `also_known_as` | Single line text | Such as Vitamin B3 |
| `summary` | Multi-line text | "What it does", about 200 characters |
| `body` | Rich text | The long explainer on the ingredient's own page |
| `good_for` | Single line text, list of values | Concerns, such as Breakouts and Visible pores. They become the glossary's concern chips. |
| `typical_strength` | Single line text | Such as 2 to 10% |
| `category` | Single line text | Such as Active, Hydrator, Soother, Exfoliant, Antioxidant, Sunscreen filter, Emollient, Preservative, Other. Shown as a pill on the ingredient page. |
| `image` | File (images) | A texture or molecule picture, shown in a circle |
| `products` | Product, list of products | Optional. Products that feature it: gives the glossary card a count ("4 products") and fills the product grid on its page. |

Under **Access**, turn on **Storefronts**. Under **Features**, turn on **Web pages** and give it a URL handle, such as `ingredient`, so each entry gets its own page (`/pages/ingredient/niacinamide`) using Derma's `metaobject/ingredient` template. Then add entries in **Content › Metaobjects › Ingredient**.

## Step 2: create the Clinical study definition

Add a second definition named **Clinical study**, type exactly `clinical_study`, with Storefronts access on:

| Field key | Type | Notes |
| --- | --- | --- |
| `summary` | Single line text | Required for anything to show. The footnote that says who was studied and how: "Independent consumer study, 32 people aged 18 to 45, 4 weeks, self-assessed." |
| `results` | Multi-line text | One result per line, as figure, claim and qualifier separated by `\|`: `87% \| saw fewer breakouts \| after 4 weeks, twice daily`. Lines with fewer than two parts are skipped. |
| `before_image` | File (images) | |
| `after_image` | File (images) | |
| `before_label` | Single line text | Such as Week 0. "Before" when empty. |
| `after_label` | Single line text | Such as Week 8. "After" when empty. |
| `caption` | Single line text | Required for the before and after: "Same person, same lighting, no retouching. Individual results vary." |
| `document` | File | The study summary PDF, linked as "Read the study summary (PDF)" |

## Step 3: create the product metafields

Go to **Settings › Custom data › Products › Add definition**. For each one, set the namespace and key exactly as shown (type `derma.formula` in the "Namespace and key" field), choose the type, and turn on **Storefronts** access. For the fields marked "choices", use the **Limit to preset choices** validation so every product uses the same spelling; filters and the quiz match values exactly.

| Namespace and key | Type | Used by |
| --- | --- | --- |
| `derma.formula` | Single line text | Formula line on cards, titles, cart and routine: "Niacinamide 10% + zinc 1%" |
| `derma.benefit` | Single line text | Card benefit line: "For breakouts and visible pores" |
| `derma.benefit_long` | Multi-line text | Description block (Short) |
| `derma.size` | Single line text | Cards, compare: "30 ml". Falls back to the Size option. |
| `derma.tint` | Color | The tinted well behind the product's images |
| `derma.actives` | Metaobject (Ingredient), list | Formula block key active cards (up to 4), formula line, Key ingredient filter, compare |
| `derma.active_strengths` | Single line text, list | The strength of each active, in the same order as `derma.actives`: 10%, 1% |
| `derma.inci` | Multi-line text | The full ingredient list, comma-separated |
| `derma.free_from` | Single line text, list | "Free from" chips: Fragrance, Alcohol, Essential oils |
| `derma.formula_notes` | Single line text, list | Chips beside the strength card: pH 5.5 to 6.5, Vegan |
| `derma.strength` | Single line text, choices Gentle, Moderate, Strong | The strength meter, compare, Strength filter, quiz question 3 |
| `derma.strength_note` | Single line text | Under the meter: "Start once a day for the first week." |
| `derma.skin_types` | Single line text, list, choices Dry, Oily, Combination, Normal, Sensitive | Suits your skin, Skin type filter, quiz question 1 |
| `derma.concerns` | Single line text, list, choices such as Breakouts, Visible pores, Excess oil, Dark spots, Fine lines, Texture, Redness, Dryness, Dullness | Suits your skin, Concern filter |
| `derma.when` | Single line text, list, choices Morning, Night | How to use "When" chips, Routine |
| `derma.routine_step` | Single line text, choices Cleanse, Tone, Treat, Eye, Moisturise, Protect | How to use routine track; Routine "Build from the product". Moisturize is accepted too. |
| `derma.amount` | Single line text | How to use "Amount"; the supplement facts amount chip, as written ("2 capsules a day") |
| `derma.frequency` | Single line text | How to use "How often" |
| `derma.pairs_with` | Single line text | How to use "Pairs well with" |
| `derma.avoid_with` | Single line text | How to use "Don't layer with" |
| `derma.directions` | Rich text | How to use; the How to use accordion row |
| `derma.patch_test` | Multi-line text | How to use "Patch test first" callout; the Patch test accordion row. Falls back to the theme setting. |
| `derma.spf_reminder` | True or false | Adds the SPF reminder from theme settings to How to use |
| `derma.studies` | Metaobject (Clinical study), list | Clinical results block (up to 2 studies) |
| `derma.serving_size` | Single line text | Supplement facts: "2 capsules" |
| `derma.servings` | Integer | Supplement facts: servings per container |
| `derma.facts` | Multi-line text | Supplement facts rows (below) |
| `derma.other_ingredients` | Multi-line text | Supplement facts |
| `derma.allergens` | Single line text | Supplement facts |
| `derma.warnings` | Multi-line text | Supplement facts |
| `derma.refill` | Product | Buy buttons refill link, with the saving |
| `derma.suitable_for` | Single line text, list | Optional: the Daily preset's finder asks "How do you eat?" and filters on it (Vegan, Vegetarian) |

**Variant metafields** (Settings › Custom data › Variants):

| Namespace and key | Type | Used by |
| --- | --- | --- |
| `derma.note` | Single line text | A short note inside the variant's option pill: "Save 15%" |
| `derma.shade_note` | Single line text | Under the shade swatches: "light, warm undertone" |

**Blog post metafields**: `derma.reviewed_by` (single line text) and `derma.reviewed_on` (date) for the "Medically reviewed by" line (chapter 5).

**Writing the values**

* `derma.inci`: the full list in label order, separated by commas: `Aqua, Niacinamide, Glycerin, Zinc PCA, …`. Tokens that match a key active are highlighted; tokens that match an Ingredient entry link to it.
* `derma.facts`: one row per line as name, amount and daily value separated by `|`: `Vitamin D3 (as cholecalciferol) | 25 µg | 125%`. Leave the daily value empty to print "†". Start a line with `## ` for a sub-heading, or with `- ` to indent it under the row above.
* `derma.active_strengths`: keep the order of `derma.actives`. An active without a strength shows a drop icon in place of the figure.

> **Tip:** Fill a few products completely first, then use **Products › Bulk edit** (add the metafield columns) or a CSV import to fill the rest.

## Step 4: add the Search & Discovery filters

Install Shopify's free **Search & Discovery** app. In **Filters › Add filter**, add these product metafield filters (the app lists a metafield once its definition exists with Storefronts access):

| Filter label | Source | URL parameter |
| --- | --- | --- |
| Skin type | `derma.skin_types` | `filter.p.m.derma.skin_types=Oily` |
| Concern | `derma.concerns` | `filter.p.m.derma.concerns=Breakouts` |
| Key ingredient | `derma.actives` | `filter.p.m.derma.actives=gid://shopify/Metaobject/<id>` |
| Strength | `derma.strength` | `filter.p.m.derma.strength=Gentle` |

Collection and search pages then show them, and links can use them: the format is `filter.p.m.<namespace>.<key>=<value>`. Different filters combine with AND; repeating one filter's parameter combines its values with OR (`?filter.p.m.derma.strength=Gentle&filter.p.m.derma.strength=Moderate`). The skin quiz builds exactly these links.

While you're in the app, set up **Product recommendations › Complementary products** for your hero products. The Routine section's "Build from the product", the cart's "Complete your routine" and "Complementary products" recommendations use them.

## Step 5: set up the skin quiz page

1. **Online Store › Pages › Add page**. Title it, for example, "Skin quiz". In **Theme template**, choose `skin-quiz`. Save.
2. **Theme settings › Skin and formula › Skin quiz page**: choose it. Every "Take the skin quiz" and "Change" link now goes there; with no page chosen those links are hidden.
3. Open the page in the theme editor. The Skin finder section comes with five Skin type answers, six Concern answers and three Reaction answers. Each Concern answer points at a collection by handle (`breakouts`, `dark-spots`, `fine-lines`, `redness`, `dryness`, `dullness`). Create those collections, or choose your own for each answer. Until then, the template's "Fallback collection" (All products) stands in, so the quiz works on a new store: it shows your full range and says that nothing is matched to that concern yet.
4. Check that each Skin type answer's "Filter value" matches the value on your products exactly (Oily, not oily).

How it works: question 1 filters by skin type, question 2 picks the collection the results come from, and question 3 filters by strength. The results show up to "Products to show" matches and a "See all" link to the filtered collection. If nothing matches, the quiz drops question 3's filter, then question 1's, and says so ("Nothing in Breakouts is marked for your sensitivity yet, so we've left that answer out."). The answers also go in the page address (`#skin=oily,breakouts,often`), so a result can be shared. Without JavaScript, the concern answers work as plain links to their collections.

**Skin finder settings**

| Setting | Default | Notes |
| --- | --- | --- |
| Question 1: Step name, Question, Hint | Skin type; "What's your skin type?"; "Think about how your skin feels by midday." | |
| Question 1: Filter parameter | `filter.p.m.derma.skin_types` | `filter.p.m.namespace.key` for a product metafield, or `filter.p.tag` to match tags. Leave empty to ask without filtering. |
| Question 2: Step name, Question, Hint | Main concern; "What would you most like to change?"; "Pick the one that bothers you most. You can add more later." | |
| Fallback collection | | Used by Concern answers without a collection of their own. Leave empty to hide those answers. |
| Ask question 3 | On | If your heading says how many questions there are ("in three questions"), change it when you turn this off. |
| Question 3: Step name, Question, Hint | Sensitivity; "How does your skin react to new products?"; "Think about the last new product you tried." | |
| Question 3: Filter parameter | `filter.p.m.derma.strength` | |
| Results: Heading | "Matched to your skin" | |
| Products to show | 4 | 2 to 8 |
| Background | Surface | Page or Surface |

Answer blocks:

* **Skin type** (up to 6): "Label", "Filter value" (the value as it's entered on your products), "Description", "Image", "Icon" (Drop, Sun, Leaf, Sparkle or Shield, shown when there's no image).
* **Concern** (up to 9): "Label", "Collection" (shoppers who pick this answer see this collection, filtered by their other answers), "Description", "Image" (uses the collection's image when empty).
* **Reaction** (up to 4): "Label", "Description", "Filter values" (separated by commas; products with any of them match; leave empty to show every strength). The defaults are Rarely (empty: any strength), Sometimes (Gentle, Moderate) and Often (Gentle).

The quiz isn't only for skin. The Bloom preset asks about skin type and then what the shopper is shopping for (Skin tint, Concealer, Blush…); Daily asks "How do you eat?" (filtering on `derma.suitable_for`) and a health goal. You can use tags instead of metafields with `filter.p.tag`.

## The skin profile

With Theme settings › Skin and formula › "Remember skin profile" on, a finished quiz saves the answers on the shopper's device (browser storage, not their customer account) and says "Saved to your skin profile". Then:

* The header shows a chip with the profile, such as "oily, breakouts" (Header › "Show skin profile"); on phones it's a bar under the header.
* **Suits your skin** on the product page highlights the skin types and concerns that match, with "Matches your skin profile". Without a profile it reads "Not sure? Take the skin quiz" (when a quiz page is chosen).
* Collection pages offer "Filter for oily skin" in place of the quiz prompt, when the collection has that filter.
* "Change" goes back to the quiz page.

## Step 6: set up the glossary and ingredient pages

1. **Online Store › Pages › Add page**, titled for example "Ingredients", with the theme template `ingredients`.
2. **Theme settings › Skin and formula › Ingredient glossary page**: choose it. The home page teaser's "Browse A to Z" link goes there.
3. Each Ingredient entry's own page uses the **Ingredient** section: image, name, also known as, category, typical strength, the long explainer, the concerns it's good for, and a grid of the entry's `products` (or a "See products with niacinamide" button that opens your catalogue filtered by the Key ingredient filter).

The full glossary shows an A to Z letter rail, a search field and concern chips that filter the cards, with entries grouped by letter. Glossary cards link to "4 products" when the entry's `products` field is filled, or to "See products" (the Key ingredient filter) when it isn't. Until the store has at least one Ingredient entry, glossary sections are hidden from shoppers and the editor shows a note.

## The product page blocks that read this data

All four live in the **Formula and use** section (product pages only).

**Formula**: the strength card and formula notes, the key active cards (each a big percentage, name, also known as, summary and an "About niacinamide" link), and the full ingredient list with a search ("Check for an ingredient": "Glycerin is in this formula, 3rd of 14.") and a Copy list button.

| Setting | Default | Notes |
| --- | --- | --- |
| Active cards | 3 | 0 to 4. Set to 0 to hide the active cards (Bloom does this for colour cosmetics). |
| Show ingredient list | On | |
| Show ingredient search | On | |
| Show copy button | On | |
| Show free from | On | |
| Link glossary entries | On | Links ingredients in the list to their glossary entry. Reads the first 50 Ingredient entries. |
| Link actives to filtered products | Off | Links each active to your catalog filtered by that ingredient instead of its own page. Needs the Key ingredient filter. |

**How to use**: "When" chips, a routine track with this product's step lit and a sentence such as "After cleansing and toning, before moisturiser.", Amount, How often, Pairs well with, Don't layer with, the directions, the patch test callout and the SPF reminder. Settings: "Label" (default "How to use"), "Heading" (default "Use it after cleansing, morning and night"), "Show routine track" (on), "Show patch test note" (on; uses `derma.patch_test`, or the theme setting). With no routine data it shows only the patch test note, and with that off, nothing. The patch test note alone doesn't make a band: a Formula and use band whose other blocks have nothing for this product isn't shown.

**Clinical results**: results from the product's `derma.studies`, with footnotes. Settings: "Label" (default "Clinical results"), "Heading" (default "What people saw"), "Show before and after" (off; needs both images and a caption on the study).

**Supplement facts**: chips for the daily amount, servings and how long a container lasts (when `derma.amount` and `derma.serving_size` both start with a number), the facts panel, then other ingredients, allergens, warnings and the supplement disclaimer from theme settings. Settings: "Title" (default "Supplement facts"; use the name your regulator requires, such as Nutrition information), "Daily value column" (default "% Daily value"; "%NRV" in the EU and Australia), "Footnote" (default "† Daily value not established."). Without `derma.facts` the block renders nothing, disclaimer included.

**Details** (spec table) can also go in this band for rows such as texture, size and where it's made.

**Suits your skin** sits in the main Product section and has no settings. It renders nothing for products without `derma.skin_types` or `derma.concerns`.

## Known limits

* **50 items per loop.** Shopify Liquid reads at most 50 items in a loop. The glossary page shows 50 entries per page and paginates past that; the glossary search and concern chips filter the entries on the current page. Ingredient-list links reach the first 50 Ingredient entries (key actives are always linked, through `derma.actives`).
* **No reverse lookup.** Liquid can't find "every product that contains this ingredient". Fill the entry's `products` field for a count and grid, or rely on the Key ingredient filter link.
* **Search & Discovery limits.** Filters don't show on collections with more than 5,000 products, so point quiz answers at smaller collections. Metafield list values are capped at 128 entries.
* **Exact matching.** Filter values match exactly. "Oily" on a product doesn't match an answer whose filter value is "oily skin". Preset choices on the definitions prevent drift.
* **The profile lives on one device.** It's stored in the browser, so it doesn't follow a shopper to another device and is cleared with their browser data.
* **Accordion rows need connecting.** The product template's metafield rows ship empty because a theme can't connect to metafields before your store defines them (chapter 6).
