My homepage showed the same price nine times.
I did not put it there nine times. It arrived one commit at a time: a hero rewrite that mentioned the audit band, a proof strip that repeated it, a funnel bridge that repeated it again, a newsletter panel that said "packages from $3K", a contact block that carried the proof line a second time. Each one made sense in its own pull request. Together they read like a shop with the price gun set to auto.
This note is the audit that found them, the research that decided what to keep, and the one-line rule that came out of it.
Last verified against nyk.dev rendered DOM, NN/g, Baymard, and 14 comparable sites. Version-specific details drift — check the vendor docs before relying on an exact flag or limit.
Why more price mentions fail to convert more
The intuition is that a visitor who sees the price early self-qualifies, so repeating it costs nothing. Two things are wrong with that.
First, banner blindness applies to your own copy. Elements that look the same and repeat get filtered by the reader; the ninth $4K-$7K is invisible in the way the ninth cookie banner is invisible, and it takes the surrounding sentence with it.
Second, a price that appears before the visitor knows what they are buying is a tag without a product. In the hero, "$4K-$7K" sat in the second sentence, before the page had said what a Reliability Audit returns. A price wants to sit next to the thing it prices.
What the research does support is a floor. Nielsen Norman's B2B work found buyers put pricing at the top of the information they need, and that hiding it triggers a distrust halo over the whole company. So the decision is not "price or no price". It is "where, and how many times".
By the end you will have
- The Price Exposure DOM Walk: a browser snippet that lists every visible price string on a page with its position, section, and font size.
- A before and after count from a real homepage.
- Sources for the three claims that decided the cut, graded by how strong they are.
- A placement rule you can apply to a hub page that sells services and products together.
The DOM walk found nine copies of one price
The snippet below runs in DevTools or through Playwright's page.evaluate. It walks text nodes, matches currency patterns, skips hidden elements, and reports where each hit sits.
Before, at 1440px:
| y | Section | Text |
|---|---|---|
| 408 | Hero | "…already broke. $4K-$7K. Two weeks." |
| 862 | Proof strip | "Reliability Audit: $4K-$7K, two weeks…" |
| 1247 | Offer (proof line) | "…Reliability Audit $4K-$7K · packages from $3K…" |
| 1421-1509 | Offer cards | $4K-$7K, $8K-$12K, then both again in a summary line |
| 2053 / 2447 | Product cards | €149, €299 (header and footer each) |
| 3527 | Ventures chip | "Reliability Audit · $4-7K" |
| 4048 | Funnel strip | "…first paid step is a Reliability Audit, $4K-$7K." |
| 4644 | Newsletter | "…packages from $3K." |
| 6500 / 6540 | Contact | proof line again, link again |
Fifteen price strings. The audit band nine times. Two of the nine came from one shared constant rendered in two sections, which is why grepping the source undercounted.
After the cut: six strings. The audit and setup prices on the two offer cards, where the decision is made, and the two product prices on their own cards. The hero, the proof strip, the ventures chip, the funnel bridge, the newsletter, and the contact block carry none.
Magnet: Price Exposure DOM Walk
// Paste into the console on the page you are auditing.
(() => {
const re = /(€|\$)\s?\d[\d,.]*\s?K?(\s?[\u2013-]\s?\$?\d[\d,.]*\s?K?)?|\bfrom \$\d+K?/;
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
const hits = [];
for (let n; (n = walker.nextNode()); ) {
const text = n.textContent.replace(/\s+/g, " ").trim();
if (!text || !re.test(text)) continue;
const el = n.parentElement;
const cs = getComputedStyle(el);
if (cs.display === "none" || cs.visibility === "hidden" || el.closest("[hidden],[aria-hidden='true']")) continue;
const r = el.getBoundingClientRect();
if (!r.width && !r.height) continue;
const section = el.closest("section,header,footer,[data-section]");
hits.push({
y: Math.round(r.top + scrollY),
section: section?.id || section?.tagName || "?",
size: Math.round(parseFloat(cs.fontSize)),
text: text.slice(0, 90),
});
}
console.table(hits);
return `${hits.length} price strings on ${document.documentElement.scrollHeight}px`;
})();Scroll the whole page once before running it if sections are lazily rendered, so nothing is skipped as zero-size.
You should see: a table with one row per visible price, ordered top to bottom. Count how many rows carry the same number. If any number appears more than twice, decide which single position owns it and cut the rest.
The placement rule for a hub page
A hub sells more than one thing: here, consulting packages and self-serve products. The rule that came out of the research and the audit:
- Consulting: one floor, at the offer cards. The cards are the decision point. It sits above the products, so any anchoring effect a higher number has on the product prices survives. Not in the hero.
- Products: on their cards, and nowhere else. This is Baymard's product-page finding, which comes from large-sample usability testing but is scoped to product pages, not hub narratives.
- Proof lines and bridges carry no price. Stars, followers, a date. If a proof line has to mention money, it is not a proof line.
- The dedicated pages keep the full band.
/consultingand/contactstill state the price in their metadata and copy. The search snippet can name a number; the homepage narrative names it once.
Comparable sites, for calibration: leftclick.ai says "Engagements typically start at $5K" once, in the closing CTA. designgud.co has a price-free hero and one pricing panel mid-page. justinwelsh.me has no price on the homepage at all.
Failure modes
The source grep. grep -c '\$4K' said seven. The DOM said nine, because one constant rendered twice. Count what the visitor sees.
The hero band. The price in the second sentence of the hero, before the offer is explained. It was the first thing cut, and the one that had felt like transparency.
The proof line that prices. A line built for social proof (stars, followers, date) that grew a price. Now it is two things, and neither lands.
Cutting the floor. Going to zero mentions would trade a habituation problem for a trust problem. Keep one.
The test that pinned the repetition. The e2e suite asserted $4K-$7K in the hero and the proof strip. The cut required flipping those to negative assertions and adding a page-level guard: the band appears exactly once on /.
When not to apply this
Do not apply it to a pricing page. That page's job is to show every number; repetition across tiers is the content.
Do not apply it to a single-product landing page with one price. There the Baymard product-page finding applies: put it near the buy button and do not make people hunt.
Do not use it to justify hiding prices behind "contact us" for a sub-$25K service. The transparency evidence points the other way.
Price is a claim, and claims are stated once
You would not put the same testimonial in six sections. A price is a claim about value with a number on it, and it earns exactly the same treatment.
If the page you are auditing sells a productised engagement, the Reliability Audit is the shape this site settled on: one price, on one card, with the deliverables next to it.
Your next action: run the Price Exposure DOM Walk on your homepage, count the repeats, and give each number a single owner.






