seo-rendering (M4)
SkillMediaAudit a page's rendering strategy and JavaScript dependency — diff raw HTML against the rendered DOM to measure how much primary content, links, headings, and JSON-LD exist only after JS executes, classify CSR-only / SSR / SSG / ISR, and emit framework-specific guidance. Module M4. Feeds both the Search SEO and AI Visibility scores.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the seo-rendering (M4) skill
What this skill tells your AI
The instructions your AI receives, as published by hainrixz/claude-seo-ai in skills/seo-rendering/SKILL.md and read by ahel’s review.
Content that only exists after hydration is invisible to any consumer that does not run JavaScript. Google renders JS (documented); most third-party AI crawlers are reported not to (directional — see Honesty), so a CSR-only shell is primarily an AI-visibility and crawl-efficiency problem. JS dependency also delays first paint; see references/cwv-thresholds.md for how this feeds LCP/INP.
Inputs
Work from the PageSnapshot named in your dispatch envelope: read parsed from <run_dir>/pages/<slug>.json and parsed_rendered, plus the render{needed,signals,used,confidence,hint,delta} block — the script already computed the raw-vs-rendered delta; raw_html_path/rendered_html_path name the files on disk; Grep pages/<slug>.html for verbatim evidence; site artifacts live in <run_dir>/site/{robots.json,sitemaps.json,discovery.json}. Deterministic findings already emitted by audit.mjs are listed in <run_dir>/findings.deterministic.json — do not re-emit those ids; add model-judged findings only. If invoked directly with a URL/path and no snapshot exists, first run node "${CLAUDE_PLUGIN_ROOT}/scripts/snapshot.mjs" <target> --out "${CLAUDE_PLUGIN_DATA}/runs" and use the printed snapshot path.
Audits
Working from the PageSnapshot (parsed_rendered when render.used is not none, else parsed) and the script-computed render.delta:
- Content delta: diff
raw_html_pathvsrendered_html_path— measure the share of primary text, internal links, headings (h1–h3), and<script type="application/ld+json">blocks that appear only after JavaScript runs. - Classify the strategy: CSR-only (empty/near-empty raw shell, content injected client-side) / SSR / SSG (prerendered static) / ISR (prerendered + revalidated). Use raw-HTML completeness and framework signals (
__NEXT_DATA__, hydration markers,data-reactroot, build manifests). - Hydration-blocked text: primary content present in raw HTML but hidden/empty until hydration, or rendered only into a client-only island.
- Lazy-loaded main content: above-the-fold or primary content that requires scroll/intersection/interaction to load — invisible to a non-interacting crawler.
- AI gate: if the h1, primary body, or JSON-LD exist only in
rendered_html_path, flag the page as not reliably consumable by non-JS AI crawlers.
Fixes (fixable: advisory)
Rendering strategy is a framework/architecture decision with high breakage risk, so M4 is ADVISORY only — it diagnoses and prioritizes, it never auto-edits build/server code.
- Emit framework-specific guidance: e.g. move CSR-only routes to SSG/ISR or SSR (Next.js App Router server components /
generateStaticParams+revalidate; Nuxt/Astro/SvelteKit equivalents). - Recommend prerendering or partial prerendering for primary content; reserve client-only islands for genuinely interactive widgets.
- Where the right strategy depends on data freshness or constraints the snapshot can't reveal, leave a clearly-marked TODO for the user — never fabricate a
revalidateinterval or assert a strategy choice. Every finding carriesfixable: advisory.
Verification
render_diff: compute the content-delta ratio ofraw_html_pathvsrendered_html_path(primary text / links / headings / JSON-LD present in rendered but absent in raw). A high delta on primary content confirms the JS dependency.- Rendering an accurate
rendered_html_pathrequires a headless-browser data tier. When that tier is unavailable, status isneeds_api— never a falsepass.
Findings
Emit findings per schema/finding.schema.json. Severity policy: 5 is reserved for catastrophic, eligibility-killing facts at site/template scope; 4 major · 3 moderate · 2 minor · 1 cosmetic · 0 informational — and only an established severity-5 fail in an active category can cap a score (references/scoring-model.md). Examples:
M4.render.csr_only_primary_content— the H1 and body text exist only inrendered_html_path; the raw HTML is an empty shell (fail, severity 5, axisboth,fixable: advisory, confidenceestablished). This is the module's only capping finding, and only at template/site scope.M4.render.jsonld_js_injected— JSON-LD blocks appear only after hydration, so a non-JS consumer sees no structured data (warn, severity 3, axisai,fixable: advisory, confidenceestablished).M4.render.lazy_main_content— primary content loads only on scroll or interaction (warn, severity 3, axisboth,fixable: advisory, confidencedirectional).M4.render.needs_renderer— the page shows CSR signals and no renderer was available, so the delta could not be measured (needs_api, severity 3, axisboth). Each finding:evidence.observedquotes the raw-vs-rendered delta on the page;verification.reproduceis a runnablerender_diffassertion;expected_impactis banded + confidence-tagged (no naked %).
Honesty
- Googlebot renders JavaScript — documented by Google (second-wave, queued rendering), so a well-built CSR app can still be indexed and rank. That part is
established; treat CSR-only as a risk to AI consumers and to crawl efficiency, not as an automatic Google failure. - "Most AI crawlers do not execute JavaScript" is
directional, not documented. Vendors publish user-agent tokens, not rendering capabilities. Word it as "we could not confirm that these crawlers execute JS, and their published behaviour suggests they do not" — never as a vendor statement. - Don't claim "SSR ranks higher than CSR" as a ranking factor. What is real is content availability to non-JS consumers and faster first paint, not a rendering-mode boost. Keep CSR where the page is interactive by nature and the primary content is still server-delivered.
- A render delta measured without a real headless browser is not a measurement — if the renderer tier was unavailable, say
needs_apirather than inferring the delta from framework markers alone.
Signals
- GitHub stars
- 59
- Forks
- 5
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
seo-rendering- Source
- github.com/hainrixz/claude-seo-ai