# SEO Monitoring Dashboard

A private dashboard that watches backlinks, Google positions, index status and Core Web Vitals across my own sites — built entirely on free Google APIs, with alerts when something moves.

**Canonical:** https://spoko.space/seo-monitoring-dashboard/  
**Language:** en  
**Published:** 2026-05-14  
**Updated:** 2026-09-22  
**Tags:** laravel, filament, mariadb, seo, google-api, core-web-vitals  
**Category:** Portfolio

---
## At a glance {#at-a-glance}

|  |  |
| --- | --- |
| Problem | Backlinks disappear, positions slide and pages fall out of the index quietly. You find out weeks later, and the tools that would have told you sooner bill by the month. |
| What was built | A dashboard that watches backlinks, Search Console performance, keyword positions, index status, Core Web Vitals, visitor analytics and on-page issues across several sites, and raises an alert when one of them moves the wrong way. |
| My role | All of it — the data model, the Google API integrations, the scheduler and queue work, the Filament panel and the alerting. |
| What makes it interesting | Almost everything a paid rank tracker sells is available free from Google’s own APIs. The product is the plumbing: scheduling, storing history and noticing change. |
| Result | A private tool I and a few people close to me run our own sites on, inside free API quotas, with the history kept so a drop can be dated. |

This one is not a client project and not a product you can sign up for. It runs for my own sites and a handful of people close to me, and it exists because the alternative was paying a monthly subscription for numbers Google already gives away.

## The problem {#the-problem}

Search visibility fails slowly and quietly. A backlink you paid for or earned goes dead when someone redesigns their site. A page drops out of the index after a template change. Your average position slides two places a week for a month, which is nothing on any given day and a lot by the end. [Core Web Vitals](https://spoko.space/glossary/core-web-vitals/) degrade because a plugin update shipped a heavier script.

None of that announces itself. You notice when traffic is already down and then spend an afternoon working out when it started — and usually you cannot, because nobody was writing the numbers down.

Commercial tools solve this and charge per month per project for it. That is fair for an agency running fifty clients. It is a poor deal when you want to watch a handful of your own sites and the underlying data is free.

## What it watches {#what-it-watches}

**In one dashboard**

- **Backlinks, and whether they are still alive** — Each link is re-crawled on its own schedule: HTTP status, anchor text, rel attribute, and whether the linking page is still indexed. A 0–100 quality score folds those signals into one number.
- **Search Console performance** — Clicks, impressions, CTR and average position pulled daily and stored as history — by page, query, device and country, so a drop can be dated rather than guessed at.
- **Keyword positions** — Tracked keywords get a daily position from Search Console rather than a scraper, with a 30-day trend and the clicks and impressions behind each one.
- **Core Web Vitals, twice over** — PageSpeed Insights for lab data and the Chrome UX Report for what real visitors actually experienced — mobile and desktop, tracked over time instead of checked once.
- **Index status and sitemaps** — URL Inspection says whether Google has the page. The sitemap monitor parses robots.txt and sitemap.xml, follows sitemap indexes, and flags pages that are indexed but missing from the sitemap.
- **What the visitors actually did** — Sessions, users, pageviews, bounce rate and average session duration come daily from Analytics, with traffic sources, top pages and referrers — so what search promised and what people actually did sit on the same screen.
- **On-page audit** — Each page is fetched and checked against thirteen rules — title, meta description, H1, canonical, robots, image alt text, links, word count, Open Graph, schema, hreflang, HTTPS and response time — then scored 0–100, with every issue weighted by severity.
- **Alerts, not dashboards to remember to open** — A lost backlink, an average position down more than three places week over week, a page that stops passing inspection, Core Web Vitals crossing into poor — each raises an alert with a severity.

## The interesting part: it all runs on free quotas {#the-interesting-part-it-all-runs-on-free-quotas}

The reason a tool like this can exist without a subscription is that Google publishes the data through its own APIs, at no cost, to anyone willing to build the plumbing.

| API | What it gives, and what it costs |
| --- | --- |
| Search Console — Search Analytics | Clicks, impressions, CTR, position, broken down by page, query, device and country. **25 000 calls a day**, per project; a sync spends five to fifteen. |
| Search Console — URL Inspection | Whether a specific URL is indexed and why. **2 000 a day** per property; the scheduler spends fifty per run on the top pages. |
| PageSpeed Insights | Lab Core Web Vitals plus performance, accessibility, SEO and best-practice scores. **25 000 a day**; two calls per site, mobile and desktop. |
| Chrome UX Report | Field data — what Chrome users actually experienced, per origin and per URL. **150 a minute**, no daily cap. |
| Analytics Data API (GA4) | Sessions, users, pageviews, bounce rate, traffic sources, top pages and referrers. **200 000 core tokens a day** per property — this one bills by query complexity rather than by call; the daily sync runs four reports over a 30-day window. |

The on-page audit is the exception that proves the point: it uses no Google API at all. It fetches my own pages and reads the HTML, so the only thing it costs is the request.

Those numbers are the whole design constraint. They are generous enough that the system would carry roughly 1 500 projects before [Search Console](https://spoko.space/glossary/google-search-console/) became the limit — which is far more than it will ever need, and the reason nothing here is rationed or paywalled internally.

What you do not get for free is the part that makes it useful: something that calls those APIs on a schedule, keeps the answers, compares today against last week, and tells you when the comparison is bad. That is the product.

## How it stays current {#how-it-stays-current}

**The schedule**

1. **Backlinks — hourly** — Not every link every hour: the runner picks up whichever links are due for a re-check, so crawling spreads out instead of arriving as one daily spike.
2. **Search Console — daily, 05:00** — Yesterday’s performance and the tracked keywords, written into history tables the charts read from.
3. **Analytics — daily, 05:30** — A rolling 30-day window of sessions, traffic sources, top pages and referrers, half an hour after Search Console so the two sets of numbers line up on the same day.
4. **Index status — daily, 06:00** — URL Inspection across the top pages, capped per run so the daily quota is never the thing that breaks.
5. **Core Web Vitals — Mondays** — PageSpeed Insights, then the Chrome UX Report half an hour later. Weekly, because field data moves on a 28-day window and daily polling would tell you nothing new.
6. **Sitemaps — Mondays, 08:00** — Re-parse, re-compare against what is indexed, and surface the difference.
7. **On-page audit — Mondays, 09:00** — Fifty pages a run, fetched and scored against the thirteen rules. Weekly, because on-page issues arrive with a deploy, not on their own.

Everything heavier than a single HTTP call goes through a queue rather than the scheduler itself, so a slow crawl or a rate-limited API never holds up the rest of the run.

## My role {#my-role}

All of it. The project is mine end to end: the data model — thirty-three tables, most of them history rather than current state — the OAuth flow that covers both Search Console and Analytics, the four Google API clients, my own crawler for backlinks and the on-page audit, the scheduler and queue workers, the Filament panel, the charts and the alerting rules. Ninety-eight commits over about three and a half weeks in April 2026.

## Result {#result}

- **Drops can be dated** — Because the numbers are written down daily, "when did this start" has an answer instead of a guess.
- **No subscription** — The data was always free; what was missing was something to collect it. Running cost is a small server and nothing else.
- **Alerts that fire — and need tuning** — Lost links and slipping positions raise alerts rather than waiting to be noticed. Four thousand have accumulated and a hundred or so sit unread at any time, which is its own lesson: an alert nobody can act on is noise, and the thresholds are the unfinished part.

## Technologies {#technologies}
