Add SEO Checks to Your CI/CD Pipeline

Every deployment is a chance to accidentally break SEO. A developer removes a canonical tag, a build step strips meta descriptions, a config change adds noindex to production — and you don't find out until rankings drop weeks later. The fix is treating SEO like any other quality gate: run checks on every deployment and fail the build if something critical breaks.

Why Do SEO Checks Belong in CI/CD?

SEO regressions are invisible at deploy time. Unlike a broken API endpoint or a failing unit test, a missing <title> tag or an accidental noindex directive has no immediate error signal — it silently degrades over days or weeks as search engines recrawl and update their indexes. By the time rankings drop, the causal commit is buried under dozens of subsequent changes.

CI/CD SEO checks create the same feedback loop you have for code quality: if a deployment introduces an SEO regression, the pipeline fails, the developer sees the issue immediately, and it never reaches production.

Which Checks Matter Most in a Pipeline?

Not all 54 audit checks are equally critical at deploy time. These are the high-priority checks that justify a build failure:

Check Why it matters Failure threshold
Meta title Missing or empty title tanks click-through rate Must be present
Meta description Direct impact on SERP snippet quality Must be present
Canonical tag Duplicate content and indexation issues Must be present
Noindex directive Accidentally blocking pages from Google Must not be set on key pages
HTTPS Required for ranking; marks page as insecure Must pass
Overall score Composite health indicator Define your own threshold (e.g., ≥ 70)

GitHub Actions Workflow

Add this workflow to .github/workflows/seo-check.yml:

name: SEO Quality Gate

on:
  deployment_status:
  push:
    branches: [main]

jobs:
  seo-audit:
    runs-on: ubuntu-latest
    if: github.event.deployment_status.state == 'success' || github.event_name == 'push'

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install SEO Score API SDK
        run: pip install seoscoreapi

      - name: Run SEO audit
        env:
          SEO_API_KEY: ${{ secrets.SEO_API_KEY }}
          AUDIT_URL: "https://your-production-site.com"
          SCORE_THRESHOLD: "70"
        run: |
          python - <<'EOF'
          import os, sys
          from seoscoreapi import audit

          result = audit(os.environ["AUDIT_URL"], api_key=os.environ["SEO_API_KEY"])
          score = result["score"]
          grade = result["grade"]
          threshold = int(os.environ["SCORE_THRESHOLD"])

          print(f"SEO Score: {score}/100 ({grade})")

          failures = []
          checks = result.get("audit", {})

          if checks.get("meta", {}).get("title") == "fail":
              failures.append("CRITICAL: Missing meta title")
          if checks.get("meta", {}).get("description") == "fail":
              failures.append("CRITICAL: Missing meta description")
          if checks.get("meta", {}).get("canonical") == "fail":
              failures.append("CRITICAL: Missing canonical tag")
          if score < threshold:
              failures.append(f"Score {score} is below threshold {threshold}")

          if failures:
              print("\nSEO Quality Gate FAILED:")
              for f in failures:
                  print(f"  - {f}")
              sys.exit(1)
          else:
              print("SEO Quality Gate PASSED")
          EOF

Store your API key as a GitHub Actions secret: Settings > Secrets and variables > Actions > New repository secret named SEO_API_KEY.

How to Fail a Build If Score Drops Below a Threshold

The pattern above uses sys.exit(1) to signal failure to the CI runner. Choose your threshold based on your baseline:

  • 70 — reasonable starting point for most sites
  • 80 — appropriate for established sites where any regression is significant
  • Custom — run an initial audit, note your current score, then set the threshold 5–10 points below it

To track score over time, write the result to a GitHub Actions output or post it as a PR comment using the GitHub API:

import os, json, urllib.request

score = result["score"]
comment = f"SEO Score: **{score}/100** ({result['grade']})"

pr_number = os.environ.get("PR_NUMBER")
if pr_number:
    data = json.dumps({"body": comment}).encode()
    req = urllib.request.Request(
        f"https://api.github.com/repos/{os.environ['GITHUB_REPOSITORY']}/issues/{pr_number}/comments",
        data=data,
        headers={"Authorization": f"token {os.environ['GITHUB_TOKEN']}", "Content-Type": "application/json"}
    )
    urllib.request.urlopen(req)

GitLab CI Example

Add to .gitlab-ci.yml:

seo-audit:
  stage: test
  image: python:3.11-slim
  script:
    - pip install seoscoreapi
    - |
      python - <<'EOF'
      import os, sys
      from seoscoreapi import audit

      result = audit("https://your-site.com", api_key=os.environ["SEO_API_KEY"])
      print(f"Score: {result['score']}/100 ({result['grade']})")

      if result["score"] < 70:
          print(f"FAIL: Score {result['score']} is below threshold 70")
          sys.exit(1)
      print("PASS: SEO quality gate cleared")
      EOF
  variables:
    SEO_API_KEY: $SEO_API_KEY
  only:
    - main
    - merge_requests

Set SEO_API_KEY in Settings > CI/CD > Variables in your GitLab project.

Python Script for Custom Pipelines

For non-GitHub/GitLab pipelines (Jenkins, CircleCI, Bitbucket Pipelines, or a local pre-deploy hook):

#!/usr/bin/env python3
"""seo_gate.py — run before any deployment to catch SEO regressions."""

import sys
import os
from seoscoreapi import audit

AUDIT_URL = os.environ.get("AUDIT_URL", "https://your-site.com")
API_KEY = os.environ["SEO_API_KEY"]
THRESHOLD = int(os.environ.get("SCORE_THRESHOLD", "70"))

result = audit(AUDIT_URL, api_key=API_KEY)
score = result["score"]
grade = result["grade"]
priorities = result.get("priorities", [])

print(f"\nSEO Audit: {AUDIT_URL}")
print(f"Score: {score}/100 ({grade})")

critical_issues = [p for p in priorities if p["severity"] == "critical"]

if critical_issues:
    print(f"\n{len(critical_issues)} critical issue(s) found:")
    for issue in critical_issues:
        print(f"  - {issue['issue']}")

if score < THRESHOLD or critical_issues:
    print(f"\nSEO Quality Gate: FAILED")
    sys.exit(1)

print(f"\nSEO Quality Gate: PASSED")
sys.exit(0)

Run it as a pipeline step: SEO_API_KEY=your_key python seo_gate.py

Get Started

  1. Get a free API key — 5 audits/day, no credit card required
  2. Add the workflow YAML to your repo
  3. Set SEO_API_KEY as a pipeline secret
  4. Push to main and watch the quality gate run

For teams running audits on every PR across multiple environments, the Basic plan ($15/mo) gives you 1,000 audits/month at 30 RPM.


Frequently Asked Questions

Why should SEO checks run in CI/CD rather than on a schedule?

Scheduled audits tell you that something broke — CI/CD checks tell you which deployment broke it. Running checks at deploy time means you catch regressions in the same pull request that introduced them, before they ever reach production and before any search engine recrawls the affected pages.

Which SEO checks are most important to fail a build on?

Fail the build on missing meta title, missing meta description, missing canonical tag, and any noindex directive on pages that should be indexed. These are high-impact, unambiguous regressions. Use a score threshold (e.g., ≥ 70) as a secondary gate to catch broader degradation across multiple minor issues.

How do you set up the SEO audit GitHub Action?

Add a workflow file to .github/workflows/seo-check.yml with a Python step that installs seoscoreapi, runs audit() against your production URL, checks for critical failures, and calls sys.exit(1) if any are found. Store your API key as a GitHub Actions secret named SEO_API_KEY.

Does the SEO audit check a staging URL or the live site?

You can audit either. For catching regressions before they go live, point the audit at your staging or preview URL after deployment but before promoting to production. For production monitoring, audit the live URL as a post-deploy verification step.

How many API calls does a CI/CD pipeline use?

Each audit call counts as one request against your monthly quota. A team pushing to main once a day uses about 30 audits/month — well within the free tier. If you audit on every PR (e.g., 10 PRs/day), the Starter plan at $5/mo (200 audits/month) covers most teams comfortably.