Lee Foot

Keyword-to-Page Mapper

Semantically match keywords to existing pages using ML embeddings.

Launch the app → View the source

#about

PolyFuzz with Sentence Transformers for semantic similarity (not exact keyword matching).

Three embedding models: all-MiniLM-L6-v2 (fastest), multi-qa-mpnet-base-dot-v1, all-mpnet-base-v2 (most accurate).

Similarity threshold 0.5-0.95 (default 0.75).

Exact match exclusion toggle.

xlsxwriter multi-sheet Excel.

Streamlit app

Platform
Browser-based (no installation required)
Input
Pages CSV: URL/Address + H1/Title columnKeywords CSV: Keyword + optional Volume (Ahrefs/SEMrush format)
Output
Mapped CSV: keyword, H1, similarity, URL, volume, opportunity count. Gaps CSV: unmapped keywords. Excel: multi-sheet combining both.
Category
Content

Use cases

  • Finding content opportunities from competitor keywords
  • Mapping keywords to existing content
  • Identifying content gaps
  • Content strategy planning

#features

  • PolyFuzz + Sentence Transformers semantic matching
  • 3 embedding models: MiniLM, mpnet-base-dot, mpnet-base-v2
  • Similarity threshold slider (0.5-0.95, default 0.75)
  • Exact match exclusion toggle
  • Content gap detection for unmapped keywords
  • Multi-sheet xlsxwriter Excel export

#how-to-use

  1. Upload crawl export with H1s/titles
  2. Upload competitor keywords
  3. Select embedding model
  4. Set similarity threshold (0.5-0.95)
  5. Toggle exact match exclusion
  6. Download mapped keywords and content gaps

#faq

Can a keyword be mapped to more than one page?
No. PolyFuzz returns the single best match per keyword, so each keyword is assigned at most one page (the H1 with the highest similarity). Pages can receive many keywords, and that is what the Opportunity Size column counts.
Why does a keyword appear in Content Gaps when I clearly have a page for it?
Two reasons visible in the code. Anything below the similarity threshold is treated as unmapped. Less obviously, the Exclude exact matches toggle drops keywords whose text already appears inside the matched H1, and those dropped keywords are then counted as unmapped, so they land in the Content Gaps sheet despite having a perfect page. Untick the toggle if that distinction matters to you.
What does it actually match against, the whole page?
Only the single H1 or title column you select, lowercased. Page body content is never embedded, so pages with vague or branded H1s will under-match regardless of the threshold you set.
Does it need an API key or cost anything to run?
No. Embeddings are computed locally with sentence-transformers, so there is no per-keyword cost. The first run is slow because the selected model has to download; after that it is cached.
Do my CSVs need specific column names?
No fixed names, but auto-detection looks for a column called Address for URLs, columns containing 'h1' or 'title' for page content, 'keyword' or 'query' for keywords, and 'vol' for volume. If nothing matches, the first column is silently preselected, so always check the dropdowns before running. Both files must be CSV, not Excel.

/contact

Want me to run this for you? I run this tool as a managed service, or build something custom around your data. You get the insights without touching the code.