---
title: "Hyper-personalization: a store for every shopper | Crystallize"
description: "Rank by Taste re-orders search, categories, menus and basket for each shopper, from your catalogue tags and their orders. Built into the Discovery API."
canonical: "https://crystallize.com/hyper-personalization"
page_type: "landing-page"
image: "https://crystallize.com/hyper-personalization-share.jpg"
---

# Hyper-personalization: A different store for every shopper

Rank by Taste re-orders every page for the person looking at it, from nothing but what they have bought. No segments to maintain, no rules per customer, no second system

[Try the photo store](https://photo-store-vector.superfast.shop)

## The idea in one picture

You know the idea from music streaming: the app learns your taste and plays more of what fits. Rank by Taste does the same for a catalogue. Every product is described by what it is and who it is for, every shopper builds a profile in the same words, and the store puts the best matches first

## Your rules stay in charge

Next to the shopper’s taste sit the things a merchandiser cares about: what sells, what earns, what’s in stock, what’s on campaign and what’s new. Every page gets its own blend

Shift the mix: all the way towards the store rules and everyone sees the same bestseller shelf, all the way towards taste and the shopper leads. Merchandisers tune it live in the store and watch every page re-order as they go. A great match that’s out of stock won’t sit on top

## Personalization your team can actually run

Rank by Taste is part of the Discovery API on every Crystallize tenant. No add-on, nothing to install, no model to train. It’s in your Crystallize already
- **Ready on day one** It runs on the product tags you already keep, inside the search itself, at search speed. No training data, no overnight jobs
- **Merchandisers in control** Taste never overrules the business. Margin, stock, sales and campaigns keep their say, tuned per page
- **Explainable** Every position comes with its reasons, so decisions are made on facts, and can be explained to anyone
- **B2C and B2B, any market** Consumers and business buyers, UK and US, own prices and tax: the same approach for all of them

## No black box

Each product on each page comes with its reasons: how much came from the shopper’s taste profile and how much from your own rules. Merchandisers tune against facts, not hunches
- **In the store, click the score.** Any product card shows its breakdown
- **Same answer every time.** The breakdown adds up to exactly the position you see

## 1. Describe products once

The tags your team already keeps in the product catalogue become its taste profile. Nothing else to maintain
- **Three lenses.** Which brand and camera system it belongs to, what people use it for, and what kind of gear it is
- **Order matters.** A Tamron lens made for Nikon is mostly Tamron, but also a little bit Nikon, so a Nikon shooter still finds it
- **“Fits anything” stays neutral.** A tripod that works with every camera doesn’t pull every accessory buyer towards every tripod

## 2. Shoppers profile themselves

The profile is built from real orders in Crystallize. No surveys, no guesswork, and nothing about the customer is hard-coded
- **Recent counts more.** What someone bought last month says more than what they bought two years ago
- **Big decisions count more.** A $5,000 lens says more about a photographer than a memory card
- **No history yet? No problem.** A new shopper sees your own mix: bestsellers, campaigns, new arrivals. The first order starts the profile, and the next page already knows

## 3. Match

For every page, the whole catalogue is lined up against the shopper’s profile. The more a product has in common with them, the higher it goes
- **Across all three lenses at once.** Right brand and right use beats either one alone
- **Never the wrong system.** A Nikon photographer isn’t shown lenses that don’t fit their camera
- **Inside search itself.** No separate recommendation engine, no overnight job: it happens as the page loads

## One profile. Every page

The same taste profile and the same rules work wherever products are shown, so the whole store feels like it knows the shopper, not just one widget on the front page
- **Front page & campaigns:** Banners and product picks ordered for the shopper. Oliver opens on Nikon instant savings, Milo on DJI deals
- **Category pages:** The same filters for everyone, a different order for each. In Lenses, the glass that fits their camera comes first
- **Search & suggestions:** The words typed lead, taste breaks the ties, typos are forgiven. "nikkon" still finds Nikkor, ranked for Oliver’s Z kit
- **Menu:** Every category in the menu shows its three best picks for this shopper. Amelia sees primes under Lenses, Milo sees zooms
- **Product page:** Similar products found automatically, plus picks for the shopper. No hand-made related-products lists to keep up to date
- **Basket & checkout:** What is in the basket counts most: add-ons that complete it, never a second version of the same thing. A Nikon lens in the basket suggests Nikon bodies, never another lens
The live page shows this same set of surfaces for furniture and food, matched to each industry's own catalogue.

## For developers

Under the hood a taste profile is a vector. Products get theirs from their tags, shoppers get theirs from their orders, and Discovery scores how close the two are as one signal in the ranking, next to relevance, recency, stock and your own field boosts

Nothing about the shopper is stored in Crystallize: build their vector from their orders, send it with the query, set the weights per page, and read the breakdown back with every hit. This one runs against the real catalogue of the store you have open. Change the shopper or the weights and run it again
### The photo store

Endpoint: https://api.crystallize.com/photo-store/discovery

```graphql
# The camera store, ranked for one shopper on top of the store’s own rules.
# The shopper and the mix are in the variables: change them and run again.
query RankedForShopper($context: ContextInput!, $rankBy: RankByInput!) {
  browse {
    product(language: en, context: $context, rankBy: $rankBy, pagination: { limit: 8 }) {
      hits {
        name
        rankScore
        rankExplain { signal contribution }
        topicPaths(leafOnly: true)
        defaultVariant { sku defaultPrice }
      }
    }
  }
}
```

Variables:

```json
{
  "context": {
    "userTaste": [
      {
        "vocabulary": "brand",
        "weights": {
          "brand:nikon": 1
        },
        "magnitude": 1
      },
      {
        "vocabulary": "usecase",
        "weights": {
          "usecase:wildlife": 1
        },
        "magnitude": 1
      }
    ]
  },
  "rankBy": {
    "terms": [
      {
        "signal": "tasteCosine",
        "weight": 1,
        "vocabulary": "brand",
        "from": "userTaste"
      },
      {
        "signal": "tasteCosine",
        "weight": 0.8,
        "vocabulary": "usecase",
        "from": "userTaste"
      },
      {
        "signal": "inStockBoost",
        "weight": 0.4,
        "field": "stock_default"
      },
      {
        "signal": "fieldBoost",
        "weight": 0.6,
        "field": "margin_number"
      },
      {
        "signal": "recency",
        "weight": 0.2,
        "field": "publishedAt",
        "halfLifeDays": 60
      }
    ],
    "tieBreaker": "itemId",
    "explain": true
  }
}
```
### The furniture store

Endpoint: https://api.crystallize.com/sofa-configurator/discovery

```graphql
# The furniture store, in the order the store itself sets: margin, sales, rating, stock.
# The mix is in the variables: change the weights and run again.
query RankedByTheStore($rankBy: RankByInput!) {
  browse {
    furniture(language: en, rankBy: $rankBy, pagination: { limit: 8 }) {
      hits {
        name
        rankScore
        rankExplain { signal contribution }
        topicPaths(leafOnly: true)
        defaultVariant { sku defaultPrice }
      }
    }
  }
}
```

Variables:

```json
{
  "rankBy": {
    "terms": [
      {
        "signal": "fieldBoost",
        "weight": 0.6,
        "field": "merchandising_margin_number"
      },
      {
        "signal": "fieldBoost",
        "weight": 0.5,
        "field": "merchandising_sold_30d_number"
      },
      {
        "signal": "fieldBoost",
        "weight": 0.3,
        "field": "merchandising_rating_number"
      },
      {
        "signal": "inStockBoost",
        "weight": 0.4,
        "field": "stock_default"
      }
    ],
    "tieBreaker": "itemId",
    "explain": true
  }
}
```
### The food store

Endpoint: https://api.crystallize.com/food-universe/discovery

```graphql
# The food store, ranked for one shopper on top of the store’s own rules.
# The shopper and the mix are in the variables: change them and run again.
query RankedForShopper($context: ContextInput!, $rankBy: RankByInput!) {
  browse {
    product(language: en, context: $context, rankBy: $rankBy, pagination: { limit: 8 }) {
      hits {
        name
        rankScore
        rankExplain { signal contribution }
        topicPaths(leafOnly: true)
        defaultVariant { sku defaultPrice }
      }
    }
  }
}
```

Variables:

```json
{
  "context": {
    "userTaste": [
      {
        "vocabulary": "taste",
        "weights": {
          "cuisine:italian": 1,
          "occasion:dinner": 0.6,
          "main-ingredient:dairy": 0.5
        },
        "magnitude": 1.2689
      }
    ]
  },
  "rankBy": {
    "terms": [
      {
        "signal": "tasteCosine",
        "weight": 1,
        "vocabulary": "taste",
        "from": "userTaste"
      },
      {
        "signal": "inStockBoost",
        "weight": 0.4,
        "field": "stock_default"
      },
      {
        "signal": "fieldBoost",
        "weight": 0.6,
        "field": "commercial_margin_number"
      },
      {
        "signal": "fieldBoost",
        "weight": 0.3,
        "field": "commercial_salesVelocity_number"
      }
    ],
    "tieBreaker": "itemId",
    "explain": true
  }
}
```

## See it for yourself

Pick a shopper, watch every page re-order, click any score for its reasons. Then picture it on your own catalogue
- [Open the demo store](https://photo-store-vector.superfast.shop)
- [Watch the livestream](https://www.youtube.com/watch?v=lnmhrg7GDqo)
Demo stores, one per industry:
- [The photo store](https://photo-store-vector.superfast.shop): consumer electronics, as a retailer
- [The furniture store](https://furniture-universe.superfast.shop): furniture, as a manufacturer
- [The food store](https://food-universe.superfast.shop): food & beverage, as a distributor
All our demo stores, for every industry, are on [superfast.shop](https://superfast.shop).

## Questions

### What about shoppers with no order history?

They see your own mix: bestsellers, campaigns, new arrivals, in stock first, exactly as the merchandiser set it. Nothing is guessed. The first order starts the taste profile, and the next page already uses it

### Is Rank by Taste a separate recommendation engine?

No. It is a ranking signal inside the Discovery API, in the same query that already serves search, categories and menus. There is no second index to sync, no separate service to host and no overnight job

### Do we need to train a model or collect browsing sessions?

No. Products get their taste profile from the tags already in your catalogue, and shoppers get theirs from their orders in Crystallize. It works from the first day, on a catalogue of any size

### Can merchandisers override it?

Yes. Taste is one weight next to stock, margin, sales, campaigns and recency, tuned per page. Turn it all the way towards the store rules and everyone sees the same shelf. Turn it towards taste and the shopper leads

### Does it work for B2B?

Yes. A business account builds its profile the same way, from what it orders, while its own price list, market and tax rules still apply

### Which pages does it cover?

Any page that queries Discovery: the front page, categories, search, menus, product pages, the basket and the checkout. One profile, every surface

### What is the difference between hyper-personalization, Rank by Taste and a taste profile?

Hyper-personalization is the outcome: a store that re-orders itself for each shopper. Rank by Taste is the Crystallize feature that does it, inside the Discovery API. A taste profile is the mechanism: a vector built from tags for a product and from orders for a shopper, compared at query time
