On-Page SEO Analyzer

Paste a page's HTML to check 30 on-page items — title, description, headings, canonical, robots, alt text, Open Graph and JSON-LD — with the score formula shown.

Runs in your browser

Paste a page's HTML to check 30 items. Nothing leaves your browser — it is only kept in this browser — so unpublished and staging pages work too.

  1. Open the page you want to check in your browser.
  2. Press Ctrl+U (⌘⌥U on macOS) to view its source.
  3. Press Ctrl+A then Ctrl+C, and paste it below.

Used to compare the canonical link, og:url and hreflang against where the page will actually live.

What you paste never leaves your browser. It is kept in this browser only so a reload does not lose it — “Clear” removes it immediately.

The example has problems planted on purpose, so you can see what a report looks like.

Paste a page’s HTML above and the report appears here.

What an on-page check can and cannot tell you

This tool reads one HTML document. Everything it reports comes from that document: the title, the meta tags, the heading outline, the links and images written in the markup, the Open Graph set and the JSON-LD blocks. That is the majority of what "on-page SEO" means, and it is the part you fully control.

What it cannot see is anything that lives outside the file. Response time and Core Web Vitals, TLS certificates and security headers, redirect chains and HTTP status codes, the actual robots.txt and sitemap.xml, duplicate content across the site, the internal link graph, real image file sizes, backlinks, rankings and search volume — none of those are in the HTML, and a browser cannot fetch them from another site for you.

Tools that do report those numbers run a server-side crawler, which is also why they cap you at five checks a day and ask for an email. The trade is honest in both directions: they see more, we have no limit, no queue, and no upload.

How to get the HTML of a page

The fastest route is view-source. Open the page, press Ctrl+U (⌘⌥U on macOS), select all, copy. That gives you exactly what the server sent — the same bytes a crawler receives — which is what you want to audit.

For a page you have not deployed, use the file the framework produced (build output, or Save Page As → "Webpage, HTML only") or open the local address and view-source there. Staging behind Basic Auth, a CMS preview, a page behind a login: all of them work here, because you copy the source yourself instead of asking a crawler to reach it.

For a client-rendered app, view-source is nearly empty — the content is built by JavaScript after load. Open DevTools, switch to Elements, right-click the <html> node and choose Copy → Copy outerHTML. That gives you the rendered DOM, which is closer to what Google sees after rendering. This tool detects the empty-shell case and says so.

  • The URL tab in this tool asks your browser to fetch a page directly. It works only for sites that send permissive CORS headers, which is a small minority of the web. When it fails, the browser does not tell anyone whether it was CORS or the network — so we do not guess.

The checks that change what appears in search

Not all 30 items weigh the same. The heaviest are the ones that decide whether the page appears at all and what it looks like when it does: the robots meta (a stray noindex removes the page entirely), the title (weight 10), the meta description (8), the canonical link (6), the H1 (7) and the viewport (6).

Title and description are measured in pixels, not characters, because that is how Google truncates them — the desktop title link is cut near 600px at 20px Arial and the snippet near 920px at 14px. A title of 55 narrow letters fits; 45 capitals do not. Korean and Japanese titles fit about 30 characters because CJK glyphs are full-width.

The body-text check counts words differently for CJK: a Latin or numeric run is one word, and two CJK characters count as one word, because roughly 600 Hangul syllables carry what 300 English words carry. The 300-word line itself is a convention in the SEO industry, not a Google rule — treat a "thin" verdict as a prompt to read the page, not as a quota.

  • hreflang only works in pairs. Every language version must list every other version including itself; a set that omits the current page is often ignored wholesale.
  • A JSON-LD block that fails to parse earns nothing at all. One trailing comma disables the whole block, which is why the parse check is separate from the content checks.

Why Google rewrites your title

Google replaces the title link when it judges the <title> a poor match for the page, and it lists the situations: titles that are half empty or boilerplate, obsolete titles, inaccurate titles, micro-boilerplate repeated across a site, titles that do not make the main heading obvious, titles in a language different from the page, and titles that repeat the site name.

Several checks here map directly onto that list. A short title (under 200px) is the "half empty" case. A repeated word is the keyword-stuffed case. A missing or duplicated H1 is the "main heading not obvious" case. A missing html lang, or a lang that disagrees with the title's script, is the language mismatch case.

A rewrite is not a penalty and has nothing to do with ranking. But it takes the most visible line of your result out of your hands, so the fix is to remove the trigger: one distinct, accurate title per page that agrees with its H1 and its language.

How the score is calculated

Every check carries a published weight. A pass scores 1, a warning 0.5, a failure 0, and a check that does not apply is removed from both sides of the fraction — a page with no images is not punished for having no alt text. The score is 100 × Σ(weight × value) / Σ(weight of applicable checks), rounded, and the grade bands are 90 A, 75 B, 60 C, 40 D, below that F.

The total weight of all 28 scored checks is 125. The title carries 10, the robots meta and the H1 carry 7 each, the meta description carries 8, and small things like meta keywords carry 1. The full table is on this page, under the score — you can audit every point, which is the opposite of "200+ factors" with no published formula.

Two deliberate consequences. A page that is otherwise perfect but carries noindex still scores in the eighties, because the score measures on-page quality and not deployment readiness — that is why noindex is reported as a failure at the top of the list rather than as a zero. And a fragment of HTML gets no score at all, because with the head checks removed the number would mean nothing.

Checking a page before you deploy it

The moment to catch an SEO mistake is before it ships, and that is exactly the moment a crawler-based checker cannot help — the page has no public URL yet. Two mistakes are worth the check on their own: a noindex left over from the staging template, and a canonical still pointing at the staging host. Both are invisible in a browser and both remove the page from search.

A workable routine: run your build, open the generated HTML for the page you changed, paste it here, and read the failures. Then paste the previous version into the compare box to confirm you did not lose something while fixing something else — a template edit that fixes a title often drops an og:image at the same time.

For a team, export the result as Markdown and put it in the pull request. It is a short, specific list with the offending values attached, which reviews better than "please check SEO".

Client-rendered pages (React, Vue, Svelte SPAs)

If view-source shows only a <div id="root"></div> and a script tag, the HTML a crawler first receives contains none of your content. Google does render JavaScript, but rendering happens in a second pass with no guaranteed timing, and other consumers — social scrapers, Bing, AI crawlers, link previews — mostly do not render at all. A share on Slack or KakaoTalk reads the initial HTML, full stop.

This tool flags the empty-shell case and tells you to paste the rendered DOM instead, which shows what the page looks like after hydration. Both views are worth checking: the shell tells you what a non-rendering consumer sees, the rendered DOM tells you what Google eventually indexes.

The structural fix is to move the head tags to the server: server-side rendering, prerendering at build time, or at minimum a per-route title, description, canonical and Open Graph set emitted in the initial HTML. Frameworks all support this — SvelteKit prerender, Next.js metadata, Nuxt useSeoMeta — and it is the difference between a link preview that works and one that shows your app’s default title on every page.

What to fix first

  • First, anything that blocks indexing: a noindex robots meta, a canonical pointing somewhere else, a staging host in the canonical. These make every other item irrelevant.
  • Second, the two lines searchers actually read: the title and the meta description. They are the highest-weighted content items here and the only ones that change your result’s appearance directly.
  • Third, structure: one H1, an unbroken heading outline, a viewport meta, an html lang. These are cheap edits that affect accessibility as much as search.
  • Fourth, sharing and structured data: the four Open Graph tags, twitter:card, and a JSON-LD block that parses. A broken JSON-LD block is worth more attention than a missing one, because it looks done and earns nothing.
  • Last, the long tail: image alt text, width and height attributes, anchor text, rel="noopener". Individually small, collectively the difference between a B and an A.

How to use

  1. Open the page and view its source with Ctrl+U (Mac: ⌘⌥U).
  2. Select all, copy, and paste it into the box.
  3. Read the failures from the top. Fix anything that blocks indexing (noindex) first.
  4. Expand “why & how to fix” for the fix and the offending values.
  5. Paste the fixed HTML into the compare box to see how much the score moved.

FAQ

Why is there no URL input like other SEO checkers?

There is a URL tab, but the request comes from your own browser, so it only succeeds on the small minority of sites that send permissive CORS headers. Running a server-side crawler instead would mean daily limits, a queue and an email address — and it still could not reach an unpublished page, a staging host behind Basic Auth, or anything behind a login. Pasting the source is the price of having none of those limits.

Is a score of 100 the goal?

No. The score summarises what can be verified in this one document; it does not predict ranking. A single failure — a stray noindex, a canonical pointing at your staging host — matters far more than the difference between 88 and 100. Read the failure list from the top and treat the number as a progress bar, not a target.

Does the tool store the HTML I paste?

It is never sent to a server. It is kept in this browser’s localStorage so a reload does not lose your work, and the Clear button deletes it immediately. If the draft is sensitive, clear it when you are done — or use a private window, where the storage disappears with the window.

Why does my page score differently here than on another tool?

Because the item list and the weights differ, and most tools do not publish either. They also fold in things a server-side crawl can measure — speed, TLS, redirects — which no browser-only tool can see. Here all 28 scored checks and their weights are printed under the score, so you can recompute the number yourself and decide whether you agree with it.

Can I check a whole site at once?

No — crawling a site needs a server, and this site does not have one. Check page by page, but note that pages sharing a template usually share their problems too, so one representative page from each template normally surfaces everything worth fixing.

Related tools

More SEO & Web tools: SEO & Web

Send feedback

Found a bug or have an idea? Tell us — it helps make the tools better.

Only needed if you would like a reply.

Page: /seo/seo-analyzer/