Skip to content
No-Code TemplateGoogle SheetsFree

Google Sheets Formulas for SEO Keyword Research and Content Analysis (Copyable, Tested)

ForKeyword researchSearch intent

By Lazarina Stoy· Updated 24 Oct 2026

Not every keyword project needs Python. A lot of the labelling I do on a keyword export can happen right in Google Sheets with a few well-built formulas, and that’s where most marketers already work. This free set collects my most-used formulas for keyword research and content analysis, refreshed for 2026 and checked by an automated test script.

What’s included

  • Search intent labels: informational, commercial, transactional, navigational and local (US states, UK cities, or a cities list kept in another tab), as single labels or every matching label.
  • SERP features as intent signals, and which content types Google is featuring, from the SERP features column in a Semrush or Ahrefs export (AI Overview included).
  • Branded splits: own brand, competitor brand and non-branded.
  • URL formulas: site section from the URL (or from a rules tab with XLOOKUP), language folder, and the brand from a URL, which handles subdomains and suffixes such as co.uk.
  • Rank buckets that handle decimal Search Console positions.
  • Rules tabs for intent and site sections, plus seven sample keywords to try everything on.

Who it’s for

Spreadsheet-first SEOs and content marketers who want consistent labels on a keyword list without opening Colab.

How to use it

  1. Open FORMULAS.md on GitHub. Each formula lists the cells it expects: C2 for the keyword, J2 for SERP features, A2 for the URL or position.
  2. Import rules_intent.csv and rules_sections.csv into new tabs named Rules and Sections if you want the table-driven versions.
  3. Paste a formula into the first row of an empty column, or use the BYROW or MAP versions to fill the whole column from one cell.
  4. Swap in your own brand and competitor names, and add words that matter in your niche.
  5. Save the ones you reuse as Named functions (Data > Named functions) so your team can type something like =INTENT(C2).

What changed from the 2024 versions

The old intent lists were case-sensitive and matched parts of words (“show” matched “how”, “laptop” matched “top”). The new ones use (?i)\b...\b regex for whole words in any case. Rank buckets no longer let a position of 3.4 fall through the gaps, and empty labels no longer leave stray commas.

Limits

  • Rule-based labels are a quick first pass. Words like “cost” or “deal” sit in more than one intent list on purpose.
  • The language formula reads any two-letter folder as a language, so exclude folders such as /us/ or /ai/.
  • Free, and no add-ons needed.

For labels that go beyond rules, read Search-Intent Classification with Machine Learning, and when you’re ready to try ML, start with the Introduction to Machine Learning for SEO course.

What’s included

  • Copy-and-paste formulas for informational, commercial, transactional, local and navigational intent
  • SERP features as intent signals, branded vs competitor vs non-branded, site sections from URLs, language folders, rank buckets
  • Rules tabs (intent and site sections) so you edit a table instead of a 900-character regex
  • Modern functions: LET, IFS, TEXTJOIN, XLOOKUP, BYROW, MAP and LAMBDA to fill a whole column from one cell
  • The regex and bucket logic is covered by 107 automated checks
. Disclosure menus (APG pattern), hover intent, mobile dialog with focus trap, announcement dismiss, skip-link target, newsletter status message. No dependencies. */ (function () { 'use strict'; var d = document;/* ---------- skip link target: #main, else the page's
, else the first block after the header */ (function () { var mains = d.querySelectorAll('main'); if (mains.length > 1) { // Our post-content
plus another one: drop the landmark from ours. var ours = d.querySelector('main[data-mlfc-main]'); if (ours) { ours.setAttribute('role', 'none'); ours.removeAttribute('id'); } } var skip = d.querySelector('.mlfc-skip'); if (!skip) return; var t = d.getElementById('main'); if (!t || (t.getAttribute('role') === 'none')) { t = d.querySelector('main:not([role="none"]), [role="main"]'); if (!t) { var hd = skip.closest('.wp-block-template-part') || skip.closest('.mlfc-hdw'); t = hd && hd.nextElementSibling; } if (!t) return; if (!t.id) t.id = 'main'; skip.setAttribute('href', '#' + t.id); } if (!t.hasAttribute('tabindex')) t.setAttribute('tabindex', '-1'); skip.addEventListener('click', function () { setTimeout(function () { t.focus({ preventScroll: false }); }, 0); }); })();/* ---------- announcement dismiss */ d.querySelectorAll('[data-mlfc-ann]').forEach(function (bar) { var btn = bar.querySelector('[data-mlfc-ann-close]'); if (!btn) return; btn.addEventListener('click', function () { try { localStorage.setItem(bar.getAttribute('data-mlfc-ann'), '1'); } catch (e) {} var next = d.querySelector('.mlfc-logo'); bar.hidden = true; if (next) next.focus(); }); });/* ---------- disclosure dropdowns */ var items = [].slice.call(d.querySelectorAll('.mlfc-hdw [data-mlfc-dd]')); var fine = window.matchMedia && window.matchMedia('(hover: hover) and (pointer: fine)').matches; function btnOf(it) { return it.querySelector('button[aria-controls]'); } function panelOf(it) { return d.getElementById(btnOf(it).getAttribute('aria-controls')); } function isOpen(it) { return btnOf(it).getAttribute('aria-expanded') === 'true'; } function setOpen(it, open) { var b = btnOf(it), p = panelOf(it); if (!b || !p) return; b.setAttribute('aria-expanded', open ? 'true' : 'false'); p.hidden = !open; if (open) { // keep the panel inside the viewport p.style.left = ''; p.style.right = ''; var r = p.getBoundingClientRect(); if (r.right > window.innerWidth - 12) { p.style.left = 'auto'; p.style.right = '0'; } } } function closeAll(except) { items.forEach(function (it) { if (it !== except && isOpen(it)) setOpen(it, false); }); }items.forEach(function (it) { var b = btnOf(it), tIn, tOut; if (!b) return; b.addEventListener('click', function () { clearTimeout(tIn); clearTimeout(tOut); var open = !isOpen(it); closeAll(it); setOpen(it, open); }); if (fine) { // Hover intent: open after 300 ms, close 400 ms after the pointer leaves trigger + panel. it.addEventListener('mouseenter', function () { clearTimeout(tOut); tIn = setTimeout(function () { closeAll(it); setOpen(it, true); }, 300); }); it.addEventListener('mouseleave', function () { clearTimeout(tIn); tOut = setTimeout(function () { setOpen(it, false); }, 400); }); } it.addEventListener('focusout', function (e) { if (e.relatedTarget && !it.contains(e.relatedTarget)) setOpen(it, false); }); it.addEventListener('keydown', function (e) { if (e.key === 'Escape' && isOpen(it)) { e.stopPropagation(); setOpen(it, false); b.focus(); } }); }); d.addEventListener('click', function (e) { items.forEach(function (it) { if (isOpen(it) && !it.contains(e.target)) setOpen(it, false); }); }); d.addEventListener('keydown', function (e) { if (e.key !== 'Escape') return; items.forEach(function (it) { if (isOpen(it)) { setOpen(it, false); btnOf(it).focus(); } }); });/* ---------- mobile menu dialog */ var menuBtn = d.querySelector('.mlfc-menu-btn'); var dlg = d.getElementById('mlfc-mnav'); if (menuBtn && dlg) { var FOC = 'a[href],button:not([disabled]),input,select,textarea,[tabindex]:not([tabindex="-1"])'; var openMenu = function () { dlg.hidden = false; menuBtn.setAttribute('aria-expanded', 'true'); d.body.classList.add('mlfc-lock'); var c = dlg.querySelector('[data-mlfc-close]'); if (c) c.focus(); }; var closeMenu = function (restore) { if (dlg.hidden) return; dlg.hidden = true; menuBtn.setAttribute('aria-expanded', 'false'); d.body.classList.remove('mlfc-lock'); if (restore !== false) menuBtn.focus(); }; menuBtn.addEventListener('click', function () { dlg.hidden ? openMenu() : closeMenu(); }); dlg.querySelector('[data-mlfc-close]').addEventListener('click', function () { closeMenu(); }); dlg.addEventListener('keydown', function (e) { if (e.key === 'Escape') { e.preventDefault(); closeMenu(); return; } if (e.key !== 'Tab') return; var f = [].filter.call(dlg.querySelectorAll(FOC), function (el) { return el.offsetParent !== null || el === d.activeElement; }); if (!f.length) return; var first = f[0], last = f[f.length - 1]; if (e.shiftKey && d.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && d.activeElement === last) { e.preventDefault(); first.focus(); } }); // In-page links (e.g. #courses) close the menu first. dlg.addEventListener('click', function (e) { var a = e.target.closest && e.target.closest('a[href^="#"]'); if (a) closeMenu(false); }); var mq = window.matchMedia('(min-width: 1024px)'); var onMq = function () { if (mq.matches) closeMenu(false); }; if (mq.addEventListener) mq.addEventListener('change', onMq); else if (mq.addListener) mq.addListener(onMq); }/* ---------- newsletter: plain POST to Kit in a new tab (same pattern as mlfa2_newsletter()); say so in the live region */ d.querySelectorAll('form[data-mlfc-nl]').forEach(function (form) { var msg = form.querySelector('.mlfc-nl__msg'); form.addEventListener('submit', function () { if (msg) msg.textContent = 'Thanks. Kit opens in a new tab: confirm your subscription there and check your inbox.'; }); }); })();