JSPM

easy-seo-checker

1.0.3
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 8
  • Score
    100M100P100Q37630F
  • License MIT

Client-side SEO page analyzer (browser-only): DOM analysis, scoring, and actionable suggestions.

Package Exports

  • easy-seo-checker
  • easy-seo-checker/react

Readme

easy-seo-checker

CI npm version MIT License Bundle Size

Lightweight client-side SEO analyzer for web pages.
Analyzes the rendered DOM, calculates an SEO score (0–100) with clear labels, and generates actionable suggestions β€” all directly in the browser with zero runtime dependencies.

Features

  • πŸ“Š SEO scoring (0–100) with clear labels
  • πŸ” DOM analysis for titles, meta tags, headings, images, links, and more
  • 🧠 Actionable SEO recommendations you can surface in UIs
  • ⚑ Zero runtime dependencies
  • 🌐 Browser-only (runs after page render)
  • βš›οΈ Optional React hook (easy-seo-checker/react)
  • 🎯 Ignore elements with [data-seo-ignore]
  • πŸ“¦ Small bundle size

Installation

npm install easy-seo-checker

That's it β€” the core library has zero runtime dependencies and works with any browser framework.

Framework Compatibility

The core entry (easy-seo-checker) is framework-agnostic. It works anywhere the browser DOM is available:

Framework Supported Entry point
Vanilla JS Yes easy-seo-checker
React Yes easy-seo-checker + optional easy-seo-checker/react hook
Angular Yes easy-seo-checker
Vue Yes easy-seo-checker
Svelte Yes easy-seo-checker
Next.js / Nuxt / Angular Universal Client-side only Call after mount, not during SSR
Node.js / Deno / Bun (server) No Requires browser DOM

The optional easy-seo-checker/react sub-path provides a useSeoPageAnalysis hook for React projects. React is listed as an optional peer dependency β€” non-React projects won't install or download it.

Quick Start

Vanilla / any framework

Run the analyzer after the page has rendered:

import { getSeoPageAnalysis, getScoreLabel } from "easy-seo-checker";

const result = getSeoPageAnalysis(window.location.pathname);

console.log("Score:", result.score);
console.log("Label:", getScoreLabel(result.score));
console.log("Suggestions:", result.recommendations);

With options

import { getSeoPageAnalysis } from "easy-seo-checker";

const result = getSeoPageAnalysis(window.location.pathname, {
  ignoreSelector: ".admin-panel, [data-seo-ignore]",
});

Angular

import { Component, AfterViewInit } from "@angular/core";
import { getSeoPageAnalysis, getScoreLabel } from "easy-seo-checker";

@Component({ selector: "app-seo", template: `<p>Score: {{ result?.score }}</p>` })
export class SeoComponent implements AfterViewInit {
  result: ReturnType<typeof getSeoPageAnalysis> | null = null;

  ngAfterViewInit() {
    this.result = getSeoPageAnalysis(window.location.pathname);
  }
}

Vue

<script setup>
import { ref, onMounted } from "vue";
import { getSeoPageAnalysis, getScoreLabel } from "easy-seo-checker";

const result = ref(null);
onMounted(() => {
  result.value = getSeoPageAnalysis(window.location.pathname);
});
</script>
<template>
  <p v-if="result">Score: {{ result.score }} – {{ getScoreLabel(result.score) }}</p>
</template>

Svelte

<script>
  import { onMount } from "svelte";
  import { getSeoPageAnalysis, getScoreLabel } from "easy-seo-checker";

  let result = null;
  onMount(() => {
    result = getSeoPageAnalysis(window.location.pathname);
  });
</script>

{#if result}
  <p>Score: {result.score} – {getScoreLabel(result.score)}</p>
{/if}

React (optional hook)

import { useEffect } from "react";
import { getScoreLabel } from "easy-seo-checker";
import { useSeoPageAnalysis } from "easy-seo-checker/react";

function SeoReviewPanel() {
  const pathname = typeof window !== "undefined" ? window.location.pathname : null;
  const { result, run, reset, loading, error } = useSeoPageAnalysis(pathname, {
    runOnMount: false,
  });

  useEffect(() => {
    if (!pathname) return;
    run();
  }, [pathname, run]);

  if (loading) return <p>Analyzing…</p>;
  if (error) return <p>Error: {error.message}</p>;
  if (!result) return <button onClick={run}>Run SEO analysis</button>;

  return (
    <div>
      <p>
        Score: {result.score} – {getScoreLabel(result.score)}
      </p>
      <ul>
        {result.recommendations.map((r, i) => (
          <li key={i}>{r}</li>
        ))}
      </ul>
      <button onClick={reset}>Clear</button>
    </div>
  );
}

Example Output

{
  score: 82,
  label: "Good",
  recommendations: [
    "Meta description is missing",
    "Add alt text to 3 images",
    "Consider adding structured data (JSON-LD)"
  ]
}

Browser Only

This package runs only in the browser because it relies on:

  • document
  • window
  • location

Do not run during SSR (Next.js, Nuxt, etc.).
Instead, run it after the page mounts (e.g. in useEffect, onMounted, ngAfterViewInit, onMount, etc.).

Ignore Selector

Elements with the attribute [data-seo-ignore] are excluded from analysis by default. Add this attribute to admin UI, modals, or chatbots you want excluded:

<div data-seo-ignore>
  <!-- This block is ignored by the analyzer -->
</div>

You can customize this via the ignoreSelector option or pass your own ignoreSelector when calling getSeoPageAnalysis.

API

Main entry (easy-seo-checker)

Export Description
getSeoPageAnalysis(pathname, options?) Full DOM analysis; returns SeoPageAnalysisResult
getMainContentRoot(ignoreSelector?) First main, article, or .content outside ignored containers
getPageParagraphs(ignoreSelector?) All <p> elements outside ignored containers
calculateSeoScore(result) Score 0–100 from a SeoAnalysisResult
generateSeoSuggestions(result) Suggestion strings from a SeoAnalysisResult
getScoreColor(score) Hex color string (e.g. "#16a34a" for green)
getScoreLabel(score) Label: "Excellent", "Good", "Needs Improvement", or "Poor"

Options

interface SeoAnalyzerOptions {
  /** CSS selector for elements to exclude. Default: "[data-seo-ignore]" */
  ignoreSelector?: string;
}

React entry (easy-seo-checker/react)

Export Description
useSeoPageAnalysis(pathname, options?) Returns { result, run, reset, loading, error }

Hook Options

interface UseSeoPageAnalysisOptions extends SeoAnalyzerOptions {
  /** Run analysis once when pathname is set. Default: false */
  runOnMount?: boolean;
}

Types

All types are exported from the main entry:

  • SeoAnalyzerOptions
  • SeoAnalysisResult
  • SeoPageAnalysisResult
  • SeoPageImagesResult
  • SeoPageKeywordsResult
  • SeoPageAiSignalsResult
  • SeoPageContentStructureResult
  • SeoPageKeywordDensityResult
  • SeoPageUrlSlugResult

Score Breakdown (100 points)

Category Points Criteria
Meta tags 30 Title present (10), title length 30–60 (5), description present (10), description length 120–160 (5)
Open Graph 20 og:title (5), og:description (5), og:image (5), twitter:card (5)
Headings 20 Single H1 (15) or multiple H1s (5), H2 present (5)
Images 15 Scaled by alt-text coverage; full marks if no images
Links 10 Internal links (5), external links (5)
Structured data 5 Valid JSON-LD present

Use Cases

  • SEO audit tools
  • CMS SEO panels
  • Browser extensions
  • Admin dashboards
  • Static site SEO validation
  • Content publishing workflows

Performance

The analyzer scans the rendered DOM once and is designed to be lightweight.

Typical runtime: <10β€―ms for most pages (depends on page size and device).

Browser Support

  • Chrome
  • Edge
  • Firefox
  • Safari

Requires modern DOM APIs.

SEO Score: 82 (Good)

βœ” Title tag present
βœ” H1 found
⚠ Missing meta description
⚠ 3 images missing alt text

You can build your own UI on top of SeoPageAnalysisResult to match your product.

Development

npm install        # Install dependencies
npm run dev        # Watch mode
npm run build      # Production build
npm test           # Run tests
npm run lint       # Run linter

See CONTRIBUTING.md for guidelines.

License

MIT β€” Akash Arora