SEO for Solos
foreclosuredatahub.comSold

Foreclosure Data Hub

Foreclosure Data Hub is a foreclosure listings data product covering every US county, built and operated by one person on Next.js App Router. Roughly 2,100 of its URLs were indexable and about 2,000 of those were generated from a county data set, each carrying figures computed for that county rather than a template with the name swapped.

Role
Sole developer, operator and author
Stack
Next.js App Router, React, TypeScript, PostgreSQL
Timeline
Launched, grown to $1,500 MRR in five months, then sold
2,100
Indexable URLs
42
schema.org types
$1,500
Peak MRR
5
Months to that MRR
From launch
$28,000
Sold for
Escrow record below

The site is still live at foreclosuredatahub.com, so everything described below can be checked against the running implementation.

foreclosuredatahub.com: Escrow transaction, completed: asset sale of the Foreclosure Data Hub business and the foreclosuredatahub.com domain for $28,000 under an Asset Purchase Agreement dated July 2026
foreclosuredatahub.com · Escrow transaction, completed: asset sale of the Foreclosure Data Hub business and the foreclosuredatahub.com domain for $28,000 under an Asset Purchase Agreement dated July 2026. Full size
foreclosuredatahub.com: Google Search Console, web search, 16 months to late July 2026: 1.05K clicks and 61.8K impressions from Google organic search, average position 13.4
foreclosuredatahub.com · Google Search Console, web search, 16 months to late July 2026: 1.05K clicks and 61.8K impressions from Google organic search, average position 13.4. Full size

The page tiers

1,689
County pages
276
City pages
50
State pages

What was actually built

Each section names the checklist group it belongs to. All 112 checks are free to read, with a verification command for every one.

01Foundation

One module owned every SEO primitive

Every SEO primitive lived in a single module: the canonical origin, the URL normaliser, the Open Graph and Twitter builders, and the JSON-LD factories. No page ever hardcoded the domain.

This sounds like housekeeping and it is not. One typo in a domain constant silently splits canonical signals across two hostnames, and it is close to invisible in review. Centralising made that class of bug impossible rather than unlikely.

A permanent redirect at the edge forced every apex-domain request to the www host, so link equity never split between the two.

02Performance

Every page was server rendered and prerendered

Every public page rendered its HTML on the server, so crawlers never depended on client hydration to see content. All roughly 2,100 URLs were prerendered at build time.

Content that changed used incremental revalidation rather than client fetching, so live counts stayed fresh without giving up static HTML. Time to first byte stayed flat regardless of database latency.

03Programmatic pages

The county tier, and why it was the county tier

Foreclosures are noticed and auctioned county by county, so the county tier matched the unit the market actually searches in. That single choice mattered more than any on-page work that followed.

A state-only build would have produced 50 pages competing with every national aggregator. A ZIP-code build would have produced tens of thousands of pages with nothing unique on any of them.

Nothing became a public URL unless it resolved against an authoritative US county reference list. Scraped county values are polluted with malformed spellings, and without that gate the generator would have produced hundreds of near-duplicate pages for entities that do not exist.

04Programmatic pages

What made 1,689 generated pages survive

Each county page carried its own numbers: total listings, upcoming auctions, next scheduled sale date, share of state volume, and rank among tracked counties in that state.

It also carried a real preview table of listings from that county, with an explicit honest label when inventory was too thin and a statewide sample was shown instead. FAQ answers were computed from those same numbers and fed both the visible accordion and the structured data.

The test that governs this: strip the entity name from the page. If nothing unique remains, the tier should not be published. Templated answers with only the place name swapped are what triggers a doorway classification, and that classification is site-level and is not appealable by argument, only by deletion.

05Structured data

Structured data as one entity, not scattered markup

The sitewide graph was a single @graph array with stable @id anchors, so the organisation, site, business and software nodes cross-referenced each other instead of duplicating. The site node pointed at the organisation by id rather than restating it.

Honestly: breadcrumbs and FAQ markup changed what appeared in results. Dataset markup opened a channel most competitors ignore. The remaining types produced no visible rich result. They are not wasted, they contribute to entity understanding, but adding eleven schema types does not produce eleven rich results.

Two rules prevented rejections. Optional fields were omitted rather than filled with empty strings, and every number inside the structured data was computed from the same source as the visible text. Markup that disagrees with the page is a standard cause of rich-result rejection.

06AI and answer engines

Crawlers were sorted by whether they send traffic back

Search crawlers and citation engines were allowed: Googlebot, Bingbot, and the answer engines that produce cited, clickable links. Training-only crawlers that take the corpus and return no referral traffic were disallowed.

This is the highest-leverage robots decision available right now, and it is a decision rather than a default. Blocking everything labelled AI costs citations. Allowing everything donates the corpus for free.

robots.txt was generated from code rather than kept as a static file, so the disallow list could not drift from the routes.

07Crawling and indexing

A sitemap that carried a real freshness signal

The sitemap was generated from the same data modules the pages rendered from, so a new county page could not exist without a sitemap entry.

Last-modified dates were differentiated per content type rather than stamped with one build timestamp. A sitemap where every URL changed at the same second is a freshness signal crawlers learn to ignore. County entries used a constant stamped by the data regeneration job, so the date was genuinely true.

The same constant fed the visible data-as-of label on the page, so the page and the sitemap could never disagree.

08AI and answer engines

Answer engines were treated as a first-class surface

The site published a machine-readable brief with an entity definition, a key facts block, and explicit statements about what the company is not, plus an extended file carrying a canonical question and answer block and citation guidance naming which URL to cite.

Two techniques changed citation behaviour across a set of seed queries. First, answers were written as self-contained sentences that restate the subject, so an extracted sentence stands alone as a citable fact. Multi-paragraph answers to the same questions produced no citations where single self-contained sentences did.

Second, explicit entity boundaries. Stating that the company is not a government agency, not a county recorder and not a brokerage stopped models conflating it with adjacent entities, which in a government-adjacent niche was a recurring problem.

09Measurement

Freshness ran as a pipeline, not a habit

Scheduled jobs regenerated the county data snapshots weekly and committed the diff, submitted the URL set to participating engines, and refreshed the underlying listing data daily.

Generated snapshots were committed to the repository, so builds were deterministic and a bad data pull showed up as a reviewable diff rather than a silent change on the live site.

What this build got wrong

Published on purpose. A case study that lists only wins is an advertisement, and these are the traps that recur on every site.

  • No Content-Security-Policy header, despite an otherwise complete header set.
  • No custom 404 page, so traffic from dead links hit the framework default with no recovery links.
  • The Organization node listed no third-party profiles, which forfeits an entity-confirmation signal.
  • Last-modified dates for hand-written pages were hardcoded in the sitemap and drifted.
  • One flat sitemap for 2,100 URLs. Within limits, but a sitemap index split by content type would have given per-tier indexation reporting, which is the diagnostic you want at that scale.
  • No image sitemap, and limited use of the optimised image component outside the marketing pages.

The checklist behind this build is free

Everything above is described in the 112-check playbook, all of which is free to read. The agent skill is the version your coding agent runs: it audits your site against the same checks, reports what is missing, and implements the gaps one at a time.

Product analytics are optional. On the skill page, X advertising measurement is also optional and shares your visit and ad identifiers with X. Both are off until you allow them. Privacy policy.