tools/seo_dashboard/probe.py
<link rel="alternate" hreflang="es" href="https://es.christchurchmiami.org/"> in its HTML head — but es.christchurchmiami.org returns NXDOMAIN. Google can interpret a broken hreflang pair as a configuration error and drop the en page from the cluster, or treat both as misconfigured. This is the top action item for this pass.
| Surface | 2026-05-09 state | 2026-05-14 state | Δ |
|---|---|---|---|
| christchurchmiami.org | Snappages main site, 11 critical/high findings, 6 medium | Snappages main site, 200 OK, 53.8 KB body, 17 JSON-LD types, 84 sitemap URLs, hreflang declared (en/es/x-default) | stable |
| es.christchurchmiami.org | Not tracked | NXDOMAIN — host does not resolve | new — offline |
| prayer.christchurchmiami.org | Not tracked | NXDOMAIN — host does not resolve | new — offline |
| app.christchurchmiami.org | Cloudflare Pages app, ~2 days live, 3 critical / 4 high / 5 medium findings (APP-1..APP-12) | NXDOMAIN — host does not resolve | regression — offline |
| resources.christchurchmiami.org | SermonShots subdomain, sunset path pending 301 from vendor | SermonSend SvelteKit SPA, 200 OK but canonical points at a logo PNG, 583 bytes visible text, 0 sitemap URLs | stable — leaking |
The main site's homepage HTML declares Spanish alternate via <link rel="alternate" hreflang="es" href="https://es.christchurchmiami.org/"> alongside an en and x-default. But dig +short es.christchurchmiami.org @1.1.1.1 returns empty — the subdomain has no DNS record.
es.christchurchmiami.org CNAME at the rendered Spanish content if it exists somewhere; (b) remove the hreflang declaration from the en page (Snappages-side edit); (c) repoint the hreflang at /spanish-sermons or whatever Spanish path lives on the main domain.Workspace memory references a multi-tenant prayer wall project (project_prayer_wall_multitenant) where the prayer subdomain is designed for CCM first. DNS confirms the subdomain does not currently resolve.
The 2026-05-09 audit verified the app subdomain as live ("Cloudflare Pages app, ~2 days live") and identified APP-1 through APP-12. As of 2026-05-14, dig +short app.christchurchmiami.org @1.1.1.1 returns empty.
reference_app_christchurchmiami: GitHub at Humble-Disruption/app-christchurchmiami-org). Confirm in browser before claiming resolved.The subdomain serves a SvelteKit SPA. Parsing the HTML: <link rel="canonical" href="/_app/immutable/assets/S%20SEND%20LOGO%20ORIGINAL.BFgn2FyZ.png">. No meta description, no og:image, no JSON-LD blocks, no h1. The visible-text estimate is 583 bytes — well under the 1 KB SPA-shell threshold. /sitemap.xml returns 200 but lists 0 URLs.
resources.cm/* → app.cm lands (per 5/9 audit's URL mapping table), this subdomain is bleeding link equity and confusing crawlers.Probe parsed the homepage meta block: 17 JSON-LD types, hreflang declared, canonical present, meta description present, robots OK, sitemap 84 URLs. But og:title and og:image are both absent from the homepage head. Twitter and Slack scrapers fall back to <title> and image-from-first-img — which is functional but leaves the social-share preview to chance.
https://opengraph.xyz/url/https%3A%2F%2Fchristchurchmiami.org after.The 5/9 audit's findings against christchurchmiami.org remain open (the main site itself hasn't materially changed in 5 days). Specifically: CCM-1 through CCM-14. The findings against app.christchurchmiami.org (APP-1..APP-12) are now blocked behind DNS-3 — they can't be re-verified until the subdomain is back online.
| ID | Severity | Title | Status |
|---|---|---|---|
CCM-1 | crit | /en-espanol returns 404 — Ad Grant blocker | open |
CCM-2 | high | Legacy About-tier pages missing title/meta/canonical/schema | open |
CCM-3 | high | /giving redirect chain — Ad Grant policy concern | open |
CCM-4 | high | /sermons-and-blogs not in primary navigation | open |
CCM-5 | high | Blog index meta description is mission statement | open |
CCM-7 | high | Blog tag taxonomy bloated (80+ tags) | open |
CCM-8 | med | Older blog posts predate the 11-entity @graph | open |
CCM-9 | med | Image alt text gap on legacy pages | open |
CCM-10 | med | Five /sermons* pages cannibalize each other | open |
CCM-11 | med | og:image protocol mismatch (http://) on blog posts | open |
CCM-13 | med | FAQ count varies post-to-post (6, 9, 11) | open |
CCM-14 | low | /resources menu page may cannibalize subdomain | open |
APP-1..APP-12 | — | All 12 app.cm findings | blocked on DNS-3 |
The 5/9 manual comparative matrix is preserved in the dashboard. Today's automated probe confirms the peer reachability and body-size profile:
| Peer | Status | Body size | JSON-LD blocks | H1 count | Note |
|---|---|---|---|---|---|
| Christ Journey | 200 | 291 KB | 1 | 0 | Default WordPress; large content library |
| Christ Fellowship Miami | 200 | 1.6 MB | 3 | 7 | Wix; aggressive local SEO |
| Granada Church | 200 | 795 KB | 1 | 0 | Older WordPress build |
| Old Cutler Presbyterian | 200 | 114 B | 0 | 0 | JS redirect script → /lander; thin landing |
| Vous Church | 200 | 87 KB | 0 | 1 | Webflow build; zero JSON-LD |
| Christchurch Miami | 200 | 53.8 KB | 4+ | 3 | 17 distinct JSON-LD types — dominates peers |
CCM ships a tighter HTML payload (lowest body size of the responding peers) with the strongest JSON-LD breadth (17 distinct types vs. max 3 at any peer). The 5/9 audit's qualitative aggregate (CCM tied with CFM/CJ at 35) still stands directionally — and the schema gap measured today is the largest single CCM moat.
Each tracked CCM surface earns up to 100 points, summed and averaged across the 5 tracked surfaces. Surfaces that don't resolve in DNS score 0. The probe runs daily at 06:00 EST via the scheduled-tasks system; see tools/seo_dashboard/probe.py.
| Signal | Points |
|---|---|
| Online & 2xx response | 30 |
| JSON-LD schema present | 10 |
| Title, meta description, canonical, og:image (5 each) | 20 |
| og:title (3), hreflang/EN-only OK (5) | 8 |
| Robots.txt + sitemap.xml reachable (5 each) | 10 |
| H1 present + non-trivial body + visible text > 1KB (5 each) | 15 |
| html lang attribute | 2 |
| Max | 100 |
The formula is intentionally simple — it surfaces gross gaps (missing tags, offline subdomains) rather than nuanced quality differences. The narrative audit (this document) is where qualitative judgment lives. The formula's role is to give Jeff a daily-trackable number that future passes can compare against apples-to-apples.
These three actions clear all four new critical findings opened in this pass and unblock the path back to the trajectory the 5/9 audit was on.