On-Page SEO

On-Page SEO Services Built on Keyword Mapping and Template Patches

On-page SEO is a mapping problem before it is a writing problem. seothumb.com assigns every commercial query to one URL, resolves the conflicts that already exist on your site, and ships title, heading, schema and internal link changes as template patches your developers can review and revert.

  • 12 pages in 5 business days

    Free technical audit

  • $2,400/mo flat

    Retainers from

  • One senior consultant

    Who does the work

Overhead view of a technical SEO audit workspace with a magnifying glass, notebook and laptop

Keyword mapping: one query gets exactly one URL

On-page SEO starts with a decision that has nothing to do with writing — which single URL is allowed to compete for each query.

We export the full query set from Google Search Console and Ahrefs, classify it by intent (informational, commercial investigation, transactional, navigational) and assign each cluster to one owner URL. The map is a working document with a row per query and columns for volume, intent, assigned URL, the URL currently ranking, and a conflict flag where those last two disagree.

One query, one URL, for a mechanical reason. When two of your pages both qualify for a search, Google decides between them, and that decision can change between crawls. The symptoms are a ranking that moves while your content sits still, impressions split across two URLs, and internal links pointing at whichever page the author happened to remember. Choosing the owner yourself removes the ambiguity before a single tag is touched.

Mapping also draws the boundary for content work. A query with no plausible owner is a gap and goes to SEO content strategy as a brief. A query with two plausible owners is a cannibalization conflict, resolved below. Nothing new gets commissioned while the existing map is dirty, because publishing into an unresolved conflict simply adds a third competitor for the same search.

Everything downstream points back at this document: a URL's title, its H1, its schema and the anchor text of every internal link aimed at it all come from the terms that URL owns.

How cannibalization is detected and resolved

Detection is a query-level exercise, not a page-level one. We pull Search Console performance data through the API into BigQuery so the query-by-page dimension survives export limits, then flag four patterns:

  • any query where two or more URLs take meaningful impressions
  • any query where the top-ranking URL flips from one week to the next
  • clusters of near-duplicate title tags and H1s in the Screaming Frog crawl
  • pages holding a stable position with click-through well below what that position band supports

Every flagged conflict gets one of four resolutions, decided on evidence rather than preference.

Merge. Two pages saying the same thing to the same audience. The stronger URL keeps the slot, genuinely unique passages are ported across, the weaker URL is 301'd, and every internal link that pointed at the old URL is rewritten to the survivor instead of being left to lean on the redirect.

Canonicalize. Both pages have to exist for people — a parameterized variant, a syndicated copy, a print view — so one is declared canonical and the other carries the reference. The content stays live; the index signal stops splitting.

Differentiate. The two pages should serve different intents and currently do not. Titles, H1s, opening sections and inbound anchors are rewritten so one owns the informational query and the other owns the commercial one.

Prune. No referring domains, no conversions, no unique value. Redirect it where it has earned links, remove it where it has not.

Meta title optimization at template level, not page by page

A product or category title tag is rarely written; it is generated. In Shopify it comes from the theme's title block or an SEO app field assembled from Liquid variables. In WordPress with Yoast or Rank Math it comes from the title template set per post type under Search Appearance, using variables like %%title%% and %%sep%%, with a per-post override that wins whenever it is filled in. In a headless build the string is assembled in the layout from CMS fields.

That is where the work belongs. Rewriting sixty product titles by hand is sixty edits, sixty chances to paste the wrong variant, no version history a developer can read, no way to reverse the change except sixty more edits — and nothing at all applied to the sixty-first product added next week. Patching the template that generates them is one change, reviewable as a diff, reversible in one deploy, and inherited by every URL created afterwards.

We write the specification as the variable string your CMS actually accepts, then set the rules:

  • primary mapped term near the front, where it still reads like a sentence
  • one qualifier, not three, and no term repeated twice in the same tag
  • length judged in pixels rather than characters, because truncation is width-based
  • brand suffix only where the brand is itself a reason to click

Hand-written overrides are reserved for the URLs that earn the attention. Templates carry the long tail, which is most of the site. Google's SEO starter guide sets the baseline; the keyword map sets the wording.

Heading architecture that describes the page instead of styling it

One H1 per URL, carrying the mapped primary term in the form a person would actually say it. H2s cover the subtopics the search results already prove belong to that query: the People Also Ask set, the sections shared by the pages currently ranking, the qualifiers sitting in the long tail of the same cluster. H3s exist only where content genuinely nests under an H2.

Most heading problems on a live site are not editorial, they are theme-level. Card titles in a grid, sidebar widget labels, footer column headers and promo blocks are routinely marked up as H2 or H3 because that was the size the designer wanted. A category page shipping thirty product cards can carry thirty H2s that say nothing about the page's topic, with the real subheadings buried among them. The fix is a template change rather than an editing pass: heading classes for visual size, heading tags for structure.

We also check that the opening paragraph answers the query the URL owns instead of warming up to it, that the mapped term and its close variants appear where they read naturally, and that empty or duplicated heading tags left behind by page builders are removed. The standard the copy is held to is Google's guidance on people-first content, not a density target.

Internal linking strategy: modules placed programmatically

Internal links arrive in three layers, and each is built differently.

Navigational links — header, footer, breadcrumbs — are template-level and set reachability. Money pages should sit within three clicks of the homepage, and breadcrumbs earn their place twice, as navigation and as a search result feature.

Contextual links stay hand-placed. A link inside a relevant paragraph carries more weight than a row in a widget, so every content brief names its required internal link targets and the anchor to use.

Modular links are the scale play. A related-content block ordered by publish date is a recency widget, not an internal linking strategy. To make it work, cluster membership has to exist as a real field in the CMS — a taxonomy term, a reference field, an entry tag — populated from the keyword map. The module then queries that field. The rules we set:

  • a cap on links per module, so equity is not spread across forty rows
  • exclude the current URL, plus anything noindexed or canonicalized elsewhere
  • order by the priority score in the map, never randomly or by date
  • anchors drawn from the target's mapped terms and varied across placements
  • every link checked against the redirect map, so no module points into a 301 chain or a 404

An orphan check closes the loop: crawl the site in Screaming Frog, diff it against the XML sitemap, and confirm every mapped URL clears a floor number of internal links. Faceted and paginated templates get their own link rules under ecommerce SEO.

Entity coverage and structured data per template

Relevance is not scored on the head term alone. A page about return windows for footwear is recognized partly through the things that topic contains — sizing, exchange periods, carriers, the brands involved. We build an entity list per mapped URL from the vocabulary already present in the pages ranking for that cluster and from your own product and category data, then check coverage before the page is called finished. Nothing is counted toward a density target; the list is a completeness check, not a quota.

Structured data is generated per template from the same CMS fields that render the visible page. That is the only arrangement in which markup cannot drift when someone edits a price, a question or an address. Standard coverage:

  • Organization and WebSite from the site layout, on every page
  • Service on service pages, Product with offers on product pages, Article with a real author on editorial
  • BreadcrumbList matching the visible trail exactly
  • FAQPage only where the questions are actually rendered on the page

Each template goes through the Rich Results Test before deploy, and Search Console enhancement reports are watched for a fortnight afterwards, because a parse error introduced at template level appears across thousands of URLs and only surfaces once Google recrawls. Google's structured data documentation defines which types are eligible for rich results; types outside that list are added for entity clarity rather than for a result feature.

QA after deploy, and what a regression actually looks like

Before a patch merges, we crawl staging and production, export URL, title, meta description, H1, canonical and meta robots for both, and diff them. The delta list is reviewed line by line. A template change touching four thousand URLs deserves more than a spot check on three of them.

Within 24 hours of deploy:

  • recrawl production and confirm the delta matches the approved list and nothing else moved
  • inspect rendered HTML rather than view-source, wherever tags are injected client side
  • confirm canonicals, hreflang and robots directives are untouched unless they were the point of the patch
  • resubmit affected sitemaps and spot-check URLs in Search Console's inspection tool

Then a page-level watch runs for four weeks. Regressions have recognizable shapes:

  • a template applied to a page type it was never scoped for: paginated URLs inheriting page one's title, filter URLs inheriting the parent category's
  • a noindex or an off-page canonical escaping into an entire template, which is the most expensive on-page mistake available
  • position holding while click-through falls after a title change, meaning the new tag is weaker or Google is rewriting it
  • impressions dropping on both URLs after a differentiation pass, meaning the intents were never actually separated
  • modules linking into redirect chains after a URL change

Rollback is a revert of one commit. That is the second reason this work belongs in templates, and it is judged against the crawl baseline captured in your technical SEO audit.

FAQ

Questions about on-page seo

  • Will rewriting our title tags put rankings we already have at risk?

    It can, which is why titles change against a baseline and never all at once. The pre-deploy crawl diff records the existing tag for every URL, priority pages are patched in batches, and click-through is watched at page level for four weeks. If a batch loses clicks at a stable position, the template reverts in one deploy and the next batch waits.

  • Our CMS is locked down. How does that work?

    That is the normal case, and it is the reason the deliverable is a template patch rather than a task list. Specifications are written as the exact string or component change your stack accepts, with the crawl diff attached so your reviewer can see which URLs change and how. Where we are given repository access, the patch is raised as a pull request instead.

  • Do you rewrite body content, or only tags and internal links?

    On-page work covers opening sections, heading structure, entity coverage and the copy on an existing URL where the mapped intent is not being answered. Full article production, cluster planning and refresh cycles sit in SEO content strategy. The dividing line: fixing what a live URL says is on-page, commissioning a URL that does not exist yet is content.

  • How do you decide which URL survives when two pages compete?

    Referring domains first, because links are the hardest signal to rebuild. Then existing impressions and conversions for the contested query, then URL depth and whether the slug still matches the term. The weaker page's unique passages move across to the survivor before the redirect goes live, so nothing useful is discarded in the merge.

Next step

Find out which of your pages are competing with each other

A free technical SEO audit from seothumb.com runs to 12 pages and lands inside five business days, with no call required first. It includes the duplicate-title, duplicate-H1 and near-identical heading clusters that point straight at cannibalization, so you can see the conflicts before deciding whether the on-page work is worth paying for. Retainers are flat monthly and scoped in advance, starting at $2,400 — the tiers are set out on the [pricing page](/pricing), and [contact](/contact) is where the audit starts.

Get my free technical SEO audit

Five business day turnaround. No call required to receive it.