Skip to content

Releases: izzipizzy/gsc-hub

v0.6.2 — bounded per-site fan-out

Choose a tag to compare

@izzipizzy izzipizzy released this 04 Aug 09:04

Reliability release for large portfolios: the per-site fan-out no longer melts the socket pool, and an expired token is refreshed once instead of once per site.

Fixed

  • Per-site fan-outs are bounded to 8 concurrent Search Console calls instead of one connection per property. On a ~200-site account the unbounded fan-out saturated the socket pool and the whole batch died with UND_ERR_CONNECT_TIMEOUT, so the Sites table rendered dashes. Thanks @KuznetsovRA#1.
  • An expired access token is now refreshed once per account per fan-out. The shared account row is updated in place and concurrent refreshes are deduped, so a 200-site page load no longer sends 200 token-endpoint requests — a burst Google can answer with 400s that were being read as invalid_grant and marked the account revoked.

Changed

  • Fan-out concurrency is tunable via GSC_CONCURRENCY (default 8). URL Inspection runs narrower under GSC_INSPECT_CONCURRENCY (default 4) — it is capped by quota (2000/day, 600/min per property), not by the socket pool.

Full changelog: v0.6.1...v0.6.2

v0.6.1 — Setup wizard

Choose a tag to compare

@izzipizzy izzipizzy released this 19 Jul 13:43

Browser setup wizard — no more hand-editing .env.

On first run the app opens /setup: paste your Google Client ID / Secret (the page shows the exact redirect URI to register in GCP) and pick an access mode — loopback-only or exposed-with-login. AUTH_SECRET is auto-generated and stored in SQLite. For exposed deployments the admin is created in the browser (argon2), removing the old .env-quoting and one-shot-seed lockout traps.

Added

  • Setup wizard at /setup (Google keys + access mode)
  • In-browser admin creation for exposed deployments

Fixed

  • Single-user (loopback) mode no longer forces a login redirect — it runs as a local admin
  • Token refresh resolves the Google OAuth client credentials through the config layer (env or wizard-stored), so a wizard-configured self-host keeps refreshing tokens instead of failing ~1h after connect

Changed

  • Config precedence: environment variables override wizard-stored values; env-provided fields are read-only in the wizard

Full notes in CHANGELOG.md.

v0.6.0 — SEO analytics suite

Choose a tag to compare

@izzipizzy izzipizzy released this 18 Jul 09:42

Big release: a full SEO analytics suite on top of Search Console — per-site deep-dives and a portfolio-wide view — plus Bing/IndexNow, site health checks, and optional multi-user login. All analytics are live-fetched; no GSC data is stored.

Highlights

  • Per-site analytics (/properties/[site]): Striking Distance, Keyword Cannibalization, CTR Benchmark, Content Decay, Branded split, Site Health (SSL / Safe Browsing / Core Web Vitals).
  • Portfolio analytics (/properties/portfolio): the same, aggregated across every site — URL-addressable tabs, country filter, copy-queries, per-page GSC index status, async + cached.
  • Sparklines, one-click Privacy Blur, Bing Webmaster + IndexNow, and optional login & roles (off by default).

Full details: CHANGELOG.md · CHANGELOG.ru.md

v0.3.1 — totals bar

Choose a tag to compare

@izzipizzy izzipizzy released this 11 Jun 17:14

Added

  • Totals bar on /properties: sums Sites / Impressions / Clicks across all non-hidden sites for the selected period.

v0.3.0

Choose a tag to compare

@izzipizzy izzipizzy released this 08 Jun 19:39

Major release: deploy moved to Docker Compose + OrbStack, sitemap submitting was added, and query analytics / mobile UI were expanded.

Added

  • Sitemap submit — per-site Submit sitemap (resubmits all sitemaps GSC knows, falls back to a guessed /sitemap.xml) and a Submit all sitemaps toolbar button (parallel across visible sites). Failure reasons in the row tooltip.
  • Query breakdown by page and country (query × page × country) in Top queries.
  • Google SERP link from a query's position cell (country-aware).
  • "G" badge per site for a one-click Google site: indexation check.
  • 1-day and 60-day periods (in addition to 3/7/28).
  • Docker Compose + OrbStack deploy: multi-stage Dockerfile, compose.yaml (served at https://gsc.local, automatic TLS), .dockerignore. Container also binds 127.0.0.1:5173 → 3000 so OAuth can run over localhost.

Changed

  • OAuth scope is now webmasters (read-write), required for sitemap submit.
  • Deploy switched from pm2 to Docker Compose; secrets injected at runtime via $env/dynamic/private.
  • READMEs (en/ru) and CLAUDE.md updated.

Fixed

  • Pinned @auth/core to 0.41.2 to match @auth/sveltekit 1.11.2 (the stray 0.34.3 broke sign-in with basePath?.replace is not a function).

Upgrade notes

  • Connect accounts over http://localhost:5173, not https://gsc.local — Google rejects OAuth redirects to the .local TLD.
  • Reconnect each account once to grant the read-write scope before submit works.
  • The loopback port is bound to 127.0.0.1 only; the app has no built-in auth and the DB holds OAuth tokens — do not expose it to the network.

Full changelog: https://github.com/izzipizzy/gsc-hub/blob/main/CHANGELOG.md

v0.2.0 — Operator Console refresh + URL Inspection

Choose a tag to compare

@izzipizzy izzipizzy released this 02 May 17:57

English

Visual design pass — "The Operator's Console"

  • Unified toolbar pattern across all pages (breadcrumbs, segmented controls, primary action). 3d/7d/28d period and 2/4/6 columns toggles styled like Linear/Stripe Dashboard.
  • Refined status badges with colored dots (active / revoked / error).
  • Section dividers under Top queries and Top pages with descriptive subtitles.
  • Sparkline cards now have a faint area fill (8% opacity) for visual weight.
  • Query-history chart polished: dashed gridlines, thin axis, tightened legend.
  • All numbers use tabular-nums for vertical alignment.
  • Subtle hover affordance on table rows.
  • Educational empty states ("No connected accounts yet" with a hint about local token storage).
  • Reduced-motion respected via @media (prefers-reduced-motion: reduce).
  • Full-bleed layout (no max-w-* containers).

Footer

  • Global footer with copyright, GitHub link, and Telegram link, all opening in new tabs.

URL Inspection (inline per-site expansion)

  • Click any row in the Sites table to expand a quick URL Inspection report for the top 10 URLs of that site.
  • Columns: URL, verdict (Indexed / Partial / Not indexed / Neutral), coverage state, robots.txt state, last crawl date, canonical URL with mismatch flag.
  • 401 from Google marks the account revoked automatically; 429 surfaces "quota exceeded" without crashing the page.
  • Internal clicks (CSV links, Hide/Unhide, site link) don't toggle the expansion.

URL Inspection cache (12 hours)

  • Results cached server-side in SQLite, keyed by (account_id, site_url, urls_hash). Re-clicking the same site within 12h reuses the cache.
  • Force refresh button bypasses the cache for a deliberate fresh fetch.
  • Cache age shown in the panel header ("Cached 5m ago / Fresh").
  • Required because URL Inspection has a hard 2000-call/day quota per Google account.

Sitemap fallback

  • Sites with no/low impressions in the current period now fall back to URLs from their sitemap.
  • Source order: 1) GSC sitemaps.list (user-submitted sitemaps, preferred); 2) direct /sitemap.xml at site root.
  • Handles <sitemapindex> by following the first child sitemap.
  • Homepage always included as the first URL inspected.
  • Panel header shows the source: "Top by impressions" / "by impressions + sitemap fill-in" / "from sitemap (no impressions)".

Display polish

  • Domain properties (sc-domain:example.com) shown as example.com; href still resolves to https://example.com/.
  • Page titles renamed: Properties → Sites (URL routes unchanged).

Tests

  • 39 unit tests, up from 31.

Русский

Визуальный pass — «The Operator's Console»

  • Единый паттерн toolbar'а на всех страницах (breadcrumbs, segmented controls, primary action). Переключатели периода 3d/7d/28d и колонок 2/4/6 в стилистике Linear/Stripe Dashboard.
  • Refined status badges с цветными точками (active / revoked / error).
  • Section dividers под Top queries и Top pages с описательными подписями.
  • Карточки sparkline получили мягкую area fill (opacity 8%) для визуальной плотности.
  • Query history chart: dashed gridlines, тонкая axis, плотная легенда.
  • Все числа выводятся через tabular-nums для вертикального выравнивания.
  • Аккуратный hover на строках таблиц.
  • Обучающие empty states («No connected accounts yet» с подсказкой про локальное хранение токенов).
  • Reduced-motion поддерживается через @media (prefers-reduced-motion: reduce).
  • Full-bleed layout (нигде max-w-* обёрток).

Footer

  • Глобальный footer с копирайтом, ссылкой на GitHub и Telegram, обе открываются в новой вкладке.

URL Inspection (inline expansion на сайт)

  • Клик по строке в таблице Sites разворачивает быстрый отчёт URL Inspection для топ-10 URL'ов этого сайта.
  • Колонки: URL, verdict (Indexed / Partial / Not indexed / Neutral), coverage state, robots.txt state, дата последнего crawl'а, canonical с flag'ом mismatch.
  • 401 от Google автоматически помечает аккаунт revoked; 429 показывается как «quota exceeded» без падения страницы.
  • Внутренние клики (CSV-ссылки, Hide/Unhide, ссылка на сайт) не дёргают expansion.

Кеш URL Inspection (12 часов)

  • Результаты кешируются server-side в SQLite по ключу (account_id, site_url, urls_hash). Повторный клик в течение 12 часов берёт из кеша.
  • Кнопка Force refresh обходит кеш для явного свежего запроса.
  • Возраст кеша показан в шапке панели («Cached 5m ago / Fresh»).
  • Кеш необходим потому что у URL Inspection жёсткий лимит 2000 вызовов/день на Google-аккаунт.

Sitemap fallback

  • Для сайтов без/с малыми impressions в текущем периоде теперь используется fallback по sitemap.
  • Порядок источников: 1) GSC sitemaps.list (пользователь-сабмиттед sitemap'ы, предпочтительно); 2) прямой /sitemap.xml в корне сайта.
  • <sitemapindex> обрабатывается переходом по первому child-sitemap.
  • Главная страница всегда включена первой.
  • Шапка панели показывает источник: «Top by impressions» / «by impressions + sitemap fill-in» / «from sitemap (no impressions)».

Полировка отображения

  • Domain properties (sc-domain:example.com) показываются как example.com; href ведёт на https://example.com/.
  • Заголовки переименованы: Properties → Sites (URL-маршруты не менялись).

Тесты

  • 39 unit-тестов, было 31.

v0.1.0 — initial public release

Choose a tag to compare

@izzipizzy izzipizzy released this 02 May 15:08

First public release.

What is gsc-hub

Local self-hosted multi-account hub for Google Search Console. Connect multiple Google accounts via OAuth, view all sites in one table, aggregate queries and pages across accounts, see per-site dashboards with sparklines and period-over-period deltas, drill into 16-month query history with one click. No external service, no GSC data leaves your machine.

Features

  • Multi-account OAuth — connect any number of Google accounts; refresh tokens auto-rotate; revoked tokens detected on first 401.
  • Unified sites table — all Search Console properties from all connected accounts in one full-bleed table, sortable, URL-driven (?days=, ?sort=, ?dir=).
  • Top queries & Top pages — aggregated rollups across visible (non-hidden) sites, client-side sortable.
  • Inline 16-month query history — click any query to expand a position+impressions chart spanning the last 16 months.
  • Dashboard — per-site cards with sparkline of daily clicks, four metrics with deltas vs the previous period of the same length, configurable 2/4/6 columns.
  • CSV exports — queries or pages, configurable period, RFC 4180 compliant.
  • Hide sites locally (browser localStorage), Refresh preserves all URL state.
  • No data caching — every page load is a fresh fan-out to GSC.

Stack

SvelteKit (Svelte 5) + TypeScript · Auth.js · better-sqlite3 · TailwindCSS v3 · Vitest. No chart libs, no icon fonts, system sans only.

Quickstart

```bash
git clone https://github.com/izzipizzy/gsc-hub.git
cd gsc-hub
pnpm install
cp .env.example .env

fill in GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, AUTH_SECRET

pnpm dev
```

See README.md for full setup, README.ru.md for Russian.

License

MIT.