---
title: Site Health / SEO
description: Monitor website_url, audits, IndexNow, GSC/Yandex, PageSpeed — in CMS Site admin.
---

# Site Health / SEO

**CMS Site → Health / SEO** (staff) watches the live `website_url`: crawl, score, issues, blog/KB readiness, IndexNow, organic search, and PageSpeed.

Low SEO score on publish is a **warning**, not a block. No public badge in MVP.

## What is automated (and what is not)

| Included | Where |
| --- | --- |
| `sitemap.xml` (fetch + URL list) | Audit |
| `robots.txt` (reachability, Disallow: /, Sitemap:) | Audit |
| On-page HTML (title, H1, meta, canonical, JSON-LD, alt, TTFB) | Audit |
| Blog/KB checklist → `seo_score` + checks | Audit / Content / editor |
| Homepage PageSpeed / CWV | Audit + **More → Speed** |
| IndexNow ping | On publish / manual ping |
| Clicks / impressions / queries | **More → Search** after OAuth + Sync |
| AI comment | **More → Settings → AI**, on top of scan facts |
| Plan: fix / enhance / create | **Check site** button → three lists |

The audit **does not change the live site** and does not scrape Yandex/Google SERP. Organic and average position come from GSC / Webmaster. Semantics: cluster ↔ page (gap / mapped / cannibal). You apply changes yourself.

## Prerequisites

1. Set **Website URL** on the site overview (or `base_url` in SEO settings).
2. Enable monitoring; optionally set sitemap / schedule.
3. Apply SEO migrations on Supabase (profiles, issues, reports, integrations).

## Screen (no tab bar)

1. **Check site** — audit, then the to-do list is generated automatically.
2. Three lists: **Fix** / **Enhance** / **Create**. Open an item: where, what to paste, Done.
3. Platform does not change the live site.

GSC/Yandex, PageSpeed, reports, and settings live under collapsed **More**.

| More | Purpose |
| --- | --- |
| Search | IndexNow, GSC / Yandex Webmaster OAuth, organic sync |
| Raw audit | Issues, crawled pages |
| CMS content | Blog/KB: score + checklist |
| Speed | PageSpeed / CWV (homepage) |
| Reports | Fix plan + runbook (MD) + optional AI |
| Settings | URL, schedule, notifications, IndexNow |

## Admin API

Base: `YOUR_API_URL`, admin session.

```http
GET  /v1/cms/sites/{siteId}/seo/verdict
POST /v1/cms/sites/{siteId}/seo/scans
GET  /v1/cms/sites/{siteId}/seo/issues?status=open
GET  /v1/cms/sites/{siteId}/seo/pages
POST /v1/cms/sites/{siteId}/seo/readiness/blog
POST /v1/cms/sites/{siteId}/seo/readiness/kb
POST /v1/cms/sites/{siteId}/seo/indexnow
POST /v1/cms/sites/{siteId}/seo/psi
POST /v1/cms/sites/{siteId}/seo/digest
GET  /v1/cms/sites/{siteId}/seo/content
GET  /v1/cms/sites/{siteId}/seo/tasks
GET  /v1/cms/sites/{siteId}/seo/dashboard
GET  /v1/cms/sites/{siteId}/seo/work-plan
POST /v1/cms/sites/{siteId}/seo/work-plan/generate
GET  /v1/cms/sites/{siteId}/seo/work-plan/markdown
PATCH /v1/cms/sites/{siteId}/seo/clusters/{clusterId}
POST /v1/cms/sites/{siteId}/seo/competitors
GET/PUT /v1/settings/ai
```

OAuth:

```text
Google Redirect URI (exactly as shown in Search UI):
{YOUR_API_URL}/v1/cms/seo/oauth/google/callback
→ Google Cloud → Authorized redirect URIs (API host, not admin)

Yandex (typical app): Callback is only
https://oauth.yandex.ru/verification_code
→ “Open Yandex” → copy code → “Confirm code”
(POST /v1/cms/sites/{siteId}/seo/search/connect/yandex/code)

Custom `{YOUR_API_URL}/v1/cms/seo/oauth/yandex/callback` —
only if Yandex allows a Callback URI and YANDEX_OAUTH_REDIRECT_URI is set.
```

Schedule: worker → `POST /v1/internal/seo/tick` (`WORKER_SECRET`).

## IndexNow

1. Generate a key in Search / Settings.
2. Host `{key}.txt` at the site root (body = key).
3. On blog/KB publish, Platform pings IndexNow (if configured) and soft-rechecks the URL.

## PageSpeed

**More → Speed** calls the [PageSpeed Insights API](https://developers.google.com/speed/docs/insights/v5/get-started) for the site’s `Website URL`. Without an API key Google rate-limits by IP (429) quickly — on production the key is required.

### Beginner setup

1. **Website URL** on the CMS site Overview: `https://your-site.example` (public, not localhost).
2. **Enable the API:** [PageSpeed Insights API](https://console.cloud.google.com/apis/library/pagespeedonline.googleapis.com) → Enable.
3. **Create a key:** [Credentials](https://console.cloud.google.com/apis/credentials) → Create credentials → API key.
4. Set on the Platform **API** process and **restart**:

   ```bash
   PAGESPEED_API_KEY=AIza...your_key
   ```

5. Check `GET YOUR_API_URL/v1/health` → `seo.pagespeed` is `"configured"`, then run **Start PSI** on Performance (or a full homepage audit).

Manual check without Platform: [pagespeed.web.dev](https://pagespeed.web.dev/).

The key is **not** entered in admin UI — only API env. **More → Speed** shows key status from `/v1/health`.

## Content SEO meta

Blog and KB editors: meta title/description, cover alt, readiness card. Score is weighted (not coarse 0/17/33… buckets). Public KB returns `meta_title`, `meta_description`, `cover_alt` on `GET …/kb/articles/{slug}`.

## Reports and AI strategist

After an audit, **Reports** show coverage, a **full fix plan** (not only top-5) with owner / where-in-code / steps / acceptance, **Copy runbook (MD)** for developer tickets, and optional AI.

Issue-type catalog: [SEO — developer runbook](/en/guides/cms-seo-dev-runbook).

```http
GET /v1/cms/sites/{siteId}/seo/reports
GET /v1/cms/sites/{siteId}/seo/reports/{reportId}
GET /v1/cms/sites/{siteId}/seo/reports/{reportId}/developer-doc
POST /v1/cms/sites/{siteId}/seo/reports/{reportId}/ai
POST /v1/cms/sites/{siteId}/seo/digest
```

AI keys: **Settings → AI** (not env). Providers: Claude, OpenAI, [Timeweb AI Gateway](https://timeweb.cloud/docs/ai-agents/api-usage/ai-gateway) (`base_url` `https://api.timeweb.ai/v1`, models like `openai/gpt-4o`). API: `GET/PUT /v1/settings/ai`.

In the blog/KB editor: **Generate SEO** fills only empty `meta_title`, `meta_description`, `body` (with `# H1`), `cover_alt` — `POST /v1/cms/sites/{id}/seo/generate-fields`.

## GSC / Yandex — API env

Without `GOOGLE_OAUTH_CLIENT_ID/SECRET` and `YANDEX_OAUTH_CLIENT_ID/SECRET`, Connect stays disabled (`platform_oauth_missing`). The Redirect URI in the UI matches the OAuth authorize request.

See also [CMS Site](/en/guides/cms-site).
