Blog · · 12 min
Social proof when you have no customers yet
With zero reviews there are four honest proofs left and none of them is a star rating: proof by material, proof by method, proof by written commitment, and an honest counter. Inventing reviews is listed as unfair in all circumstances in EU law, and it is visible anyway. The component has to render a useful empty state instead of an empty carousel.
By uxgen
Four proofs survive having no customers, and none of them is a star. Proof by material: photographs of the real object, close enough that nobody could copy them. Proof by method: saying how the thing is made and by whom. Proof by commitment: a return policy written in full, which is a promise you can be held to. Proof by honest counter: open since March, not 12,000 happy customers. Fabricating the fifth one is a bad idea legally and a worse one practically, because it shows.
We are writing this from inside the problem. uxgen.ai has no paying customers to date, and its own site says so in plain words. Everything below is what we do instead.
Why not just write a few reviews to get started?
Two reasons, and the commercial one is heavier than the legal one.
The legal one first, briefly. Directive (EU) 2019/2161 inserted new entries into Annex I of Directive 2005/29/EC, the list of commercial practices considered unfair in all circumstances. Point 23c covers submitting, or commissioning someone else to submit, false consumer reviews or endorsements in order to promote a product. Point 23b covers stating that reviews come from consumers who actually used or bought the product without taking reasonable and proportionate steps to check that they do. That list is a blacklist: no case-by-case assessment of whether the buyer was actually misled. Each member state transposed it into its own consumer code with its own enforcement and its own penalties, so check the local text rather than this paragraph.
The commercial one. Invented reviews read as invented. Five reviews on a store with no other history, all four or five stars, all posted in the same fortnight, all written in the same register, praising the same two attributes. A buyer does not have to reason about it, and they do not have to be right about it either. They only have to feel it, once, and the doubt attaches to the whole page including the parts that were true.
The worst part is what it costs you afterwards. Once fabricated reviews are on the page, every real proof beside them is read as fabricated too. Your genuine close-up photographs, your genuine returns policy: all downgraded by association. You spend the proof you actually had to buy proof you did not.
Which proofs actually survive zero customers?
The useful sort is not by persuasiveness. It is by what it would cost a competitor to copy, because a proof anyone can duplicate in ten seconds is not carrying the weight you think it is.
| Proof | What it costs to fake | Needs a customer? | Where it lives |
|---|---|---|---|
| Close-up photographs of the real object | a real object and a real shoot | no | gallery, top of page |
| The method: who makes it, where, how | it has to be true and specific | no | a named section, mid-page |
| Written return policy, unusually generous | a commitment you have to honour | no | under the buy button |
| Certificate, test report, lab result you can link | the actual test | no | linked, near the claim |
| Honest opening date | nothing, and that is fine, it is checkable | no | footer or about |
| Named founder, real face, reachable address | a real identity | no | about, footer |
| Star average and review count | a text file, five minutes | yes | nowhere, until you have them |
Read the last two rows together. A named person with a face and a postal address is harder to fake than a 4.8 average, and buyers price that difference correctly even when they never articulate it.
Proof by material is the one most stores skip because it costs a day of work. It is also the only one that cannot be produced by a language model. A generated store can invent a founder's biography and a returns policy in one prompt; it cannot photograph a thing that exists. That asymmetry is exactly what makes a real photograph worth more today than it was five years ago.

What does an honest counter look like?
It comes out of a query. That is the whole rule. A number typed into a constant is a claim with nothing behind it, and it stays wrong forever after the day someone typed it.
// Wrong: a figure nobody can trace back to a row in a table.
const HAPPY_CUSTOMERS = 12_000
// Right: the same figure, from the only place it can honestly come from,
// or nothing at all.
const shipped = await db.order.count({ where: { shippedAt: { not: null } } })
/**
* Below your own comfort threshold, print nothing.
* "7 orders shipped" is true and works against you; that is an editorial
* decision, not a licence to round it up. Silence is the honest small number.
*/
export const orderLine = shipped >= 50 ? `${shipped} orders shipped so far` : null
/**
* The counter that works from day one, because it counts time and not people.
* Returns null rather than a nonsense string if the date is bad or in the
* future, so a typo in a config file cannot print "Open since March 2027".
*/
export function openSince(iso: string, locale = 'en-GB'): string | null {
const start = new Date(iso)
if (Number.isNaN(start.getTime()) || start > new Date()) return null
const when = new Intl.DateTimeFormat(locale, {
month: 'long',
year: 'numeric',
}).format(start)
return `Open since ${when}`
}
The threshold of 50 is ours and it is arbitrary. Pick your own, write it down, and apply it in one place. What must not happen is a component that decides at render time to show the number when it looks good and hide it when it does not, because that is the same dishonesty in slower motion.
How does a proof component degrade properly?
This is the part every implementation skips, and it is the reason a new store looks broken. An agent asked for a social proof section returns a review carousel. With no reviews the carousel renders as an empty rounded rectangle, or worse, as a skeleton loader that never resolves. The page then carries a hole exactly where the reassurance was supposed to be, which is worse than not having the section at all.
The fix is a component that takes several kinds of proof, keeps only the ones that hold, and renders the strongest of them.
type Proof =
| { kind: 'material'; photos: { src: string; alt: string }[] }
| { kind: 'method'; heading: string; steps: string[] }
| { kind: 'commitment'; summary: string; href: string }
| { kind: 'age'; openedOn: string }
| { kind: 'reviews'; count: number; average: number }
/** A proof is kept only if it has something real inside it. */
function holds(p: Proof): boolean {
switch (p.kind) {
case 'material': return p.photos.length >= 3
case 'method': return p.steps.length >= 2
case 'commitment': return p.summary.trim().length > 30
case 'age': return openSince(p.openedOn) !== null
// The one line that stops an empty carousel from ever reaching a page.
case 'reviews': return p.count > 0
}
}
/** Strongest first, so the section leads with what is hardest to copy. */
const ORDER: Proof['kind'][] = ['material', 'method', 'commitment', 'reviews', 'age']
export function ProofSection({ proofs }: { proofs: Proof[] }) {
const kept = proofs
.filter(holds)
.sort((a, b) => ORDER.indexOf(a.kind) - ORDER.indexOf(b.kind))
// No proof at all: render nothing. An empty section is a hole in the page,
// and a hole reads as something that failed to load.
if (kept.length === 0) return null
return (
<section className="proof">
{kept.map((p) => (
<ProofBlock key={p.kind} proof={p} />
))}
</section>
)
}
Two properties are worth naming because they are what a generated version will not have.
There is no placeholder branch. No Be the first to review, no greyed-out stars, no skeleton. Each of those advertises the absence. The section simply gets shorter, and a shorter page with four honest blocks reads as deliberate.
The ordering is a decision, not a prop. Material first because it is the hardest to fabricate. Reviews near the end because when they finally exist they will be the easiest thing on the page to doubt. Making the order configurable would mean handing the most important judgment in the component to whoever configures it fastest.
When the reviews finally arrive, what changes?
Only one thing: reviews starts to hold, and the section grows a block. Nothing else in the page moves, which is the point of the shape above.
At that moment a second question opens, which is what markup to attach so the stars can appear in a search result, and what happens if the markup describes reviews the visitor cannot see. That has its own answer, in a reviews section with real structured data. Until then, emitting no rating markup at all is not a missed opportunity: it is the only correct output.
And if what you were reaching for was reassurance rather than reviews, the sorting rule for the little seals under the buy button is in trust badges on a product page. Most of them fail the same test the invented review fails, for the same reason.
Why we can write this without flinching
Because we are in it. uxgen.ai has no paying customers as of today, the site states that on its own pages, and we have not put a single fabricated testimonial anywhere. What is there instead is the code, in the open, under an MIT licence, along with the reasoning behind each component. A repository someone can read is a proof by material: it exists, it can be inspected, and no prompt produces it.
This is also the least glamorous of the four proofs and the one that takes the longest, which is why so few new stores use it. The store that spends a day photographing the actual object ends up with something no competitor can lift, at a moment when everything else on the page can be regenerated in a minute.
The other thing to accept early is that you cannot test your way out of this. Below roughly forty thousand sessions per variant a split test cannot separate a real effect from noise, which describes almost every new store. What to do instead is set out in ecommerce conversion rate optimization without traffic.
FAQ
How do I show social proof with no reviews?
Use the proofs that do not require a customer. Photographs of the real object taken close enough that they could not be lifted from a supplier catalogue, a plain description of how and where it is made, a return policy written out in full with who pays the postage, and an honest counter such as the month you opened. Each of those is checkable, and checkable is what social proof was ever for.
Is it illegal to write my own reviews?
In the EU, submitting or commissioning false consumer reviews to promote a product is listed in Annex I of Directive 2005/29/EC as unfair in all circumstances, following the amendments made by Directive (EU) 2019/2161. Being on that list means no assessment of actual harm is required. The directive is transposed country by country with local enforcement and penalties, so check the national text that applies to you.
What should a reviews component render when there are no reviews?
Nothing at all, and no structured data either. A greyed-out star row, a be the first to review prompt or an empty carousel each announce the absence in a place the buyer was looking for reassurance. Let the section be absent and let the page be shorter. Render the review block only once the array is non-empty.
Can I display a customer counter on a new store?
Only if the number comes from a query rather than a constant, and only above a threshold you decided in advance and wrote down. A counter that reads seven is honest and unhelpful, so pick a floor and show nothing below it. Counting time instead of people works from the first day: an opening month is true, checkable, and needs nobody to have bought anything.
Where this leads
uxgen.ai is an MCP server that hands Claude 168 commerce components and installs them in the store as HTML the merchant keeps. Nothing to uninstall, no commission per order, $19, $29 or $59 a month. The cart components are specified in the open at github.com/kinerette/uxgen-commerce-kit under an MIT licence. There is no customer list to show you yet, and when there is one it will be a number out of a query.