1,204 escrows openHeld volume $2.4MMedian payout 4 minDispute rate 1.9%

Pre-publish check

Find the reason a page will not index, before you ship it.

This fetches every public route from the running server, reads the head it actually renders, and applies one rule pass. Findings are deterministic. The model only writes the fix.

Rule reference

Every finding above is produced by one of these rules. Each entry states the exact condition evaluated against the server-rendered HTML, so a finding can always be traced back to a rule rather than an opinion.

Reachability

Whether a crawler can retrieve and is allowed to index this URL at all.

Document returns 200

blockerhttp.status
Why it matters.
A non-200 response is never added to the index, so every other tag on the page is irrelevant until this is fixed. Crawlers also back off from hosts that answer with errors.
What the rule checks.
The response status of the server-rendered document is not 200.
Fix.
Make the route render for an anonymous visitor. Routes that legitimately require a session should be removed from auditablePaths() instead of made public.
Google: HTTP status codes and indexing

Document is reachable

blockerfetch.failed
Why it matters.
If the audit cannot fetch the page over HTTP, a crawler cannot either. This is usually a server crash during SSR rather than a metadata problem.
What the rule checks.
The fetch for this path threw before a response arrived.
Fix.
Open the path directly and read the server error. SSR crashes are commonly caused by browser-only APIs running at module or render time.
Google: HTTP status codes and indexing

No noindex directive

blockerrobots.noindex
Why it matters.
A noindex directive removes the page from search entirely, even when everything else is correct. It is the single most common cause of a page that will not appear.
What the rule checks.
A robots meta tag on this page contains noindex.
Fix.
Remove the robots meta entry from this route's head(). Keep noindex only on routes you deliberately hide, and never place it in __root.tsx where it applies sitewide.
Google: robots meta tags

Title

The clickable line in results and the strongest relevance signal.

Title present

blockertitle.missing
Why it matters.
The title is the strongest on-page relevance signal and the clickable line in results. With none, the crawler falls back to the parent route's title and every page looks identical in search.
What the rule checks.
No <title> element in the server-rendered head.
Fix.
Add a { title: "…" } entry to the meta array of this route's head(). A top-level title field on head() is silently ignored.
Google: title links

Title is not a template default

blockertitle.default
Why it matters.
A generator's placeholder title tells both crawlers and visitors that the page was never finished, and it is identical across thousands of other sites.
What the rule checks.
Title matches a known template default such as "Lovable App".
Fix.
Replace it with a page-specific title in this route's head().
Google: title links

Title fits the result

warningtitle.length
Why it matters.
Results truncate around 60 characters, so anything past that is invisible at the moment of the click and may push the distinguishing words off the end.
What the rule checks.
Title length is over 60 characters.
Fix.
Move the brand suffix to the end and drop filler words. Lead with the words a visitor would actually type.
Google: title links

Title is specific

warningtitle.short
Why it matters.
A very short title usually names a section rather than a page, which gives the crawler almost nothing to match a query against.
What the rule checks.
Title length is under 15 characters.
Fix.
Say what the page contains and for whom, then append the brand.
Google: title links

Description

Who writes the snippet under the result: you, or the crawler.

Meta description present

blockerdescription.missing
Why it matters.
Without one, the search snippet is assembled from whatever body text the crawler picks, which is often navigation or legal boilerplate rather than your pitch.
What the rule checks.
No <meta name="description"> in the server-rendered head.
Fix.
Add { name: "description", content: "…" } to this route's head() meta array.
Google: snippets and meta descriptions

Description fits the snippet

warningdescription.length
Why it matters.
Snippets cut off near 160 characters, usually mid-sentence, so a long description ends in an ellipsis instead of a reason to click.
What the rule checks.
Meta description is over 160 characters.
Fix.
Cut to one sentence that names the page's concrete payoff.
Google: snippets and meta descriptions

Description says enough

notedescription.short
Why it matters.
A very short description leaves most of the snippet empty, so the crawler often ignores it and writes its own instead.
What the rule checks.
Meta description is under 50 characters.
Fix.
Extend to roughly 110-155 characters with specifics rather than adjectives.
Google: snippets and meta descriptions

URL identity

Which URL this page claims to be, so signals are not split.

Canonical declared

warningcanonical.missing
Why it matters.
Query strings, trailing slashes, and preview hosts create several URLs for one page. With no canonical, the crawler picks one itself and may split ranking signals across the variants.
What the rule checks.
No <link rel="canonical"> in the server-rendered head.
Fix.
Add a links: [{ rel: "canonical", href: "…" }] entry to this leaf route's head(). Keep it on leaf routes only — router concatenates links, so a root canonical would emit a second one.
Google: canonicalization

Canonical self-references

blockercanonical.homepage
Why it matters.
A canonical pointing at the homepage tells crawlers this page is the homepage, so its own title, description, and preview image are discarded and the URL usually drops out of results.
What the rule checks.
The canonical href resolves to the site root while the audited path is not the root.
Fix.
Point canonical and og:url at this route's own URL.
Google: canonicalization

Document structure

The heading outline and image semantics both crawlers and screen readers use.

Exactly one h1 — present

warningh1.missing
Why it matters.
The h1 is the in-page statement of topic and the first landmark assistive technology reads. Its absence leaves the document outline headless.
What the rule checks.
No <h1> element in the rendered body.
Fix.
Promote the page's opening headline to <h1>. Section headings stay at <h2>.
Google: SEO starter guide, headings

Exactly one h1 — not repeated

warningh1.multiple
Why it matters.
Several h1 elements make the primary topic ambiguous and flatten the heading hierarchy screen readers use to navigate.
What the rule checks.
More than one <h1> element in the rendered body.
Fix.
Keep one <h1> per route and demote the rest to <h2>. Watch for shared layout components that emit their own <h1>.
Google: SEO starter guide, headings

Images carry alt text

warningimg.alt
Why it matters.
An image with no alt attribute is unreadable to screen readers and uncategorisable in image search. Decorative images still need alt="" so they can be skipped deliberately.
What the rule checks.
One or more <img> elements in the body have no alt attribute at all.
Fix.
Describe what the image shows, or set alt="" when it is purely decorative.
Google: image SEO best practices

Link previews

What a shared link looks like outside search engines.

og:title present

warningog.title
Why it matters.
Chat apps and social platforms read og:title, not <title>. Without it every shared link from this site shows the same sitewide default headline.
What the rule checks.
No og:title among the head's meta tags.
Fix.
Add { property: "og:title", content: "…" } to this route's head() meta array.
The Open Graph protocol

og:description present

noteog.description
Why it matters.
Link previews fall back to the meta description or to nothing, which usually means a share card with a headline and empty body.
What the rule checks.
No og:description among the head's meta tags.
Fix.
Add { property: "og:description", content: "…" } alongside og:title.
The Open Graph protocol

Content and markup depth

Whether there is enough server-rendered substance to rank and to parse.

Page has substantive content

warningcontent.thin
Why it matters.
A page whose server-rendered text is mostly chrome gives the crawler little to rank and reads as a placeholder. It also hints that the real content is client-rendered and may never be seen.
What the rule checks.
Under roughly 120 words of server-rendered text in the body.
Fix.
Render the page's primary content on the server rather than after hydration, and add the specifics a visitor came for.
Google: creating helpful content

Structured data present

notejsonld.missing
Why it matters.
JSON-LD is how a page becomes eligible for rich results and how machine readers learn what the entity is. Its absence costs eligibility, not indexing.
What the rule checks.
No "@type" key found in any JSON-LD block on the page.
Fix.
Add a scripts: [{ type: "application/ld+json", children: JSON.stringify(…) }] entry to head(), matching the page type — Product for listings, Article for posts, WebSite at the root.
Google: structured data introduction

Delivery

How fast the document reaches the crawler.

Server responds promptly

noteperf.ttfb
Why it matters.
Slow documents reduce how many pages a crawler fetches per visit and delay the first paint for real visitors. It is a budget problem more than a ranking one.
What the rule checks.
The server-rendered document took over 1200ms to arrive.
Fix.
Move blocking work out of the loader, cache what is stable, and check for sequential awaits that could run in parallel.
web.dev: Time to First Byte