Guide ·
Comparison and pricing pages for a software product: what to put on them
Three pages do most of the work when someone is about to choose a tool: an alternatives page, a “you vs them” page and a pricing page. Here is what each should hold, a terminal command that checks each part, and what is on our own comparison pages, with dates.
Why these pages
The people searching them are close to choosing
Someone who searches “[competitor] alternative” already wants a tool like yours. Someone who searches “[you] vs [them]” has narrowed it to two. Fewer people search these than broad topics, and the ones who do are close to picking. The pricing page is often the last page they read before they pay.
Most small software sites do not have these pages ready. In our study of 1,000 Show HN launch sites, checked without JavaScript on 20 Oct 2026, 148 of the 928 sites we reached (15.9%) had any comparison, vs or alternatives page, and 197 (21.2%) had a pricing page a crawler could find. Of the roughly 264 sites that showed a sign of selling something, 103 had a comparison page. The study counted with text rules checked by hand; its limits are on its page.
Before you start
Set your address once
The checks use curl, grep, sed and perl, which come with macOS and most Linux systems, and work the same in zsh and bash. Set your site’s address once, without a slash at the end. Steps that check one page set that page’s address too.
site=https://example.com
Page 1 · Alternatives
An alternatives page: a list where you are one option
Searched as “[competitor] alternative” or “[competitor] alternatives for Mac”. The reader is leaving a tool, or never liked it, and wants the field in one place.
Write one alternatives page, with you as one option
- Do
Name the tools your buyers already weigh, yours included, in one table near the top: price, platforms, licence and the one or two features buyers ask about. Then a short section on each tool. Write it for a reader who has not picked yet, and put the date you checked the prices on the page.
- Check
This prints the comparison and alternatives pages listed in your sitemap. No output means a buyer searching “[competitor] alternative” has no page of yours to land on.
curl -s "$site/sitemap.xml" | grep -o '<loc>[^<]*' | sed 's/<loc>//' | grep -i -E 'alternative|(^|[/-])vs([/-]|$)|versus|compar'- On our sites
Upright, Basalt’s free Mac app for Logitech mice, got a Logi Options+ alternatives page on 18 Oct 2026 (proof page). It compares 8 apps in one table, Logi Options+ included, and is dated “Updated October 20, 2026”. Run on Upright, the command printed:
https://upright.hellobasalt.dev/logi-options-alternatives https://upright.hellobasalt.dev/upright-vs-mac-mouse-fix https://upright.hellobasalt.dev/upright-vs-bettermouse https://upright.hellobasalt.dev/upright-vs-steermouse https://upright.hellobasalt.dev/upright-vs-openlogiThe last line is a fourth vs page, dated 20 Oct on the page itself.
Say who each tool suits, yours included
- Do
End with a “which one should you pick?” list: one line per kind of buyer, and the tool that fits them. Some lines should point away from you. That is what makes the page a comparison and not an ad.
- Check
This prints the page’s section headings. You want one per tool and one that helps the reader choose.
page="$site/your-alternatives-page" curl -s "$page" | grep -o -E '<h[23][^>]*>[^<]+' | sed -E 's/<h[23][^>]*>//'- On our sites
On Upright’s alternatives page it printed one heading per app and a section for choosing. Five of that section’s six lines send the reader to another app: OpenLogi, Mouser, BetterMouse, Mac Mouse Fix or LinearMouse, and SteerMouse.
At a glance Upright OpenLogi Mouser BetterMouse Mac Mouse Fix SteerMouse LinearMouse Which one should you pick? FAQ
Page 2 · You vs them
A “you vs them” page: a dated table, and where they win
Searched as “[you] vs [them]” or “[them] vs [you]”. The reader has narrowed it to two, so write one page for each rival buyers name.
Put a dated table at the top
- Do
One table near the top, with the same rows for both products. Put the date you checked their facts next to it, and link the pages you took them from. Their prices and features change; the date tells the reader how old your facts are, and tells you when to check again.
- Check
The first command counts the tables in the page’s HTML. The second prints any “checked”, “updated” or “written” date in its text.
page="$site/you-vs-them" curl -s "$page" | grep -c '<table' curl -s "$page" | perl -0777 -pe 's/<[^>]+>/ /g' | grep -o -i -E '(checked|updated|written) [^.]{0,30}20[0-9]{2}' | sort -u -f- On our sites
Upright’s three “vs” pages went live on 19 Oct 2026 (proof page): vs Mac Mouse Fix, vs BetterMouse and vs SteerMouse. Each has one “At a glance” table, the line “Checked 19 October 2026 · Facts from each developer’s own site” under the title, and its sources at the end. On vs Mac Mouse Fix the commands printed:
1 Checked 19 October 2026KahveDrop, our Turkish coffee finder, linked and dated its comparison page on 20 Oct: it answers ten “which one?” questions with 250 g prices side by side, under the line “Son güncelleme: 20 Ekim 2026” (last updated).
Say where they win
- Do
Add a short “which should you pick?” list and give them the lines they win: more devices, a lower price, a longer track record. Say what yours does not do yet, too.
- Check
Put their product’s name in
them. This prints every line where your page tells the reader to choose them. No output means the page never does.page="$site/you-vs-them"; them="Their App" curl -s "$page" | perl -0777 -pe 's/<[^>]+>//g' | grep -i -E "(choose |pick |: )$them" | sed 's/^ *//'- On our sites
Each of Upright’s three vs pages gives the other app half or more of its “Which should you pick?” lines: 3 of 6 on vs Mac Mouse Fix, 3 of 6 on vs BetterMouse and 3 of 5 on vs SteerMouse. On vs BetterMouse the command printed:
You want the most Logitech hardware control without Logi Options+: BetterMouse. Onboard profiles, the MX Master thumb wheel and keyboard settings are things Upright doesn't do. You also have a Logitech keyboard, or need to pair a Unifying or Bolt receiver: BetterMouse. You want a notarized app with polished smooth scrolling, and $7.99 is fine: BetterMouse.Upright’s MX Master 3S on Mac without Logi Options+ page, live on 20 Oct, says near the top: “Read this first: it is not tested on this mouse.”
Put both prices in the HTML
- Do
Write their price and yours as text in the table, with the date you checked, not in an image or a widget. The reader came to compare cost, and a crawler that does not run JavaScript sees only what is in the HTML.
- Check
This prints each price in the page’s text without scripts and styles, and how often it appears. Their price should be there, and so should yours unless the product is free. It looks for $, € and £; change the pattern for other currencies.
curl -s "$page" | perl -0777 -pe 's/<(script|style)\b.*?<\/\1>//gis; s/<[^>]+>/ /g' | grep -o -E '(US)?[$€£] ?[0-9][0-9,]*(\.[0-9]{2})?' | sort | uniq -c- On our sites
Upright is free, so its column says “Free”. The other app’s price is in the HTML of each page: $2.99 on vs Mac Mouse Fix, $7.99 on vs BetterMouse, and on vs SteerMouse the command printed:
3 US$12.99 4 US$19.99
Page 3 · Pricing
A pricing page a crawler can read
In our study, 38 of 197 pricing pages showed no price in the HTML without JavaScript, 29 of the 179 we could match against a sitemap were missing from it, 3 were marked noindex, and 61 of 197 described the price in structured data.
Put the price in the HTML, not only in JavaScript
- Do
Plan names, prices, currency and billing period should be in the HTML the server sends. A pricing table drawn by a script reaches a crawler that does not run JavaScript empty.
- Check
Set your pricing page’s address. The first command counts the words without JavaScript, the second prints the prices among them. A few dozen words and no prices means the page is drawn by JavaScript.
pricing="$site/pricing" curl -s "$pricing" | perl -0777 -pe 's/<(script|style)\b.*?<\/\1>//gis; s/<[^>]+>/ /g' | wc -w curl -s "$pricing" | perl -0777 -pe 's/<(script|style)\b.*?<\/\1>//gis; s/<[^>]+>/ /g' | grep -o -E '(US)?[$€£] ?[0-9][0-9,]*(\.[0-9]{2})?' | sort | uniq -c- On our sites
Outcrop has no /pricing page: /services/ lists every package with its price, and each package page shows its own. With
pricing="$site/services/", the commands printed:407 2 $1,490 1 $290 1 $490 2 $690 1 $790 1 $890 1 $990
List it in the sitemap, and do not noindex it
- Do
Put the pricing page in your sitemap, at the same address as its canonical tag. Check that no meta robots tag or X-Robots-Tag header marks it noindex.
- Check
The first command should print 1; use the address exactly as your sitemap writes it, trailing slash included. The other two should print nothing.
curl -s "$site/sitemap.xml" | grep -c "<loc>$pricing</loc>" curl -s "$pricing" | grep -i -o '<meta[^>]*robots[^>]*>' curl -s -I "$pricing" | grep -i '^x-robots-tag'- On our sites
Run on Outcrop’s /services/, the first command printed 1 and the other two printed nothing.
Describe the price in structured data
- Do
Add an Offer with a
priceand apriceCurrencyfor each plan to the page’s JSON-LD, attached to the product it sells. Keep the prices the same as the visible ones.- Check
The first command counts the Offer and Product blocks, the second prints the prices and currencies in them. Compare them with the prices on the page. Google’s Rich Results Test shows the same, with errors explained.
curl -s "$pricing" | grep -o -E '"@type": ?"(Offer|AggregateOffer|Product|OfferCatalog)"' | sort | uniq -c curl -s "$pricing" | grep -o -E '"(price|priceCurrency)": ?"?[^,}"]+"?' | sort | uniq -c- On our sites
Outcrop’s build writes the visible prices and the Offers from the same list of packages. Run on /services/, the commands printed:
6 "@type":"Offer" 1 "@type":"OfferCatalog" 1 "price":1490 1 "price":290 1 "price":490 1 "price":690 1 "price":790 1 "price":990 6 "priceCurrency":"USD"
Results
What we cannot tell you yet
Whether these pages bring buyers. Upright’s comparison pages are days old, and Search Console has no impressions for them yet. Their numbers go on the proof page at 2, 4 and 8 weeks after each change, bad weeks included.