HTTP Headers & Redirect Checker avatar

HTTP Headers & Redirect Checker

Pricing

$0.90 / 1,000 results

Go to Apify Store
HTTP Headers & Redirect Checker

HTTP Headers & Redirect Checker

Check HTTP headers and redirect chains: security score with values to set, CSP, HSTS, CORS and cache checks. Use when you need to audit headers or redirects.

Pricing

$0.90 / 1,000 results

Rating

0.0

(0)

Developer

Plain Pipe

Plain Pipe

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Security

Limited permissions

Share

Check URLs for their full redirect chain, final status code and response headers. Every URL gets a 0-100 security-header score with an A+ to F grade, the exact value to set for each weak or missing header, and CSP, HSTS, CORS, caching, compression and HTTP/2 / HTTP/3 checks.

Use this when: you need to verify redirects, final status codes, or security, CORS and cache headers for a list of URLs, and want to know what to change.

What it does

Give it a list of URLs (or an Apify dataset of URLs). For each one it follows redirects hop by hop and returns one row with:

  • Redirect chain: every hop with status code, Location, response time and server; redirect loops and over-long chains are detected and reported, HTTPS-to-HTTP downgrades and temporary (302/307) redirects are flagged.
  • Security score and grade: seven headers are scored with partial credit for weak values (see the table below), minus up to 10 points for version disclosure in Server / X-Powered-By. Each header comes with its status (good, weak, invalid, missing), notes and the value to set.
  • CSP parsing: directives found, 'unsafe-inline' (ignored when a nonce, hash or 'strict-dynamic' is present), 'unsafe-eval', wildcard or scheme-only script sources, missing default-src, object-src, base-uri, frame-ancestors.
  • HSTS details: max-age in seconds and days, includeSubDomains, preload, and whether the header meets preload-list rules.
  • CORS: Access-Control-Allow-Origin, methods, headers, max-age, plus warnings (any origin, the null origin, echoed origin without Vary: Origin). Send your own Origin to see how the server answers it.
  • Caching: Cache-Control split into fields (max-age, s-maxage, no-store, private, immutable and more), ETag, Last-Modified, Age, Vary, CDN cache status, and whether the response is cacheable in browsers and in shared caches.
  • Compression and protocol: Content-Encoding (br, gzip) for an offered br, gzip, deflate, HTTP/2 support (TLS ALPN handshake), HTTP/3 advertised in Alt-Svc, TLS version.
  • Plain lists: issues (every finding as a sentence) and recommendations (header, value to set, points gained), plus all final response headers.

Use cases

  • Verify 301 redirects after a site migration or a domain change, including multi-hop chains and loops.
  • Confirm that http:// and bare-domain URLs upgrade to HTTPS, with HSTS set correctly.
  • Audit security headers across many sites and hand developers the exact values to set.
  • Check Cache-Control, CDN hits and compression on key pages or assets after a deploy.
  • Test CORS answers for a given origin, or compare desktop and mobile responses.

How to use it

  1. Paste URLs into URLs, one per line, or set Read URLs from a dataset to the ID of a dataset (for example the output of a sitemap run). Start a URL with http:// to test the HTTPS upgrade.
  2. Optionally pick a Request method, a User-Agent, extra request headers or an Origin.
  3. Choose Output format: full for nested JSON or flat for spreadsheet-ready columns.
  4. Run the Actor. Results land in the dataset; export them as JSON, CSV or Excel, or read them through the Apify API. The Issues and fixes view lists findings and values to set per URL.

Input

FieldWhat it isDefaultExample
urlsURLs to check. A bare domain is read as https://. Invalid entries are skipped with a log warning.none["http://example.com/old-page", "example.org"]
datasetIdID or name of an Apify dataset to read URLs from (combined with urls).none"aBcD1234efGh5678"
datasetUrlFieldField of each dataset item that holds the URL.urlloc
methodHEAD (lighter) or GET. If a server refuses HEAD (405 or 501), that URL is retried with GET.HEADGET
userAgentbot, desktop or mobile. The browser-shaped strings still end in SiteCheckBot/1.0 (Apify Actor).botmobile
headersExtra request headers as a JSON object. Headers carrying secrets (Authorization, API keys, tokens) are refused.{}{"Accept-Language": "de-DE"}
originSent as the Origin request header to test CORS.noneexample.org
maxRedirectsStop following after this many redirects (0 to 30).105
includeHopHeadersAdd all response headers to every hop of the chain.falsetrue
checkHttp2One TLS handshake to the final host to read HTTP/2 (ALPN) and the TLS version.truefalse
outputFormatfull (nested) or flat (plain columns, lists joined with |).fullflat
maxConcurrencyURLs checked in parallel (1 to 5). The same host still gets at most one request per second.53
timeoutSecsTimeout per request in seconds (1 to 120).1530
maxItemsCheck at most this many URLs.1001000

Either urls or datasetId must give at least one valid URL.

Example input:

{
"urls": ["http://apify.com", "https://docs.apify.com"],
"method": "HEAD",
"userAgent": "bot",
"outputFormat": "full",
"maxItems": 2
}

Scoring

HeaderMax pointsFull points when
Strict-Transport-Security25max-age of at least one year (180 days or more gives 20, less gives 10)
Content-Security-Policy25enforced policy without 'unsafe-inline', 'unsafe-eval', broad script sources, and with default-src, object-src, base-uri (Report-Only alone gives 5)
X-Frame-Options15DENY or SAMEORIGIN, or CSP frame-ancestors
X-Content-Type-Options10nosniff
Referrer-Policy10no-referrer, same-origin, strict-origin or strict-origin-when-cross-origin
Permissions-Policy10present (legacy Feature-Policy alone gives 5)
Cross-Origin-Opener-Policy5same-origin or same-origin-allow-popups

Version numbers in Server, X-Powered-By and similar headers cost up to 10 points. Grade: A+ 95 or more, A 85, B 70, C 55, D 40, F below 40. A final URL on plain HTTP is always F. Deprecated headers (X-XSS-Protection other than 0, Expect-CT, Public-Key-Pins) are listed in issues without changing the score.

Output

One row per URL. A real row from a run on http://apify.com on 2026-11-04 (the long CSP value, scriptSources and headers are shortened here; the dataset holds every value):

{
"url": "http://apify.com/",
"finalUrl": "https://apify.com/",
"finalStatusCode": 200,
"redirectCount": 1,
"redirectLoop": false,
"tooManyRedirects": false,
"redirectChain": [
{ "url": "http://apify.com/", "statusCode": 301, "location": "https://apify.com/", "timeMs": 125, "server": "CloudFront" },
{ "url": "https://apify.com/", "statusCode": 200, "location": null, "timeMs": 1214, "server": null }
],
"httpsUpgrade": true,
"method": "HEAD",
"userAgent": "bot",
"responseTimeMs": 1214,
"totalTimeMs": 1340,
"contentType": "text/html; charset=utf-8",
"cacheControl": "private, no-cache, no-store, max-age=0, must-revalidate",
"contentEncoding": null,
"securityGrade": "C",
"securityScore": 62,
"securityHeadersPresent": ["Strict-Transport-Security", "Content-Security-Policy", "X-Frame-Options", "X-Content-Type-Options"],
"securityHeadersMissing": ["Referrer-Policy", "Permissions-Policy", "Cross-Origin-Opener-Policy"],
"issues": [
"Referrer-Policy is missing.",
"Cross-Origin-Opener-Policy is missing.",
"Strict-Transport-Security: max-age is 182 days; one year (31536000) is the common baseline.",
"Strict-Transport-Security: No includeSubDomains: subdomains can still be reached over HTTP.",
"Content-Security-Policy: script-src allows 'unsafe-inline' without a nonce or hash, so injected inline scripts run.",
"Content-Security-Policy: script-src allows 'unsafe-eval' (eval and new Function).",
"Permissions-Policy: Only the legacy Feature-Policy header is sent.",
"X-XSS-Protection \"1; mode=block\" is deprecated and can introduce leaks; set \"0\" or remove it, and rely on CSP.",
"Expect-CT is obsolete; it can be removed.",
"CORS allows any origin (*): fine for public assets, review it for private APIs.",
"no-store: nothing is cached, every visit is a full request.",
"No Content-Encoding on the HEAD response; some servers only compress GET, re-check with method GET."
],
"recommendations": [
{ "header": "Strict-Transport-Security", "set": "max-age=31536000; includeSubDomains", "gain": 5 },
{ "header": "Content-Security-Policy", "set": "replace 'unsafe-inline' in script-src with nonces or hashes; remove 'unsafe-eval'", "gain": 13 },
{ "header": "Referrer-Policy", "set": "strict-origin-when-cross-origin", "gain": 10 },
{ "header": "Permissions-Policy", "set": "camera=(), microphone=(), geolocation=()", "gain": 5 },
{ "header": "Cross-Origin-Opener-Policy", "set": "same-origin (or same-origin-allow-popups if you open third-party windows)", "gain": 5 }
],
"securityHeaders": [
{
"header": "Strict-Transport-Security", "present": true, "value": "max-age=15768000",
"score": 20, "maxScore": 25, "status": "weak",
"notes": ["max-age is 182 days; one year (31536000) is the common baseline.", "No includeSubDomains: subdomains can still be reached over HTTP."],
"recommendation": "max-age=31536000; includeSubDomains"
},
{ "header": "X-Frame-Options", "present": true, "value": "SAMEORIGIN", "score": 15, "maxScore": 15, "status": "good", "notes": [], "recommendation": null }
],
"hsts": { "maxAge": 15768000, "maxAgeDays": 182, "includeSubDomains": false, "preload": false, "preloadReady": false },
"csp": {
"directives": ["default-src", "connect-src", "img-src", "frame-src", "style-src", "style-src-elem", "style-src-attr", "script-src", "script-src-elem", "font-src", "form-action", "child-src", "media-src", "frame-ancestors", "base-uri"],
"scriptSources": ["'self'", "'unsafe-eval'", "..."],
"unsafeInline": true, "unsafeEval": true, "usesNonceOrHash": false, "strictDynamic": false,
"broadScriptSources": [], "missingDirectives": [],
"frameAncestors": "'self' https://cms.apify.com", "upgradeInsecureRequests": false, "reportsTo": false
},
"cors": {
"enabled": true, "allowOrigin": "*", "allowCredentials": null, "allowMethods": null, "allowHeaders": null,
"exposeHeaders": "Link", "maxAge": null, "crossOriginResourcePolicy": null, "crossOriginEmbedderPolicy": null,
"warnings": ["CORS allows any origin (*): fine for public assets, review it for private APIs."]
},
"caching": {
"cacheControl": "private, no-cache, no-store, max-age=0, must-revalidate", "maxAge": 0, "sMaxAge": null,
"noStore": true, "noCache": true, "private": true, "public": false, "immutable": false, "mustRevalidate": true,
"etag": null, "lastModified": null, "age": null, "vary": "Accept-Encoding", "cacheStatus": "Miss from cloudfront",
"servedFromCache": false, "browserCacheable": false, "sharedCacheable": false, "revalidatable": false
},
"compression": { "contentEncoding": null, "compressed": false, "brotli": false, "compressible": true },
"protocol": { "altSvc": "h3=\":443\"; ma=86400", "http3Advertised": true, "alpn": "h2", "tlsVersion": "TLSv1.3", "http2Supported": true },
"disclosure": { "penalty": 0 },
"headers": { "content-type": "text/html; charset=utf-8", "strict-transport-security": "max-age=15768000", "x-frame-options": "SAMEORIGIN" },
"checkedAt": "2026-11-04T09:46:15.860Z"
}

In the same run https://docs.apify.com scored 40/100 (grade D): no CSP, X-Content-Type-Options, Referrer-Policy, Permissions-Policy or Cross-Origin-Opener-Policy. The same URL https://apify.com with "method": "GET" reports contentEncoding: "gzip", which HEAD did not show.

With "outputFormat": "flat" the same facts come as plain columns, for example redirectChain: "301 http://apify.com/ -> 200 https://apify.com/", hstsMaxAge, cspUnsafeInline, corsAllowOrigin, cacheMaxAge, http2Supported, issues and recommendations as |-joined text.

A redirect loop is a result too: the row has redirectLoop: true, the hops up to the repeated URL, finalUrl / finalStatusCode of the last response received (a 3xx), no security grade, and the loop in issues. Chains longer than maxRedirects look the same with tooManyRedirects: true.

FieldMeaning
finalUrl, finalStatusCodeWhere the chain ends and that response's status code.
redirectCount, redirectChainNumber of redirects and every hop with status, Location, time and server (all headers with includeHopHeaders).
redirectLoop, tooManyRedirectsThe chain revisits a URL, or is longer than maxRedirects.
httpsUpgradetrue when an http:// URL ended on https://.
securityScore, securityGrade0-100 and A+ to F, see Scoring.
securityHeadersPer-header value, score, status, notes and the value to set.
recommendationsOnly the headers to change: value to set and points gained.
issuesEvery finding as one sentence: chain, security, CORS, cache, compression.
hsts, csp, cors, caching, compression, protocol, disclosureParsed details per area.
headersAll final response headers, lower-cased.

Pricing

Pay per result: $0.90 per 1,000 results ($0.0009 per result). You only pay for results the Actor returns. Set a maximum total charge on the run to cap your spend.

Limits

  • Follows HTTP redirects only (status 3xx with Location). Meta-refresh and JavaScript redirects are not followed.
  • Up to 30 hops per URL (maxRedirects, default 10). Loops and over-long chains are reported as rows.
  • Unreachable URLs (DNS failure, refused connection, timeout, TLS error) produce no result and cost nothing; the run log names the reason. If no URL can be checked, the run fails with zero results.
  • Checks what is publicly served. Headers carrying secrets (Authorization, API keys, tokens) are not sent.
  • At most 5 URLs in parallel and at most one request per second to the same host.
  • HEAD responses do not always show compression; use GET for that check.
  • Internationalised domain names (for example münchen.de) are converted to their ASCII form before the request.

FAQ

How much does it cost? $0.90 per 1,000 checked URLs. Unreachable URLs are free.

Is the score the same as other header graders? No. It is this Actor's own weighting, documented in the Scoring table, so every point can be traced to a header value.

Why do HEAD and GET give different results? Some servers or CDNs answer HEAD with different headers or status codes, and many only report compression on GET. Switch Request method to GET to see what a browser gets.

Why is a URL missing from the results? The domain did not resolve, the connection failed or timed out, or the certificate was invalid. The run log names the reason for each skipped URL.

Can I check URLs from another run? Yes. Set Read URLs from a dataset to that run's dataset ID and Dataset URL field to the field holding the URL.

How do I get a spreadsheet? Set Output format to flat and export the dataset as CSV or Excel.

Need DNS records, TLS certificate expiry or indexability? See Plain Pipe's DNS Records Lookup, Website Status Checker and Indexability Checker. For on-page tags, see Plain Pipe's SEO Page Audit & On-Page Checker.

Can I monitor headers on a schedule? Yes. Use Apify Schedules for recurring runs and the Apify API, webhooks or integrations to compare securityScore or issues over time.

Why this one

  • $0.90 per 1,000 results ($0.0009 per checked URL); unreachable URLs are not charged.
  • Each row gives the value to set for every weak or missing header and the points it adds, plus parsed CSP (unsafe-inline, unsafe-eval, missing directives) and HSTS (max-age, includeSubDomains, preload readiness).
  • Redirect chain with per-hop timing and loop detection, CORS, cache, compression, HTTP/2 and HTTP/3 checks in the same row; flat output for spreadsheets.
  • HEAD requests by default with automatic GET fallback, 5 URLs in parallel; no browser and no proxy. The 2-URL prefill run finishes in under 5 seconds (about 2 s in our tests), and the prefilled input is test-run daily.

This Actor processes only what you give it or public, non-personal technical data. It does not log in anywhere, does not collect personal data, and does not bypass paywalls, CAPTCHAs or access controls. You are responsible for having the right to process the inputs you provide.

Support

Open an issue on the Issues tab. Issues are answered within 14 days.

Built and maintained by Plain Pipe.