til/seo/README
README.mdupdated 2026-06-272893 words

SEO admin panel

The directory for centrally managing the SEO / KW / topic-cluster strategy of niki-nakamura.github.io/til/. It is excluded from the Jekyll build via _config.yml, so it does not appear on the public site.

Structure

seo/
├── README.md         this file
├── KEYWORDS.md       KW management (target / current rank / SV / status)
├── CLUSTERS.md       topic-cluster strategy (the pillar ↔ cluster relationship map)
├── METRICS.md        time-series metrics fetched from GSC / GA
├── config.json       settings such as site URL / property ID / GA property (gitignored)
├── config.example.json   settings template
├── package.json      Node dependency (googleapis)
├── scripts/
│   ├── fetch-gsc.mjs       GSC API → data/gsc-*.json
│   ├── fetch-ga.mjs        GA4 Data API → data/ga-*.json
│   ├── update-rankings.mjs writes KEYWORDS.md back from data
│   └── weekly-report.mjs   updates METRICS.md weekly
├── data/             API fetch results (gitignored)
└── credentials/      service-account.json etc. (gitignored)

Initial setup

1. Install dependencies

cd seo
npm install

2. Preparation on the Google Cloud side

  1. Create a GCP project (an existing HT project is fine)
  2. Enable the Search Console API and the Google Analytics Data API
  3. Create a service account → save the JSON key to seo/credentials/service-account.json
  4. GSC: settings for the target property at search.google.com/search-console → Users and permissions → add the service account's email as "Restricted"
  5. GA4: Admin → Property Access Management → add the service account's email as "Viewer"

3. Create config

cp config.example.json config.json

Edit config.json and fill in siteUrl / gscProperty / gaPropertyId.

4. Check it works

node scripts/fetch-gsc.mjs
node scripts/fetch-ga.mjs

It is OK if JSON lands in data/.

Operating workflow

Daily (minimum)

Nothing to do. Summarise weekly.

Weekly (Niki manual or schedule skill)

node scripts/fetch-gsc.mjs   # last 7 days of query / impression / click / position
node scripts/fetch-ga.mjs    # last 7 days of sessions / users / engagement
node scripts/update-rankings.mjs  # update the current-rank column in KEYWORDS.md
node scripts/weekly-report.mjs    # add a row to METRICS.md

Monthly (strategy review)

  • Review CLUSTERS.md: update pillar articles, add/remove clusters
  • Re-evaluate the status in KEYWORDS.md: for KWs that remain "target" but whose ranking does not move, suspect the cluster strategy

The basics of the topic-cluster strategy

A structure in which a single pillar (a broad theme, a deep article) sits at the centre, with multiple clusters (concrete topics) connected by internal links.

  • pillar: per TIL category (cognition / thinking / git / design / claude)
  • cluster: an individual TIL entry
  • internal links: pillar ↔ cluster is bidirectional; cluster ↔ cluster only when there is relevance

A KW with broad search intent (e.g. "metacognition") goes to the pillar; a narrowed KW (e.g. "how to use metacognition in learning") goes to a cluster.

Automatic referencing from CLAUDE.md

When handling this directory in Claude Code, enforcing in seo/CLAUDE.md or the repo-root CLAUDE.md that > before writing a new TIL, check the not-started KWs in seo/KEYWORDS.md and the cluster plan in seo/CLUSTERS.md will tie the choice of writing topic to the strategy.

148 notestil