Memory & privacy

Insights without surveillance

How a store learns what shoppers want without ever seeing one shopper’s conversation.

HawkShift Research··9 min read

In short

  • Stores get patterns of demand from Concierge conversations: what people asked for, what they couldn’t find, what put them off. They never get a conversation, a shopper or a quote.
  • We launched with a 25-shopper minimum behind every pattern. On a small store it hid nearly everything and protected no one: “3 shoppers asked for laptops” names nobody.
  • What leaks from conversation analytics is wording, not counts. Small patterns now show when their wording is an everyday shopping term, they aren’t about a sensitive topic, and they can’t be stacked into one person’s profile.
  • On our test store, the same month went from 4 reportable patterns to 73. Another 36 stay private, because they would describe a single shopper or concern a sensitive topic.
1shopper is enough for anonymous demand to show
4 → 73patterns on our test store in one month, before and after we dropped the minimum
0shopper words or conversations a store can open

Measured on our own test store in September 2026: 102 shoppers, 409 conversations. Why the minimum went, and what replaced it, is below.

What changed

Updated 27 September 2026. We have retired the 25-shopper minimum and the subtraction check this article describes. They were built to stop a real leak, and they did, but on a small store they did it by hiding every number, including the ones that describe nobody. Stores now see anonymous demand at any size, and what we withhold is what could describe a person. The original design is kept below as we wrote it, because the reasoning is still useful and because the arithmetic in it is the reason we changed course. The new sections start at Why we dropped the minimum.

The promise

A store that installs Concierge wants to know what its shoppers are looking for. That is fair: it is the most useful thing a conversation can tell a business. “Twelve people asked for a waterproof version this week” is worth more than a thousand page views.

A shopper who talks to Concierge, meanwhile, is often more candid than they would be on a form. They mention a budget, a body shape, a partner’s birthday, a health condition that makes one chair better than another. None of that was said to the store, and none of it should reach the store.

So we made a firm rule early on: stores learn what shoppers want, never who wants it. Conversations, remembered preferences, price watches and the actions Concierge took are held by HawkShift for the shopper. A store cannot open them, export them or request them, including through its platform’s customer-data requests.

Patterns, not people

What a store does get is demand, in aggregate. After a conversation, a separate process reads it and records the demand it contains in a fixed, named vocabulary: the kind of product, the need behind it, the reason something didn’t fit. The record is attached to a group for that store and period, never to a shopper.

That separation is structural, not a policy. The table that holds demand has no column for a shopper, so no query can join a pattern back to a person. The link that does exist, from a conversation to its group, is what lets us honour a shopper’s own privacy requests, and it is never exposed to a store.

Then two gates stand between those records and a store’s dashboard.

Why a minimum isn’t enough

The first gate is the familiar one: a pattern is only shown if at least 25 different shoppers are behind it. This is the idea behind k-anonymity, and most analytics products stop here.

It doesn’t hold on its own. Imagine a store sees two numbers, both well above 25:

Published patternShoppers
Decided against a sunglasses model30
… of whom mentioned glare28
Each number is safely large. Subtract them and you learn about two people who rejected it for another reason, and a store with its own records may know exactly who they were.

This is a differencing attack, and it needs no hacking at all, only subtraction. A per-number threshold can’t see it, because each number is fine on its own. The danger is in the pair.

So the second gate compares every new number with the ones already published for that store and period. If the difference between them names fewer than 25 people, the new number is refused.

The arithmetic

That second gate has a consequence worth stating plainly. With a minimum group size k and a total of P shoppers in a period, a smaller pattern of c shoppers can only be published if it covers at least k people and leaves at least k people outside it:

k ≤ c ≤ P − k, which is impossible unless P ≥ 2k.

With k = 25, that means a store needs roughly 50 distinct shoppers talking to Concierge in a period before anything finer than a whole-population total can appear. Below that, the honest answer is that there is nothing safe to show yet.

Smaller leaks we closed

Two more problems only surfaced when we tested the gates directly, and both are easy to miss.

A hidden pattern must hide its label too

Suppressing the count of a small pattern isn’t enough if its description is still shown. Labels are written from what people said, and a group of one carries a phrase only that person would produce. A pattern that fails the gate now disappears entirely: no count, no label, no “fewer than 25”.

Two publishers at once

The differencing check reads what is already published. If two updates run at the same moment, each can pass against the old state and together publish exactly the pair the check exists to prevent. The final commit now re-reads the published record before it writes, so the second update sees the first.

What it doesn’t cover

We would rather state the limits than imply a guarantee we don’t have. This design is a bounded defence against the most common attack, not a proof of anonymity.

  • Overlapping patterns that don’t nest can still, in principle, be combined to narrow a group.
  • What a store already knows from its own orders or its own customers is outside our control.
  • Differences across periods, this month against last, are not yet checked.

Formal methods such as differential privacy address some of these with added noise, at the cost of accuracy that small stores can least afford. Whether that trade is worth making for a small store is still an open question for us.

An empty dashboard is the system working

The strangest part of shipping this was accepting what it looks like at first. A new store, or a small one, opens its insights page and sees nothing. It would be easy to make that page look busy: lower the minimum, skip the pair check, show “trending” guesses. Each would make the demo better and the promise worse.

Instead the page explains itself: patterns appear once enough shoppers have talked to Concierge that no one can be picked out. For a store owner that is a clear, honest reason. For a shopper it is the reason they can talk freely.

  1. Make the separation structuralIf demand records can’t name a shopper, no later feature can leak one by accident.
  2. Check pairs, not just numbersA threshold on each number misses the subtraction between them.
  3. Suppress labels with countsA description can identify a small group as well as a number can.
  4. Publish the arithmeticTell stores why a small period is empty, instead of weakening the rule to fill it.

Why we dropped the minimum

The minimum came from a careful place. CanaryBench, a 2026 study of privacy in conversation analytics, planted secret phrases in chats and then checked whether the analytics built from those chats gave them away. When summaries were written from only a few conversations, they did: a model describing a group of one tends to repeat what that one person said. A minimum of 25 people per group, together with redaction, brought the leak to zero.

Look closely at what leaked, though. It was never a count. It was the wording of a label. The minimum worked because a label shared by 25 people can’t be one person’s phrase. It also worked by hiding every count below 25, and for a small business those counts are the whole picture.

The arithmetic in the section above says a store needed about 50 shoppers in a month before anything finer than a total could appear. In practice it was worse. On our own test store, with 102 shoppers and 409 conversations in a month, the page could show at most four patterns. Everything else was “withheld”: the one shopper looking for a laptop, the three who wanted headphones the store doesn’t stock, the two who named a budget under $50. None of those numbers identifies anyone. Hiding them protected nobody, and it cost the store the one thing a small business most needs to know: what people came in for that it couldn’t sell them.

We also found a failure the arithmetic didn’t predict. The subtraction check remembered the first number it had ever shown for each pattern that month. A pattern shown at 28 shoppers was later compared, at 33, against that stale 28, and the “difference of five” hid it, even though five new shoppers arriving over a week describes nobody. Every pattern a store looked at early in the month could start hiding the patterns around it as it grew.

Privacy should protect the person. It shouldn’t hide anonymous demand.

What protects shoppers now

The structural protections are unchanged. A store still can’t open a conversation, look up a shopper, or see a quote, and the demand records still have no column that could name a person. What changed is the check between those records and the page. A number is shown at any size. A pattern from only a few shoppers is marked as an early signal, which is a statement about confidence (worth watching, not yet a trend), and it has to pass three checks before it appears.

The wording is an everyday shopping term

This is the check that replaces the minimum, because it targets what actually leaked. Every label in a small pattern, whether a product type, a feature or a reason, is judged by a separate model pass: is this something any shopper could say, or does it point at one person? A product type, a brand, a colour, a price posture or “not in your catalog” passes. A name, a place, a date, a life event or a health detail doesn’t. Each label is judged once and the answer is kept. A label that hasn’t been judged yet is treated as personal, so if the check is ever unavailable, small patterns wait rather than appear unchecked.

LabelEveryday term?Sensitive?
wedding giftsYesNo
gift for sister weddingNoNo
delivery to brooklynNoNo
usb-c power deliveryYesNo
diabetic friendlyYesYes
after knee surgeryNoYes
Six of the twenty labels we used to probe the check before shipping it. All twenty were judged the way we would have judged them. Twenty is a small sample, and the check is backed by the two rules below rather than trusted alone.

Sensitive topics are never early signals

Health, sexual life, pregnancy, religion, ethnicity, politics and financial hardship are the categories data protection law treats as special, and we treat them the same way. “One shopper asked about laptops” is anonymous. “One shopper asked about a medical condition” is not something a store should read, however anonymous it is. Sensitive patterns appear only once several shoppers share them.

One detail at a time

A single pattern can’t identify anyone. Several patterns about the same small group can: an area, a budget, a feature and a reason, all from one shopper, add up to a profile. So a small pattern carries at most one detail beside its area, and only when the area itself has several shoppers, so nobody can tell whose detail it is. “The store doesn’t carry it” doesn’t count as a detail, because it describes the store, not the shopper. Patterns are monthly totals, and stores choose from a fixed set of views rather than slicing the data freely, so they can’t assemble the stack themselves.

The subtraction check went away with the minimum. Subtracting one number from another gives back a number, never the wording or the detail behind it, and a number with nothing attached describes no one.

What’s still open

  • What a store already knows. If a store owner knows the one customer who emailed about laptops this month, “1 shopper asked about laptops” tells them that customer also used Concierge. The detail rules above stop it telling them anything more.
  • Watching the page every day. Totals are monthly, but a store that checks daily can see a number move by one. This is why detail needs an area of several shoppers.
  • A wrong judgement. The wording check is a model, and a model can be wrong. It is one of three checks, it fails closed, and every label it has passed is stored where we can audit it.
  • Across months. Month-to-month comparison is shown by area only, never at the level of detail.

Differential privacy, which adds calibrated noise to every number, would close more of these gaps. It would also blur exactly the small counts that make this useful to a small store, and we don’t think that trade is right yet. We’ll keep publishing what we measure.

  1. Protect the person, not the numberA count with nothing attached describes no one. Hide what could describe someone, whatever the count.
  2. Check the words, not the sizeLeaks come from labels a model copied from one person. Judge the label.
  3. One detail at a timeA pattern alone identifies no one; a stack of them can. Limit the stack, not the pattern.
  4. Mark confidence, don’t hide itAn early signal is labelled as early. A small number is information, not a risk.
  5. Fail closedAnything not yet checked waits. A slower dashboard is better than an unchecked one.

HawkShift Research · Updated . Numbers are from our own tests while building Concierge; small samples are marked as small.