StoryVoice
Methodology · v1

How we built the Customer Proof Index

Every heuristic, every excluded source, and every known gap behind the Customer Proof Index 2026.

StoryVoice Research||Version 1

StoryVoice sells case-study software. We built this dataset ourselves, for this report, with a crawler written for the purpose. It is a directional measurement of what 1,000 B2B software companies publish, not an audit of any single company and not a peer-reviewed study. Read this page before citing any figure from the report, and treat every number as carrying the limitations described below.

How we built the sample

We started from SaaSHub, a B2B software directory organized into “best of” category listing pages, and pulled 55 fixed B2B categories spanning sales, marketing, support, HR, finance, IT/dev/security, and vertical operations software.

For each category, we took up to 30 organic products in page order, following pagination when the default page did not surface 30 on its own, and stopped once a page contributed zero products not already seen. We excluded sponsored or promoted slots, identified by a “SPONSORED” ribbon and a rel="sponsored" attribute on the listing card. Results were deduplicated by registrable domain, and non-company sites (Wikipedia, GitHub, app stores, other directories) were dropped.

This produced 1,000 domains. 46 had an unreachable homepage at crawl time (mostly HTTP 403 or 404, a handful of timeouts or client errors) and are excluded from every percentage in the report, leaving n = 954.

How we crawled each company

For each domain, we fetched the homepage and read its navigation and footer links, plus a set of common proof-page slugs (paths like /case-studies, /customer-stories, /success-stories, and similar), then crawled up to 45 same-domain pages looking for proof content. Each page was classified as written proof, video proof (YouTube, Vimeo, Wistia, Loom, or a non-decorative embedded video or testimonial widget), or neither.

A company landed in written if at least one page read as a real case study or customer story, not a wall of one-line blurbs. It landed in video-only if we found video proof but no written story. It landed in none if we found neither.

How we sampled individual stories

For every company classified as having written proof, we sampled up to 5 individual story pages. Where the only thing we found was an index or listing page (a proof page one path segment deep, such as /case-studies itself), we fetched that index and extracted individual story links using a URL and anchor-text heuristic matching patterns like “case stud,” “customer stor,” “success stor,” “story,” or “spotlight.”

Of the 582 companies classified as having written proof, 239 had no individually-sampleable story page (only an index we could not resolve into stories), and a further 8 had every individual story fetch fail (blocked, timed out, or errored). That leaves 335 companies where at least one real story loaded successfully, which is the denominator for every per-story statistic in the report: no-number rate, named-customer rate, quote rate, word count, and freshness.

The four per-story checks, in plain English

1. Quantified result

We looked for a number attached to a unit: a percentage, a currency symbol, a multiplier (“3x”), or a time unit (hours, days, weeks, months) counts as high confidence. A “from N to M” pattern within about 100 characters of a trigger verb (increase, reduce, save, faster, grew, cut, boost, improve) counts as medium confidence. Across all 1,348 sampled stories, 982 hits were high confidence and 3 were medium; every “has a number” figure in the report counts both.

2. Named customer, strict and loose

We measured this two ways because the obvious heuristic (a capitalized name in the headline) is weak on its own. Loose is that original heuristic: a capitalized leading phrase in the H1 or title after stripping generic lead words (“How Acme Corp Cut Onboarding Time” strips to “Acme Corp”). Strict requires an explicit signal: a “Customer:”/“Company:”/“Client:” label, an “About [Name]” lead-in, a JSON-LD Organization name that is not the vendor's own brand, a customer-logo image whose alt text or class names a company that is not the vendor's own brand, or the loose candidate name recurring 3 or more times in the body as corroboration. Every “names the customer” figure in the report uses strict. Of 870 strict hits: 362 came from 3-plus repetition, 257 from a logo alt attribute, 128 from a JSON-LD organization record, 113 from an “About” lead-in, and 10 from an explicit label.

3. Direct quote

A double-quoted span of 8 or more words counts as high confidence. The bare word “said” or “says” appearing anywhere on the page counts as low confidence. The report's 83.6% “has a direct quote” figure counts both tiers.

4. Publish date

We checked, in priority order: structured machine-readable sources first (JSON-LD datePublished/dateModified, article meta tags, a <time datetime> element), then the HTTP Last-Modified header and an explicitly labeled visible date (“Published,” “Updated,” “Posted”), then an unlabeled visible date, a /YYYY/MM/ URL segment, and finally, as a last resort, the domain's sitemap.xml lastmod for that exact URL.

Two of these sources are weak in a specific way that matters for a freshness claim: header:last-modified and sitemap:lastmod are server/build metadata, not evidence read out of the page's own content, and they skew implausibly fresh (28% of dates from all sources combined land inside the last week, which is far more consistent with a redeploy than a genuine rewrite). Every freshness claim in this report (the median age, the “within 12 months” share) uses only three sources we consider genuine: JSON-LD datePublished, the article:published_time meta tag, and a <time datetime> element. The full breakdown, at the story level (1,156 total dated stories, some stories carrying more than one date source):

Date sourceStory-level hitsUsed in this report's freshness claims
json-ld:datePublished236Genuine (used for freshness)
meta:article:published_time187Genuine (used for freshness)
time[datetime]13Genuine (used for freshness)
header:last-modified292Excluded: server/CDN redeploy timestamp
sitemap:lastmod197Excluded: build or crawl timestamp
meta:article:modified_time186Excluded: last edit, not original publish
json-ld:dateModified24Excluded: last edit, not original publish
visible-text-regex15Excluded: unlabeled visible-text date, low confidence
visible-text:day-first5Excluded: unlabeled visible-text date, low confidence
visible-text:labeled-month-first1Excluded: labeled visible-text date, medium confidence

The report's freshness figures use a company-level view built from the three genuine sources only: for each of the 335 story-bearing companies, we take the newest genuine date across its sampled stories. 120 companies have at least one; the other 215 have no genuine date on any sampled story, which we report as “unknown,” not as stale.

Politeness and rate limits

We identified every request with a single user-agent string naming this research, waited at least 1.5 seconds between requests to the same host, sampled at most 5 story pages per domain (sitemap lookups included), and hard-capped at 25 requests to any one domain.

Category groups

For the by-category breakdown in the report, we rolled the 55 SaaSHub categories up into 7 broader groups so no single group has too few companies to read. The full mapping:

GroupCategoriesSaaSHub categories included
Sales & CRM4crm, cpq, sales-enablement, appointment-scheduling
Marketing10marketing-automation, email-marketing, social-media-management, seo, ab-testing, form-builder, survey, web-analytics, product-analytics, customer-feedback
Customer support & success6help-desk, live-chat, knowledge-base, user-onboarding, customer-success, customer-support
HR & people7hr, recruiting, payroll, performance-management, employee-engagement, lms, applicant-tracking
Finance & admin13accounting, subscription-billing, expense-management, procurement, contract-management, e-signature, document-management, erp, inventory-management, invoicing, tax, compliance, time-tracking
IT, dev & security11ci-cd, error-monitoring, log-management, data-integration, business-intelligence, password-manager, endpoint-security, backup, identity-management, video-conferencing, project-management
Operations & vertical4field-service-management, fleet-management, property-management, legal-practice-management

What we excluded, and why

46 of the original 1,000 domains had an unreachable homepage at crawl time and are excluded from every figure in the report. The first 8, for illustration: agilecrm.com (403), apkpure.com (403), appointy.com (403), axonsoftware.com (403), beyondtrust.com (403), billsby.com (404), breezy.hr (404), chattyui.com (client error). Most failures are anti-bot blocks (403) or dead listings (404), not sites we chose to skip.

Known limitations

  1. JS-rendered proof pages are invisible to this crawler. We fetch raw HTML only. A proof page that renders its content client-side, common on React or Vue marketing sites backed by a headless CMS, looks empty or absent to us even when a human visitor would see real stories. This biases the “no written proof” bucket upward by an amount we cannot measure.
  2. Date detection is incomplete by construction, not just imperfect. Many case-study templates never print a machine-readable or visible date at all, and some sites have no sitemap or omit the page from it. The freshness figures are computed only among companies where a genuine date was found; companies with no detectable date are excluded from the median and reported separately, not folded into “not recent.”
  3. The named-customer and quantified-result checks are regex and DOM pattern-matching, not NLP or human review. They will miss results and names phrased unusually and can be fooled by an unrelated capitalized phrase or logo. This is why we report both a strict and a loose named-customer number: strict is the one to trust, loose shows how much of a naive single-heuristic number would have been riding on a weak signal.
  4. SaaSHub's rankings are not a neutral sample of “B2B software.” It is whatever that one directory has indexed and how it sorts within a category, skewed toward products that maintain a SaaSHub listing at all. Widening from an earlier 25-category pilot to 55 categories reduces but does not eliminate this. This report never claims to describe B2B software companies that do not appear on SaaSHub.

How the sample changed when we widened it

This run followed an earlier 25-category, 234-domain pilot. We widened the category list to 55 and raised the per-category pagination target from 20 to 30, which grew the sample from 234 to 1,000 domains (954 usable after crawl errors, versus 223 before). Every heuristic described above applies identically to the original and the new domains, so the widening changed the composition of the sample and, separately, some heuristics (particularly date detection) were expanded in the same pass. We keep the original, narrower run's output as an internal reference so either variable can be isolated on request; the figures published in the report are all from the widened, current run.

Reproducing or updating this data

This is a one-time crawl dated 2026-08-21, not a live feed. We built it with a custom crawler (homepage plus navigation/footer discovery, up to 45 pages per site, up to 5 sampled stories per company) applied to a fixed list of 1,000 domains sourced from SaaSHub on the same date. If we re-run this in the future, the new figures will publish as a dated new version of this report; we will not silently overwrite the numbers above.

Version history

v1, 2026-08-21. First publication. Sample: 1,000 domains across 55 SaaSHub categories, 954 usable after excluding 46 crawl errors, 335 with at least one readable story, 1,348 stories sampled.