---
title: "Group pages into topic hubs · Agent Wranglers"
url: https://agentwranglers.se/playbook/seo/site-structure/topic-hubs
id: SEO-42
level: Recommended
updated: 2026-10-22
tokens: 850
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Group pages into topic hubs

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Site structure](https://agentwranglers.se/playbook/seo/site-structure.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: SEO-42
- Level: Recommended
- Chapter: [Site structure](https://agentwranglers.se/playbook/seo/site-structure.md)
- Rule: Give each problem group in the keyword map one hub page that links to every page in the group. Each of those pages links back to the hub.
- Check: A build test reads the keyword map. Every problem group has one hub address. The hub links to every page in the group, and every page in the group links back.
- How: A hub is the broad page, such as "Oak floor care", that a new site grows into once its long phrases rank. It introduces the topic in a few paragraphs and links each detailed page with a sentence on what it answers. The links tell readers and search engines which pages belong together and which one covers the whole topic. Add the hub to the site navigation or to the breadcrumb trail, as [Show where the page sits](https://agentwranglers.se/playbook/seo/site-structure/breadcrumbs.md) says. Choose its phrases as [Weigh difficulty against your site's strength](https://agentwranglers.se/playbook/seo/keyword-research/keyword-difficulty.md) says.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
for (const [group, rows] of Map.groupBy(keywordMap, row => row.group)) {
  const hub = hubs[group];
  for (const { path } of rows.filter(row => row.path !== hub)) {
    assert.ok(links.get(hub).has(path) && links.get(path).has(hub), `${path} and its hub ${hub} must link both ways`);
  }
}
```

### Python example

```python
from itertools import groupby

for group, rows in groupby(sorted(keyword_map, key=lambda r: r["group"]), key=lambda r: r["group"]):
    hub = hubs[group]
    for row in rows:
        if row["path"] != hub:
            assert row["path"] in links[hub] and hub in links[row["path"]], f"{row['path']} and {hub} must link both ways"
```

## Sources

- [Google Search Central – Link best practices](https://developers.google.com/search/docs/crawling-indexing/links-crawlable)

## Related rules

- SEO-27 [Weigh difficulty against your site's strength](https://agentwranglers.se/playbook/seo/keyword-research/keyword-difficulty.md) in SEO
- SEO-17 [Show where the page sits](https://agentwranglers.se/playbook/seo/site-structure/breadcrumbs.md) in SEO

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/seo/site-structure/topic-hubs">Agent Wranglers SEO playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Link every page from another](https://agentwranglers.se/playbook/seo/site-structure/internal-linking.md)
- Next: [Link related pages both ways](https://agentwranglers.se/playbook/seo/site-structure/two-way-related-links.md)
- [Site structure](https://agentwranglers.se/playbook/seo/site-structure.md)
