The visibility-exporter container on docker2 polls each configured search-engine webmaster API for every tracked site and exposes the results as Prometheus gauges. It is stdlib-only Python living in jakemon/visibility/.
visibility/sites.json maps each site to its provider identifiers — Google Search Console (sc-domain: properties), Bing, and Yandex. Tracked sites include wiki.wikantik.com, wikantik.com, jakefear.com, wiki.jakefear.com, maiiavorobiova.com, and the thelocalwiki.com family. Provider adapters live in visibility/providers/{google,bing,yandex}.py; IndexNow keys live in visibility/indexnow-keys/.
Metrics are rolling-window snapshots, not counters: each poll covers a trailing 28-day lookback ending 2 days ago (search engines lag ~2–3 days). So a Grafana range of "90d" shows how the 28-day-window gauge evolved — it does not sum to 90 days of traffic. Site totals aggregate clicks/impressions with an impression-weighted average position.
| Metric | Labels | Meaning |
|---|---|---|
webmaster_clicks / webmaster_impressions | site, engine | Site totals for the window |
webmaster_avg_position | site, engine | Impression-weighted average position |
webmaster_query_impressions / _clicks / _position | site, engine, query | Top queries |
webmaster_page_impressions / _clicks / _position | site, engine, page | Top pages |
webmaster_query_page | engine, query, page | Google query→page pairs (value = impressions) |
webmaster_indexed_pages | site, engine | Best-effort index counts |
webmaster_exporter_up / _last_success_timestamp_seconds | engine | Provider health |
Grafana needs auth; Prometheus on docker2:9090 does not. The fastest analysis loop is PromQL over the API, e.g. top pages for a site:
curl -s 'http://docker2:9090/api/v1/query' \
--data-urlencode 'query=topk(25, webmaster_page_impressions{site="wiki.wikantik.com", engine="google"})'
The search-visibility Grafana dashboard (uid search-visibility, in dashboards/services/) renders these plus AI-referral log panels from Loki. The 2026-08-08 SEO pass on the wiki was driven entirely from these metrics — the workflow is documented from the consumption side in the wikantik SEO notes.
history.py (snapshot history), opportunities.py (under-performing query/page detection), report.py (report rendering), actions.py (IndexNow submissions and similar) — all unit-tested beside the code (test_*.py).