{{ url }}
{% if 'Critical' in data.status %} {% elif 'Warning' in data.status %} {% elif 'Notice' in data.status %} {% else %}{% endif %} {{ data.status }}

Crawlability & Indexability

If any of these fail, Google cannot rank this page — fix these first.

{# ── Noindex ───────────────────────────── #} {% set ni_bad = data.noindex %}
Indexing
{{ 'BLOCKED' if ni_bad else 'INDEXABLE' }}
{% if ni_bad %} Via {{ 'X-Robots-Tag header' if data.x_robots_noindex else 'meta robots tag' }} {% else %} Google can index this page {% endif %}
{% if ni_bad %}
How to fix

{% if data.x_robots_noindex %}Remove the X-Robots-Tag: noindex response header from your server config. {% else %}Remove noindex from the <meta name="robots"> tag.{% endif %}

{% endif %}
{# ── Robots.txt ───────────────────────── #} {% set rb_bad = data.robots_disallowed %}
Robots.txt
{{ 'DISALLOWED' if rb_bad else 'ALLOWED' }}
{{ 'Googlebot cannot crawl this URL' if rb_bad else 'Googlebot can access this page' }}
{% if rb_bad %}
How to fix

Open your robots.txt file and remove or adjust the Disallow rule that matches this URL path.

{% endif %}
{# ── HTTPS ────────────────────────────── #} {% set ssl_bad = not data.is_https or not data.ssl_valid %}
Security
{% if not data.is_https %}HTTP (UNSECURE) {% elif not data.ssl_valid %}CERT INVALID {% else %}HTTPS SECURE{% endif %}
{{ 'SSL/TLS encryption' if data.is_https else 'Plain HTTP — no encryption' }}
{% if ssl_bad %}
How to fix

{% if not data.is_https %}Install an SSL certificate (Let's Encrypt is free) and set up 301 redirects from HTTP to HTTPS. {% else %}Renew or replace your SSL certificate. Check the server error log for the exact validation error.{% endif %}

{% endif %}
{# ── Mixed Content ─────────────────────── #} {% set mc_bad = data.has_mixed_content %}
Mixed Content
{{ 'DETECTED' if mc_bad else 'CLEAN' }}
{{ 'HTTP resources on HTTPS page — Chrome blocks these' if mc_bad else 'All resources use HTTPS' }}
{% if mc_bad %}
How to fix

Update all embedded src and href attributes to use https:// URLs. Use a Content Security Policy to catch future issues.

{% endif %}
{# ── Link Crawling ─────────────────────── #} {% set lc_bad = data.page_nofollow %}
Link Crawling
{{ 'NOFOLLOW' if lc_bad else 'FOLLOW' }}
{{ "Links here won't pass PageRank" if lc_bad else 'Links pass PageRank normally' }}
{% if lc_bad %}
Note

Remove nofollow from the meta robots tag unless you intentionally want to stop PageRank from flowing through this page's links.

{% endif %}

Ranking Signals

The on-page signals Google uses to understand and rank this page's content.

{# ── HTTP Status ─── #} {% set ok = data.status_code == 200 %}
HTTP Status
Server response code
{% if not ok %}
Fix: A non-200 status means this page cannot be indexed. Ensure the URL returns 200 OK or set up a proper 301 redirect to the canonical version.
{% endif %}
{{ data.status_code }}
{{ 'Error' if not ok else 'OK' }}
{# ── Title Tag ─── #} {% set tl_ok = data.title_len >= config.title_min_length and data.title_len <= config.title_max_length %} {% set tl_missing = data.title_len == 0 %}
Title Tag
Primary Google ranking signal — target {{ config.title_min_length }}–{{ config.title_max_length }} chars
{% if data.title %}
{{ data.title }}
{% endif %} {% if not tl_ok %}
{{ data.title_len }} chars {{ config.title_min_length }}–{{ config.title_max_length }} ideal
{% if tl_missing %}Fix: Add a unique, descriptive title tag between {{ config.title_min_length }} and {{ config.title_max_length }} characters that includes your primary keyword. {% elif data.title_len < config.title_min_length %}Fix: Your title is too short ({{ data.title_len }} chars). Expand it to describe the page content better while including your target keyword. {% else %}Fix: Your title is too long ({{ data.title_len }} chars) and will be truncated in search results. Shorten it to under {{ config.title_max_length }} characters.{% endif %}
{% endif %}
{{ data.title_len }}
chars
{# ── H1 ─── #} {% set h1_ok = data.h1_count == 1 %} {% set h1_bad = data.h1_count == 0 %}
H1 Tag
Main topic signal — exactly 1 required
{% if data.h1 %}
{{ data.h1 }}
{% endif %} {% if not h1_ok %}
{% if h1_bad %}Fix: Add one H1 tag that clearly describes this page's main topic. It should include your primary target keyword. {% else %}Fix: You have {{ data.h1_count }} H1 tags — remove duplicates. Only one H1 should exist per page to avoid confusing Google about the main topic.{% endif %}
{% endif %}
{{ data.h1_count }}
H1 tags
{# ── Meta Description ─── #} {% set md_len = data.meta_desc|length if data.meta_desc else 0 %} {% set md_ok = md_len >= config.meta_desc_min_length and md_len <= config.meta_desc_max_length %} {% set md_miss = md_len == 0 %}
Meta Description
Affects CTR in search results — target {{ config.meta_desc_min_length }}–{{ config.meta_desc_max_length }} chars
{% if data.meta_desc %}
{{ data.meta_desc }}
{% endif %} {% if not md_ok %}
{% if md_miss %}Fix: Write a compelling meta description ({{ config.meta_desc_min_length }}–{{ config.meta_desc_max_length }} chars) that summarizes the page and includes your keyword. This is what users see in Google search results. {% elif md_len < config.meta_desc_min_length %}Fix: Description too short ({{ md_len }} chars). Expand it to at least {{ config.meta_desc_min_length }} characters with a clear value proposition. {% else %}Fix: Description too long ({{ md_len }} chars) — Google will truncate it. Keep it under {{ config.meta_desc_max_length }} characters.{% endif %}
{% endif %}
{{ md_len }}
chars
{# ── Word Count ─── #} {% set wc_ok = data.words >= config.min_word_count %}
Word Count
Content depth — target > {{ config.min_word_count }} words
{% if not wc_ok %}
Fix: Add more content. Thin pages (under {{ config.min_word_count }} words) struggle to rank. Cover the topic thoroughly — answer the user's full intent, not just part of it.
{% endif %}
{{ data.words }}
words
{# ── Duplicate Content ─── #} {% set dup = data.has_duplicate_content %}
Duplicate Content
Identical content dilutes ranking authority across pages
{% if dup and data.duplicate_with %}
Shares identical content with:
{% for dup_url in data.duplicate_with %} {% endfor %}
Fix: Add a canonical tag pointing to the preferred URL, or differentiate the page content. Avoid publishing the same text on multiple URLs.
{% endif %}
{{ 'DUPLICATE' if dup else 'UNIQUE' }}

Performance & Delivery

Core Web Vitals signals — slow or bloated pages rank lower on mobile-first index.

{# Load Time #} {% set lt_ok = data.load_time <= config.slow_page_threshold %}
Load Time
{{ data.load_time | round(2) }}s
Target < {{ config.slow_page_threshold }}s
{% if not lt_ok %}
Fix: Enable server-side compression, reduce image sizes, defer non-critical JS, and use a CDN.
{% endif %}
{# Page Size #} {% set ps_ok = data.size <= config.max_page_size_bytes %}
Page Size
{{ (data.size / 1024) | round(1) }} KB
Max 2 MB recommended
{# URL Depth #} {% set ud_ok = data.depth <= 3 %}
URL Depth
{{ data.depth }}
Recommended ≤ 3 levels from root
{% if not ud_ok %}
Fix: Flatten your URL structure. Deep pages receive less PageRank and are crawled less frequently.
{% endif %}
{# Compression #} {% set cmp_ok = data.has_compression %}
Compression
{{ 'GZIP / BR' if cmp_ok else 'NONE' }}
HTTP transport encoding
{% if not cmp_ok %}
Fix: Enable gzip or brotli in your server config (nginx: gzip on; or Apache's mod_deflate).
{% endif %}
{# Cache-Control #} {% set cc_ok = data.has_cache_control %}
Cache-Control
{{ 'CONFIGURED' if cc_ok else 'MISSING' }}
Browser caching header
{% if not cc_ok %}
Fix: Add Cache-Control: public, max-age=3600 to your server response headers.
{% endif %}
{# Broken Images #} {% set bi_count = data.broken_images_count or 0 %} {% set bi_ok = bi_count == 0 %}
Broken Images
{{ bi_count ~ ' BROKEN' if not bi_ok else 'ALL OK' }}
Image resource health
{% if not bi_ok %}
Fix: {{ bi_count }} image(s) returned a 4xx/5xx error. Update or remove the broken src URLs.
{% endif %}

Rich Results & Social

Schema boosts CTR through rich snippets. Open Graph controls how your page appears when shared.

{# Schema #} {% set sc_ok = data.has_schema %}
Schema / JSON-LD
Structured data for rich snippets in search results
{% if sc_ok %}
{{ data.jsonld }}
{% else %}
Opportunity: Add JSON-LD schema (Article, Product, FAQ, BreadcrumbList) to qualify for Google rich snippets, which improve CTR by 20–30%.
{% endif %}
{{ 'PRESENT' if sc_ok else 'MISSING' }}
{# Canonical #}
Canonical URL
Tells Google the preferred version of this page
{% if data.canonical %}
{{ data.canonical }}
{% else %}
Consider adding: A self-referencing canonical tag prevents duplicate content issues if this page is accessible via multiple URLs.
{% endif %}
{{ 'NONE' if not data.canonical else 'SET' }}
Open Graph Preview
How this page appears on Facebook, LinkedIn, Twitter/X
{{ 'OPTIMIZED' if data.og_title else 'MISSING' }}
{% if data.og_image %} OG Image {% else %}
No OG Image set
{% endif %}
{{ url.split('/')[2] if url.split('/')|length > 2 else 'example.com' }}
{{ data.og_title if data.og_title else (data.title if data.title else '⚠️ No title set') }}
{{ data.og_desc if data.og_desc else (data.meta_desc if data.meta_desc else '⚠️ No description set') }}
{% if not data.og_title %}
Fix: Add <meta property="og:title">, og:description, and og:image tags in your <head> to control how this page looks when shared on social media.
{% endif %}
{% if data.issues %}

Issues Found

{{ data.issues|length }} optimization point{% if data.issues|length != 1 %}s{% endif %} identified on this page.

{% for issue in data.issues %}
{{ issue }} Details
{% endfor %}
{% endif %}