Lee Foot

Internal Search Mapper

Map site search queries to existing pages and discover content gaps from user behaviour.

Launch the app → View the source

#about

Matches GA internal search queries to page H1s using TF-IDF fuzzy matching via PolyFuzz.

Outputs exact matches (similarity 1.0) and partial matches ranked by relevance and search volume.

Filters non-indexable pages and deduplicates queries keeping highest-value instances.

Streamlit app

Platform
Browser-based (no installation required)
Input
GA internal search exportScreaming Frog crawl CSV
Output
CSVs with exact and partial search matches
Category
E-commerce

Use cases

  • Identifying products or content users search for but cannot find
  • Improving internal site search by adding redirects
  • Planning new landing pages based on user demand
  • Understanding user intent and terminology

#features

  • TF-IDF fuzzy matching via PolyFuzz library
  • Exact and partial match separation (similarity scores)
  • Automatic non-indexable page filtering
  • Deduplication keeping highest search volume instances
  • Results sorted by Total Unique Searches

#how-to-use

  1. Export GA internal search report as Excel
  2. Export Screaming Frog crawl with H1 and indexability columns
  3. Upload both files to the tool
  4. Run TF-IDF matching against indexable page H1s
  5. Download three CSVs: exact matches, partial matches, and combined results

#faq

What exact export formats does it expect?
Two files: the Google Analytics site search terms report as Excel (the script reads a sheet named Dataset1; the Streamlit app falls back to the first sheet if that name is missing), and a Screaming Frog crawl CSV. The script needs the columns H1-1, Address and Indexability from internal_html.csv; the app lets you map any search term, H1 and URL columns from dropdowns.
Does this work with GA4?
It was built around the Universal Analytics Behavior > Site Search > Search Terms export, and the script hardcodes UA column names like Search Term and Total Unique Searches. In the Streamlit app you can map any column as the search term, so a GA4 view_search_results export works if you shape it into a spreadsheet first, but the volume-based sorting only kicks in if a column name contains 'search' plus 'unique' or 'volume'.
What does it actually match against?
Page H1s only, not URLs or title tags. Search terms and H1s are lowercased and matched with PolyFuzz TF-IDF, and each search term gets exactly one best-matching H1. The readme recommends crawling just your category pages, otherwise terms will happily map to blog posts or product pages.
How are non-indexable pages excluded?
Rows where the Indexability column equals exactly 'Non-Indexable' are dropped before matching. If your crawl export lacks that column (the app skips the filter silently in that case) or uses different wording, non-indexable URLs will appear as match targets.
Why do some search terms disappear from the results?
Duplicates are removed keeping one row per search term, and results are deduplicated after sorting by search volume so the highest-volume instance survives. In the app there is also a minimum similarity slider (default 0.5), so terms whose best H1 match scores below the threshold are filtered out entirely; lower the slider to see them.

/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.