GapFinder

Content gap analysis at the level of the claim, not the keyword. It compares what a site actually asserts against what its competitors assert, and shows the evidence for every gap it reports.

Live Clients only

What It Is

A gap analysis tool that works on propositions rather than keywords. It breaks a site and its competitors into individual claims, embeds them, and compares the two sets to find what the competitors assert that the site does not.

The proposition is the unit because an embedding is one point in space, and a point can only mean one thing. A two thousand word article covers eight ideas, and its vector is the blurry average of all eight, which is why every article in a category ends up looking like every other one. Measured on identical source content, section-level vectors separated the right answer from the wrong one by 0.007; proposition-level vectors separated them by 0.076.

Results are organised as runs, and every reported gap opens an evidence panel showing the source text behind it. A finding can be checked instead of trusted.

The Problem It Solves

Keyword gap analysis tells you a competitor ranks for something you do not. It does not tell you what they said. A page can target the same term and make an entirely different argument, and that argument is the actual gap.

Working at the proposition level means the output is a list of things worth saying that you are not saying, which is a content brief, rather than a list of terms, which is homework.

Where It Gets Used

Four situations account for almost every run I make of it.

  • Content strategy. Deciding what to write next from what the category already claims.
  • Page-level rewrites. Finding the missing argument on a page that already exists.
  • Competitive positioning. Seeing which claims everyone makes and which nobody has taken.
  • Audit support. Backing a content finding with the competitor sentence that motivated it.

How It Works

Seven steps. The run deliberately stops at step six and waits for you.

Step one

Gather The Corpus

URL discovery runs a ladder and stops at the first rung that yields enough: sitemaps declared in robots.txt, then common sitemap paths, then RSS and Atom feeds, then a breadth-first crawl from the homepage. The last rung is what makes it work on small marketing sites that have no sitemap at all.

Step two

Sample, Not Truncate

Filters run first, then the survivors are stratified by first path segment and sampled evenly within each. Taking the first fifty URLs of a sitemap samples one corner of a site: on a real 826-URL site, all fifty came from one section, and the analysis described that section rather than the site.

Step three

Segment And Extract

Each page splits at its H2s, and one model call per section turns it into one to four canonical questions plus an expansion of alternate phrasings. Brand names are stripped, because otherwise every vendor's self-description sits in its own corner of the space and nothing matches across sites.

Step four

Gate On Budget

The spend check happens at the one point where stopping is free: after the crawl, when the section count is real, and before a single billable call. A run over its cap parks with the numbers and three ways forward rather than spending most of the money and then failing.

Step five

Embed And Index

Propositions are embedded into a two-tier index that blends dense and sparse retrieval. Vectors and extractions are both content-addressed in the database, so re-running after a threshold change costs nothing and re-crawling only pays for text that changed.

Step six

Calibrate

You label around twenty sampled propositions covered or gap, and the threshold and the dense-sparse blend are derived from your labels rather than picked. Building this, the first vectorizer scored 62% against a 56% base rate. Twenty labels caught it in ten minutes; skipping the step would have shipped a confident, wrong report.

Step seven

Diff And Cluster

Unmatched propositions cluster into topics, counted per competitor and sorted by how many distinct rivals hold each one with nothing on your side. A topic every rival covers is table stakes; one a single rival covers may just be their niche. Same finding, different priority.

Two things that stop it lying to you: every proposition carries a facet, and cross-facet matches are penalised, because "is an IP address personal information under COPPA" otherwise scores higher than every true gap against a page answering the same question for CCPA. That moved accuracy from 81% to 88%. Separately, counting propositions per facet per side reaches the same headline using no vectors at all. When a finding survives both methods, trust it. When they disagree, trust neither until you know why.

Who It Is For

Clients on a content engagement. Registration is invite-only after the first account, and every account carries a monthly spend cap, because the extraction runs on my API keys.

  • Not a keyword tool. It never reports search volume, and it is not a substitute for one. It produces a candidate list, not a priority list.
  • Not automated publishing. It tells you what is missing, not what to write.

Status And Access

Live, and closed. It runs inside engagement work rather than as something you can sign up for.

Status and access

Status
Live
Address
gapanalysis.jakelabate.com. The subdomain predates the name; the app is GapFinder.
Sign-in
Clients only. Invite-only registration.
Cost
Included in engagement work.
Stored data
Runs, propositions and evidence records, plus the vector and extraction caches that make a re-run free.
Can you use it today
Only if we are working together.

The Stack

A process rather than a static site, which is what a crawl and a batch poller both require.

Stack

Front end
A single-page UI served by the app itself. Run progress arrives over server-sent events, so a crawl that takes minutes reports as it goes.
Backend
Python and FastAPI. Capture, segmentation, extraction, embedding, calibration, diff and clustering all run in-process, with a background poller that collects batch results across restarts.
Auth
Its own accounts: scrypt hashing with no dependency, invite codes after the first account, and a monthly spend cap per user.
Storage
SQLite in WAL mode on an attached volume, holding runs, pages, sections, propositions, labels, findings and both caches.
Hosting
Fly.io, deliberately one machine with one worker, served at gapanalysis.jakelabate.com. It scales up, never out.
Repository
Private.

Say The Thing Nobody Has Said

A gap list is a candidate list. Which of those claims are worth making, which page should carry each one, and what has to be true before any of it earns a link, is the work. That is what an engagement is for.