This guide covers the SEOLint API in GitHub Actions. For a broader setup including Core Web Vitals thresholds and PageSpeed Insights, see How to Check Core Web Vitals in GitHub Actions.
The API flow
The SEOLint API fits into any CI step in three calls:
POST /api/v1/scanStart a scan, get back scanId and pollUrlGET pollUrlPoll every 3s until status is completeRead issues[]Each issue has severity: critical | warning | info
Minimal workflow
Add to .github/workflows/seo-check.yml. Set SITE_URL as a repository variable.
name: SEO Audit
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
seo-audit:
runs-on: ubuntu-latest
steps:
- name: Start scan
id: scan
run: |
RESPONSE=$(curl -s -X POST https://seolint.dev/api/v1/scan \
-H "Content-Type: application/json" \
-d '{"url": "${{ vars.SITE_URL }}"}')
echo "scan_id=$(echo $RESPONSE | jq -r '.scanId')" >> $GITHUB_OUTPUT
echo "poll_url=$(echo $RESPONSE | jq -r '.pollUrl')" >> $GITHUB_OUTPUT
- name: Wait for results
id: results
run: |
POLL_URL="${{ steps.scan.outputs.poll_url }}"
for i in $(seq 1 20); do
STATUS=$(curl -s "$POLL_URL" | jq -r '.status')
[ "$STATUS" = "complete" ] && break
sleep 3
done
- name: Fail on critical issues
run: |
CRITICAL=$(curl -s "${{ steps.scan.outputs.poll_url }}" \
| jq '[.issues[] | select(.severity == "critical")] | length')
if [ "$CRITICAL" -gt "0" ]; then
curl -s "${{ steps.scan.outputs.poll_url }}" \
| jq -r '.issues[] | select(.severity == "critical") | "❌ " + .title'
exit 1
fi
echo "✅ No critical SEO issues"What gets checked
| Check | Severity |
|---|---|
| Missing title tag | critical |
| Missing H1 | critical |
| Missing canonical URL | critical |
| LCP > 2.5s | critical |
| Images missing alt text | warning |
| Missing Open Graph tags | warning |
| Meta description > 160 chars | warning |
| Missing robots meta | info |
Auto-open a GitHub issue
Add this step after the failure check. It opens an issue with the full markdown report attached.
- name: Open issue with report
if: failure()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
MARKDOWN=$(curl -s "${{ steps.scan.outputs.poll_url }}/markdown")
gh issue create \
--title "SEO regression: $(date +%Y-%m-%d)" \
--body "$MARKDOWN" \
--label "seo"The /markdown endpoint returns structured fix instructions, including JSON-LD suggestions that align with Google's structured data guidelines. Paste the issue body into Claude or Cursor to apply the fixes automatically.
FAQ
Can I run SEO checks in GitHub Actions?
Yes. POST a URL to the SEOLint API, poll for results, and fail the workflow if critical issues are found. All from a standard GitHub Actions step.
What SEO issues does automated monitoring catch?
Missing title tags, missing H1, broken canonical URLs, images without alt text, missing Open Graph tags, and Core Web Vital regressions.
What plan do I need for API access?
The SEOLint plan ($79/month, one site under agent watch) includes REST API access and GitHub Actions integration. 200 AI credits/month bundled in covers a typical CI loop, and you can connect your own Claude key to skip the credit cap entirely. Teams running many sites can email us for the Custom plan with volume pricing.
Related reading
Add SEO monitoring to your pipeline
Takes 5 minutes. SEOLint ($79/month) required for API access.
