lintpage
~/github-action
github action - vercel previews - free

Catch a noindex, a blocked AI crawler or a broken OG tag on the preview deploy, before merge.

When Vercel reports a preview deployment ready, the LintPage GitHub Action audits its URL with 60 SEO checks and puts the findings on the pull request as check annotations and a job summary, not a bot comment. A critical finding fails the check run; warnings show up without blocking the merge. This site runs it on its own pull requests.

.github/workflows/lintpage.yml
name: LintPage
on: deployment_status

permissions:
  contents: read

jobs:
  audit:
    # Only a finished preview deployment made by Vercel. startsWith also
    # matches the per-project names Vercel uses when a repo has several.
    if: >-
      github.event.deployment_status.state == 'success' &&
      startsWith(github.event.deployment.environment, 'Preview') &&
      github.event.deployment_status.creator.login == 'vercel[bot]'
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: lintpage/action@v1
        with:
          # Used only if your previews are protected; skipped when unset.
          vercel-bypass-secret: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}

action: MIT, on GitHub - CLI: free on npm - no account, no API key

01 - what you get on every preview

A verdict, a score and every finding, in the job summary.

This is the job summary from one of this site's own pull requests: the action audited the Vercel preview of lintpage.com. The same findings appear as annotations on the pull request's checks.

GitHub Actions job summary from the LintPage action on a lintpage.com preview deployment: verdict Ready to ship, score 96, 0 critical, 2 warnings, 5 info, followed by a table of each finding with its severity, check and message.
Ready to ship, with two warnings: a canonical that points at the production domain, which every preview has, and the CORS header Vercel sends by default. Both can be turned off or downgraded in the config. See the action's own public runs.
02 - setup on vercel

One file, plus a secret if your previews are protected.

  1. Save the workflow above as .github/workflows/lintpage.yml. Vercel reports each deployment to GitHub, and the workflow runs when a preview is ready, against that preview's URL.
  2. If your project uses Vercel Deployment Protection, previews redirect to the Vercel login page, and the audit fails with a critical finding that says so. In Vercel, open the project's Settings, then Deployment Protection, and create a Protection Bypass for Automation secret. In GitHub, add it as a repository secret named VERCEL_AUTOMATION_BYPASS_SECRET. If Deployment Protection is off, skip this step; an unset secret is ignored.
  3. Open a pull request. When the preview is up, a LintPage check appears on it.
03 - what it catches

The mistakes a code review does not see.

None of these break a build or a test. They break what search engines, AI assistants and link previews see, usually after someone has already merged.

Noindex that slipped through

A robots meta tag or X-Robots-Tag header that keeps the page out of search. On a *.vercel.app URL, the noindex header Vercel adds to preview deployments is reported as info, so it does not drown out a real one.

  • robots-noindex
  • x-robots-tag

Blocked AI crawlers

GPTBot, ClaudeBot or PerplexityBot getting a 403, 429 or server error even though robots.txt lets them in. ChatGPT-User, Claude-User or Perplexity-User blocked by robots.txt or at the edge. A near-empty page served to bots instead of the real one.

  • ai/gptbot-silent-block
  • ai/chatgpt-user-blocked
  • ai/empty-content-to-bot

which crawlers are checked

Broken share previews

A missing og:image, og:title or og:url; image width and height tags that are missing or below the recommended 1200x630; an image type other than JPEG, PNG, GIF or WebP; a Twitter card with no image.

  • og-image
  • og-image-size
  • og-image-type
  • twitter-image

Canonicals and redirects

A canonical tag that is missing, relative or points at another domain, or a page that redirects to another host, such as the Vercel login page, which is reported instead of auditing the wrong page.

  • canonical-url
  • canonical-self-referencing
  • redirected-off-site

Titles and descriptions

Missing or badly sized titles and meta descriptions, and a duplicated title, description or canonical tag: the things a refactor of the layout component quietly breaks.

  • title
  • meta-description
  • duplicate-meta

Plus structured data, headings, accessibility, security headers and performance hints: 60 checks in all.

see every check

04 - not on vercel

Any public URL.

On Netlify, Cloudflare Pages, Render or your own servers, list the pages in urls: a staging site, production, or the URL an earlier deploy step printed. Each URL is audited separately, and the check fails if any of them has a critical finding.

.github/workflows/lintpage.yml
name: LintPage
on: pull_request

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: lintpage/action@v1
        with:
          urls: 'https://staging.example.com https://staging.example.com/pricing'
05 - before you push

The same checks on localhost.

The action installs the LintPage CLI, which also runs on your own machine against your dev server, in a pre-commit hook or by hand:

npx lintpage localhost:3000

Checks that need a public address run on the preview instead. What runs on localhost, and what does not.

06 - inputs and outputs

Everything you can set.

All inputs are optional. The README on GitHub has the full reference, examples and the notes for each release.

inputwhat it doesdefault
urlsURLs to audit, separated by spaces or newlines.The deployment URL from the deployment_status event
vercel-bypass-secretVercel Protection Bypass for Automation secret, from a GitHub secret.None
fail-on-warningFail the check on warnings too, not only on critical findings.false
configPath to a LintPage config file in the checked-out repository..lintpagerc.json, .lintpagerc or lintpage.config.json
quietOnly the verdict, notices and failing annotations.false
versionThe lintpage CLI version to install, or latest.Pinned; raised by action releases
outputwhat it holds
auditedNumber of URLs audited.
exit-codeWorst result across all URLs: 0 pass, 1 findings that fail the check run, 2 an error or a URL that was skipped.
07 - faq

Questions, answered.

Is it safe to give the action my Vercel bypass secret? +
The secret reaches the CLI through its environment, never on a command line, and neither the action nor the CLI prints it. It is sent as the x-vercel-protection-bypass header only to the https *.vercel.app URLs the action audits, and only to that exact origin: not to other sites the audit contacts, and not along a redirect to another host. Pass it from secrets, as in the workflow above, so GitHub masks it in logs.
How is this different from Lighthouse's SEO score? +
Lighthouse's SEO category checks indexability (robots meta tag, X-Robots-Tag header, robots.txt), status code, title, meta description, canonical, hreflang, crawlable links, link text and image alt. LintPage covers most of that, though not link text, and its robots.txt check looks for a site-wide block rather than one on this page's path. It adds what Lighthouse does not check: Open Graph and Twitter card tags, whether GPTBot and ClaudeBot can actually fetch the page, a redirect to another host such as a login wall, and structured data validation, which Lighthouse leaves as a manual item. It also reads your Vercel bypass secret for you and reports on the pull request's checks. The two work fine side by side.
What fails the check, and what only warns? +
A critical finding fails the LintPage check run. Warnings and info show up in the job summary and as annotations, without failing it, unless you set fail-on-warning. GitHub caps how many annotations one step can show, so the run log has the full list. Preview deployments often get a canonical-self-referencing warning because their canonical tag points at your production domain, so think about that before turning fail-on-warning on for previews.
Does it run my JavaScript, like a browser? +
No. It reads the HTML your server sends, which is what most crawlers see first, and does not run the page scripts. A noindex, title or Open Graph tag added only in the browser is not seen, which is also why server-rendered meta tags are the safe choice. Next.js renders them on the server by default.
Can I change which checks run, or how severe they are? +
Yes, with a config file in your repository: turn a check off, or set its severity. Run npx lintpage init to generate one, and add actions/checkout before the action so it can read the file. A missing or invalid config falls back to the default checks.
What does it cost? +
Nothing. The action is MIT and on GitHub. The CLI it installs is free on npm; its source is not public. There is no account and no API key. It runs on your own GitHub Actions minutes, typically for under a minute per deployment.
Does it audit production deployments too? +
The workflow above audits previews only. Remove the environment condition to audit every deployment Vercel reports. Vercel adds a noindex header to preview deployments, so to check the indexing of your live site, audit your production domain with the urls input.
Why is the CLI version pinned? +
So a new CLI release cannot change your results without you knowing. When an action release raises the pin, its release notes say so and what changed. @v1 always points at the newest v1 release. Set version to latest to track the newest CLI, or to a specific version to stay on it.
one file - no account - free

Put it on your next pull request.

Copy the workflow, push it, and the next preview gets audited.

GitHub Marketplace

rather try it on one page first? run a free audit