Find what Lighthouse misses before your users do.
metaweave checks the things you usually discover after deploying:
a missing og:image, a favicon that 404s, a leftover
noindex, a robots.txt that blocks everything. One
command, 71 checks, plain-language fixes.
Built for the checks nobody remembers
Beyond LighthouseLighthouse is great at speed and basic SEO. It will not tell you that your share image is 404, your canonical points at localhost or your sitemap lists the staging domain.
Before productionPoint it at
localhost:3000 or a preview deploy. Checks that only
make sense on a live site are skipped for local servers, so you
don't get noise.
Fixes, not just flagsEvery finding says what is
wrong and how to fix it. metaweave explain tells you
why the check exists.
Install
metaweave is a single binary written in Rust. You need Rust 1.85 or newer.
# install straight from GitHub
cargo install --git https://github.com/nazimcanislam/metaweave
# or build from a clone
git clone https://github.com/nazimcanislam/metaweave
cd metaweave
cargo install --path .
Shell completions: metaweave completions bash (also
zsh, fish, powershell, elvish).
Usage
# check a live page, or your dev server (http is assumed for localhost)
metaweave https://example.com
metaweave localhost:3000
# several pages in one run; site-wide checks run once per origin
metaweave example.com example.com/pricing example.com/blog
# focus on some areas, or silence checks you don't care about
metaweave example.com --only seo,social,assets
metaweave example.com --skip links --ignore 'sec/*' -i seo/h1
# learn about a check
metaweave explain og-image
Options
| Option | What it does |
|---|---|
-f, --format |
text (default), json or
markdown
|
--only / --skip |
Comma-separated categories: seo,
social, a11y, perf,
sec, assets, links,
html
|
-i, --ignore |
Silence checks by id; prefixes like
sec/* work
|
--fail-on |
Exit with 1 at this severity or above:
error (default), warning,
info, never
|
--max-links |
How many links to verify (default 100) |
--timeout |
Per-request timeout in seconds (default 15) |
--insecure |
Accept self-signed certificates on dev or staging servers |
-v / -q |
List passed checks / show only errors and warnings |
--no-color |
Plain output; NO_COLOR is respected too
|
Exit codes
0 nothing at or above --fail-on ·
1 findings at or above it · 2 a page
could not be fetched or an argument was invalid.
What it checks
71 checks in eight categories. Each has an
id you can pass to --ignore or
metaweave explain. Checks that need extra requests
(icons, robots.txt, links…) run in parallel.
SEO8 checks
- seo/title
- Document has a <title> of a sensible length (10–60 chars)The title is the headline in search results and browser tabs; long titles get truncated.
- seo/description
- Meta description is present and 50–160 charsSearch engines use it as the result snippet; auto-generated ones are often poor.
- seo/canonical
- Canonical URL is declared, absolute and points at the right hostPrevents duplicate content and stops localhost/staging URLs from leaking into search.
- seo/h1
- Page has exactly one <h1>The h1 tells users and crawlers what the page is about.
- seo/indexable
- Page is not blocked from indexing (noindex)A leftover noindex from staging silently removes the page from search results.
- seo/structured-data
- JSON-LD structured data is present and valid JSONStructured data enables rich results (breadcrumbs, articles, products, FAQs).
- seo/viewport
- Responsive viewport meta tag is setWithout it mobile browsers render a zoomed-out desktop page; Google indexes mobile-first.
- seo/link-text
- Links use descriptive text (no “click here”)Generic link text carries no meaning for crawlers or screen-reader users.
Social previews10 checks
- social/og-title
- og:title is setIt is the headline of link previews on Facebook, LinkedIn, Slack, WhatsApp, Discord…
- social/og-description
- og:description is setIt provides the preview text shown under the title.
- social/og-image
- og:image is set to an absolute, public URLPosts without an image get far less attention; relative or localhost URLs can't be fetched by crawlers.
- social/og-image-alt
- og:image:alt describes the preview imageAlt text makes link previews accessible on platforms that support it.
- social/og-url
- og:url is set and matches the canonical URLIt tells platforms which URL to attribute likes and shares to.
- social/og-type
- og:type is setIt defines how the page is represented (website, article, product…).
- social/og-site-name
- og:site_name is setIt shows the brand name next to the preview on some platforms.
- social/og-image-reachable
- og:image URL is reachable and is an imageA 404 or HTML response means the preview card silently has no picture.
- social/og-image-size
- og:image has a suitable format and size (1200×630 recommended)Small or oddly shaped images are cropped, blurry or ignored; SVG is unsupported.
- social/twitter-card
- twitter:card is set to a valid valueX/Twitter needs twitter:card to render a rich preview; other tags fall back to Open Graph.
Accessibility13 checks
- a11y/lang
- <html> has a valid lang attributeScreen readers pick pronunciation rules from it; browsers use it for translation and hyphenation.
- a11y/img-alt
- Every <img> has an alt attributeWithout alt, screen readers read out the file name and blind users miss the content.
- a11y/link-name
- Every link has an accessible nameIcon-only or empty links are announced as just “link”.
- a11y/button-name
- Every button has an accessible nameUnlabelled buttons are unusable with a screen reader.
- a11y/form-label
- Every form field has a labelPlaceholders disappear and are not labels; unlabelled fields can't be identified by assistive tech.
- a11y/heading-order
- Headings are non-empty and do not skip levelsScreen-reader users navigate by headings; skipped levels break the outline.
- a11y/viewport-zoom
- Pinch-zoom is not disabledUsers with low vision rely on zooming.
- a11y/duplicate-id
- id attributes are uniqueDuplicate ids break label associations, anchors and ARIA references.
- a11y/landmarks
- Page has a <main> landmarkLandmarks let assistive-tech users jump straight to the content.
- a11y/iframe-title
- Every <iframe> has a titleThe title tells screen-reader users what the frame contains.
- a11y/video-captions
- Videos provide captions or subtitlesDeaf and hard-of-hearing users need captions (WCAG 1.2.2).
- a11y/tabindex
- No positive tabindex valuesPositive tabindex overrides the natural focus order and confuses keyboard users.
- a11y/skip-link
- A “skip to content” link is availableKeyboard users otherwise tab through the whole navigation on every page.
Performance11 checks
- perf/ttfb
- Server responds quickly (TTFB ≤ 600 ms)A slow first byte delays everything else, including Largest Contentful Paint.
- perf/html-size
- HTML document is lean (< 100 KB)Large HTML delays parsing and first render.
- perf/compression
- HTML is served compressed (gzip/brotli/zstd)Compression typically cuts text transfer by 70% or more.
- perf/redirects
- Page is reached without redirect chainsEach redirect adds a full round trip before content starts loading.
- perf/render-blocking
- Scripts in <head> are async, defer or modulesSynchronous scripts block HTML parsing and delay first paint.
- perf/img-dimensions
- Images declare width and heightWithout dimensions the layout jumps when images load (Cumulative Layout Shift).
- perf/img-lazy
- Below-the-fold images are lazy-loadedLazy loading saves bandwidth and speeds up the initial render.
- perf/img-format
- Modern image formats (WebP/AVIF/SVG) are usedWebP and AVIF are often 25–50% smaller than JPEG/PNG.
- perf/dom-size
- DOM is reasonably small (< 1500 elements)Large DOMs slow down style calculation, layout and memory use.
- perf/cache-headers
- Static assets have cache headersWithout caching, repeat visits re-download every file.
- perf/img-weight
- Images are reasonably sized (< 500 KB each)Oversized images are the most common cause of slow pages.
Security12 checks
- sec/https
- Site is served over HTTPS and http:// redirects to itHTTPS protects users and is required for many modern browser features.
- sec/hsts
- Strict-Transport-Security is set (max-age ≥ 6 months)HSTS prevents downgrade attacks by forcing HTTPS.
- sec/csp
- Content-Security-Policy is set and avoids unsafe-inlineCSP is the strongest defence against cross-site scripting.
- sec/nosniff
- X-Content-Type-Options: nosniff is setIt stops browsers from MIME-sniffing responses into executable types.
- sec/frame-protection
- Clickjacking protection (frame-ancestors / X-Frame-Options)It stops other sites from embedding your pages in invisible frames.
- sec/referrer-policy
- Referrer-Policy is setIt controls how much URL information leaks to other sites.
- sec/permissions-policy
- Permissions-Policy is setIt disables powerful features (camera, geolocation…) you don't use.
- sec/mixed-content
- No http:// subresources on HTTPS pagesBrowsers block or warn about mixed content, breaking images and scripts.
- sec/sri
- Third-party scripts and styles use Subresource IntegritySRI ensures a compromised CDN can't inject malicious code into your page.
- sec/target-blank
- target="_blank" links use rel="noopener"Older browsers give the opened page access to window.opener.
- sec/cookies
- Cookies set Secure, HttpOnly and SameSiteThese flags protect session cookies from theft and CSRF.
- sec/server-header
- Server headers don't reveal software versionsVersion banners help attackers target known vulnerabilities.
Site files & icons7 checks
- assets/favicon
- Favicon is declared and reachableA missing favicon shows a blank tab icon and fills server logs with 404s.
- assets/apple-touch-icon
- Apple touch icon (180×180) is availableIt is used when people add your site to the iOS home screen.
- assets/manifest
- Web app manifest is valid (name, 192/512 icons)It is needed for installable PWAs and good Android home-screen icons.
- assets/theme-color
- theme-color meta tag is setIt tints the browser UI on mobile to match your brand.
- assets/robots-txt
- robots.txt exists and doesn't block everythingA leftover “Disallow: /” from staging removes the whole site from search.
- assets/sitemap
- sitemap.xml exists, is valid and lists production URLsIt helps crawlers discover pages; wrong hosts mean staging URLs get indexed.
- assets/not-found-page
- Unknown URLs return a real 404 statusSoft 404s (200 on missing pages) confuse search engines and monitoring.
Links & resources5 checks
- links/internal
- Internal links resolve without errorsBroken links hurt users and SEO.
- links/external
- External links are aliveDead outbound links make a site look abandoned.
- links/resources
- Images, scripts and stylesheets loadA 404 resource means a broken layout or missing functionality.
- links/anchors
- #fragment links point to existing idsBroken in-page anchors silently do nothing.
- links/placeholder
- No placeholder links (href="#" or javascript:)They aren't real links: inaccessible, and they break middle-click and open-in-new-tab.
HTML hygiene5 checks
- html/status
- Page responds with a 2xx statusError pages are not indexed and usually indicate a broken deploy.
- html/doctype
- Document starts with <!DOCTYPE html>Without it browsers fall into quirks mode with inconsistent rendering.
- html/charset
- Character encoding is declared as UTF-8Otherwise special characters (ş, ğ, ü, é, emoji…) may render as garbage.
- html/deprecated
- No obsolete HTML elementsTags like font, center and marquee are unsupported or discouraged.
- html/meta-refresh
- No <meta http-equiv="refresh"> redirectsMeta refresh is slow and bad for accessibility and SEO.
Run it in CI
Fail the build when a preview deploy has errors, and put the Markdown report on the job summary:
- name: Check the preview deploy
run: |
metaweave "$PREVIEW_URL" -f markdown --fail-on error | tee -a "$GITHUB_STEP_SUMMARY"
Use -f json when you want to post-process the
results. Each finding has an id, a severity, a message and a fix.