SecurityHeaders.com API Migration Guide (2026)
The securityheaders.com API is shutting down in April 2026. If you have CI/CD pipelines, compliance scripts, or monitoring dashboards that call the securityheaders.com API, those integrations are about to break. This guide walks you through migrating to the DetectZeStack /security endpoint — step by step, with before/after examples you can copy-paste.
Time estimate: 5–15 minutes depending on how many scripts reference the old API. The endpoint URL, authentication, and response format all change, but the core workflow stays the same: send a URL, get a grade.
Step 1: Get Your API Key
DetectZeStack is available through RapidAPI. The free tier gives you 100 requests per month with no credit card required.
- Go to rapidapi.com/mlugoapx/api/detectzestack
- Click Subscribe to Test and select the Basic (free) plan
- Copy your API key from the X-RapidAPI-Key field in the code snippets panel
Store the key as an environment variable. You will reference it in all your scripts:
export RAPIDAPI_KEY="your-api-key-here"
Step 2: Update the Endpoint URL
Here is what the old securityheaders.com API call looked like:
Before: SecurityHeaders.com API
# Old securityheaders.com API (no longer working)
curl -s "https://securityheaders.com/?q=example.com&followRedirects=on" \
-H "x-api-key: YOUR_SECURITYHEADERS_KEY"
The securityheaders.com API returned the grade in an HTTP response header (X-Grade) and the body was HTML. Extracting structured data required parsing HTML or relying on undocumented response headers.
After: DetectZeStack API
# DetectZeStack /security endpoint
curl -s "https://detectzestack.p.rapidapi.com/security?url=example.com" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com"
The DetectZeStack API returns structured JSON in the response body. No HTML parsing. No undocumented headers. The grade, score, and per-header results are all explicit fields.
Step 3: Map the Response Format
Here is a side-by-side comparison of what you get back:
| Field | SecurityHeaders.com | DetectZeStack |
|---|---|---|
| Letter grade | X-Grade response header | grade (JSON field) |
| Numeric score | Not available | score (0–130) |
| Per-header results | Embedded in HTML body | tests object (JSON) |
| Response format | HTML | JSON |
| Scan timing | Not available | scan_time_ms (integer) |
| Cache indicator | Not available | cached (boolean) |
Here is the full JSON response from GET /security?url=example.com:
{
"url": "https://example.com",
"domain": "example.com",
"grade": "F",
"score": 15,
"max_score": 130,
"scan_time_ms": 287,
"cached": false,
"tests": {
"strict-transport-security": {
"pass": false,
"score_modifier": 0,
"result": "HSTS header missing",
"value": "",
"info": "No Strict-Transport-Security header found"
},
"content-security-policy": {
"pass": false,
"score_modifier": 0,
"result": "CSP header missing",
"value": "",
"info": "No Content-Security-Policy header found"
},
"x-frame-options": {
"pass": true,
"score_modifier": 15,
"result": "SAMEORIGIN",
"value": "SAMEORIGIN",
"info": "Clickjacking protection enabled"
},
"x-content-type-options": {
"pass": true,
"score_modifier": 15,
"result": "nosniff enabled",
"value": "nosniff",
"info": "MIME-type sniffing blocked"
}
}
}
Key difference: With securityheaders.com, you extracted the grade from an HTTP response header. With DetectZeStack, the grade is a JSON field in the response body. This is more reliable and easier to parse in any language.
Step 4: Update Your Parsing Logic
If your old script extracted the grade from securityheaders.com, here is how to update it:
Before: Parsing SecurityHeaders.com
# Old: extract grade from X-Grade response header
GRADE=$(curl -sI "https://securityheaders.com/?q=$DOMAIN&followRedirects=on" \
-H "x-api-key: $SH_API_KEY" \
| grep -i "x-grade:" | awk '{print $2}' | tr -d '\r')
After: Parsing DetectZeStack
# New: extract grade from JSON response body
GRADE=$(curl -s "https://detectzestack.p.rapidapi.com/security?url=$DOMAIN" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['grade'])")
If you have jq installed, the parsing is even simpler:
# Using jq
GRADE=$(curl -s "https://detectzestack.p.rapidapi.com/security?url=$DOMAIN" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
| jq -r '.grade')
Step 5: CI/CD Integration Script
Here is a complete bash script you can drop into any CI/CD pipeline. It scans your deployment URL, checks the grade, and fails the build if the grade is below your threshold:
#!/bin/bash
# ci-security-headers.sh
# Usage: RAPIDAPI_KEY=xxx DEPLOY_URL=example.com MINIMUM_GRADE=C ./ci-security-headers.sh
set -euo pipefail
DEPLOY_URL="${DEPLOY_URL:?DEPLOY_URL is required}"
RAPIDAPI_KEY="${RAPIDAPI_KEY:?RAPIDAPI_KEY is required}"
MINIMUM_GRADE="${MINIMUM_GRADE:-C}"
API_URL="https://detectzestack.p.rapidapi.com/security?url=$DEPLOY_URL"
echo "Scanning security headers for $DEPLOY_URL..."
RESPONSE=$(curl -sf "$API_URL" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com")
GRADE=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['grade'])")
SCORE=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['score'])")
echo "Grade: $GRADE ($SCORE/130)"
# Grade ordering for comparison
grade_rank() {
case "$1" in
A+) echo 6 ;; A) echo 5 ;; B) echo 4 ;;
C) echo 3 ;; D) echo 2 ;; F) echo 1 ;;
*) echo 0 ;;
esac
}
ACTUAL_RANK=$(grade_rank "$GRADE")
MIN_RANK=$(grade_rank "$MINIMUM_GRADE")
if [ "$ACTUAL_RANK" -lt "$MIN_RANK" ]; then
echo "FAIL: Grade $GRADE is below minimum $MINIMUM_GRADE"
# Print failing headers for quick debugging
echo ""
echo "Failing headers:"
echo "$RESPONSE" | python3 -c "
import sys, json
data = json.load(sys.stdin)
for header, result in data.get('tests', {}).items():
if not result.get('pass', False):
print(f' {header}: {result.get(\"result\", \"unknown\")}')
"
exit 1
fi
echo "PASS: Security headers grade $GRADE meets minimum $MINIMUM_GRADE"
GitHub Actions Example
Add this step to your deployment workflow:
# .github/workflows/deploy.yml
- name: Check security headers
env:
RAPIDAPI_KEY: ${{ secrets.RAPIDAPI_KEY }}
DEPLOY_URL: ${{ env.DEPLOY_URL }}
MINIMUM_GRADE: "C"
run: |
RESPONSE=$(curl -sf "https://detectzestack.p.rapidapi.com/security?url=$DEPLOY_URL" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com")
GRADE=$(echo "$RESPONSE" | jq -r '.grade')
echo "Security headers grade: $GRADE"
if [[ "$GRADE" == "D" || "$GRADE" == "F" ]]; then
echo "::error::Security headers grade is $GRADE (minimum: C)"
echo "$RESPONSE" | jq '.tests | to_entries[] | select(.value.pass == false) | "\(.key): \(.value.result)"'
exit 1
fi
GitLab CI Example
# .gitlab-ci.yml
security-headers-check:
stage: test
script:
- |
RESPONSE=$(curl -sf "https://detectzestack.p.rapidapi.com/security?url=$DEPLOY_URL" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com")
GRADE=$(echo "$RESPONSE" | jq -r '.grade')
echo "Grade: $GRADE"
if [ "$GRADE" = "D" ] || [ "$GRADE" = "F" ]; then
echo "Security headers grade too low: $GRADE"
exit 1
fi
Step 6: Bulk Migration for Multiple Domains
If you were scanning multiple domains with the securityheaders.com API, here is a bash loop that migrates the workflow:
#!/bin/bash
# bulk-security-scan.sh
# Scan multiple domains and output a CSV report
DOMAINS=(
"example.com"
"staging.example.com"
"api.example.com"
)
echo "domain,grade,score,hsts,csp,x_frame_options"
for domain in "${DOMAINS[@]}"; do
RESPONSE=$(curl -s "https://detectzestack.p.rapidapi.com/security?url=$domain" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com")
ROW=$(echo "$RESPONSE" | python3 -c "
import sys, json
d = json.load(sys.stdin)
t = d.get('tests', {})
hsts = 'pass' if t.get('strict-transport-security', {}).get('pass') else 'FAIL'
csp = 'pass' if t.get('content-security-policy', {}).get('pass') else 'FAIL'
xfo = 'pass' if t.get('x-frame-options', {}).get('pass') else 'FAIL'
print(f\"${domain},{d['grade']},{d['score']},{hsts},{csp},{xfo}\")
")
echo "$ROW"
sleep 1 # Rate limiting
done
Pricing Comparison
| Plan | Requests/Month | Price |
|---|---|---|
| Basic (Free) | 100 | $0/mo |
| Pro | 1,000 | $9/mo |
| Ultra | 10,000 | $29/mo |
| Mega | 50,000 | $79/mo |
The free tier is enough for most CI/CD use cases: if you deploy once per day, 100 requests covers 3+ domains. For teams scanning larger portfolios or running multiple pipelines, the Pro plan at $9/month provides 1,000 requests — enough for 33 domains scanned daily.
What You Gain Beyond SecurityHeaders.com
The /security endpoint is a direct replacement for securityheaders.com, but your API key also unlocks endpoints that securityheaders.com never offered:
- Technology detection (
GET /analyze) — identify 7,300+ technologies on any website, including frameworks, CDNs, CMS platforms, and analytics tools - Vulnerability scanning (
GET /vulnerability) — cross-reference detected technologies with the NVD database to find known CVEs - DNS intelligence (
GET /dns) — reveal hosting providers, CDNs, and email infrastructure behind any domain - SSL/TLS certificate analysis (
GET /certificate/check) — check certificate validity, expiration, and configuration - Change tracking (
GET /changes) — monitor when websites add, remove, or upgrade technologies
All endpoints share the same API key and the same request quota. No separate subscriptions.
Migration Checklist
- Get API key — Sign up on RapidAPI (free, no credit card)
- Set environment variable —
export RAPIDAPI_KEY=your-keyin CI/CD secrets - Find all references — Search your codebase for
securityheaders.comand list every file - Update endpoint URL — Replace with
https://detectzestack.p.rapidapi.com/security?url=DOMAIN - Update auth headers — Replace
x-api-keywithx-rapidapi-keyand addx-rapidapi-host - Update response parsing — Read
gradefrom JSON body instead ofX-Graderesponse header - Test against a known domain — Verify the grade matches your expectations
- Deploy and monitor — Check that your pipeline passes/fails correctly
You can also try an interactive scan on the Security Headers page — no API key needed.
Related Reading
- SecurityHeaders.com API Is Shutting Down: Free Alternative — Background on the shutdown and why securityheaders.com is going away
- How to Audit Security Headers with Python — Python code examples for bulk scanning and header grading
- Security Headers Scanner — Scan any domain interactively, no API key needed
Migrate from SecurityHeaders.com in 10 Minutes
100 requests per month free. Structured JSON. A+ to F grading. Drop-in replacement for CI/CD pipelines, compliance scripts, and monitoring dashboards.
Get Your Free API Key