For developers Vite · Astro · Next.js static export · any static output

Your site is called "Vite App" in Google. Fix it in one build step.

Headlark reads every HTML file your framework just built and writes the title, meta description, Open Graph and X cards, canonical, JSON-LD and missing alt text into it, before your host uploads it. Every crawler sees real tags, including the link previewers that never run JavaScript.

Free for one site and 25 pages. No credit card needed for the free plan. Or check your live site first, no account needed.

Install

Two lines. Then forget it exists.

npm i -D headlark

# package.json
"scripts": {
  "build": "vite build && headlark dist --site-url https://example.com"
}
  • Set HEADLARK_KEY to your site's secret key in the build environment (Vercel, Netlify, GitHub Actions, any CI).
  • Point it at your output folder. Vite and Astro build to dist; Next.js with output: "export" builds to out.
  • On Astro, npx astro add astro-headlark adds the integration instead. It takes the address from site in your config.
  • On Netlify, use the build plugin instead: one block in netlify.toml.
  • Add --strict if a page that can't be optimized should fail the build. Without it, that page is left untouched.
Why build time

Tags in the HTML, not added by a script later.

Facebook, LinkedIn, Slack and X read the raw HTML when they build a link preview. Tags a script adds in the browser are invisible to them. Headlark rewrites the files themselves, so what you deploy is what every crawler reads.

Rebuilds are free

Unchanged pages come from cache. Build timestamps, counters and other incidental changes don't count as content, so deploying ten times a day costs nothing.

Idempotent

Running it twice on the same output changes nothing. Headlark undoes its own tags before it applies new ones, so rebuilds converge.

Your choices win

An existing canonical, robots directive or JSON-LD type is kept. Headlark replaces generic titles and descriptions and fills in what's missing.

What it writes

Everything in the head, grounded in the page.

TagWhat you get
<title>30 to 60 characters, topic first, brand last.
meta descriptionA plain sentence of 70 to 155 characters about what the visitor gets.
Open Graph, X cardog:title, og:description, og:url, og:type and og:image (an image already on your page), plus twitter:card and friends.
JSON-LDOne to three schema.org objects that fit the content, such as SoftwareApplication, Article, Product or LocalBusiness, with only values found on the page.
canonical, robotsAdded only when missing. Error pages get noindex.
alt textFor images that have no alt, written from the page's context.
<html lang>Added when missing. Everything is written in the page's own language.

Prices, phone numbers, dates and emails in the output are checked against the page before they ship.

Good to know

Where it doesn't fit.

  • Server-rendered pages (SSR, ISR) have no HTML at build time. Prerender them, or use the deploy hook with the snippet (Google only).
  • Client-only SPAs give an empty shell. Prerender at build time first, then add the build step.
  • It doesn't create images. og:image points at the page's existing og:image or its most representative image.

Ship your next deploy with SEO.

Free tools to see where you stand: the site checker, SEO checker, structured data checker and llms.txt generator.

Guides for Vite, Astro, Next.js static export and Netlify.

Start free →