# Bulk URL Status Checker — Broken Links, Redirects & SSL (`hipersoft/bulk-url-checker`) Actor

Check thousands of URLs over plain HTTP: status codes, broken links (404/410/5xx), full redirect chains, response time, content type, page title and SSL certificate expiry.

- **URL**: https://apify.com/hipersoft/bulk-url-checker.md
- **Developed by:** [Hipersoft](https://apify.com/hipersoft) (community)
- **Categories:** Developer tools, SEO tools
- **Features:** Limited permissions
- **Stats:** 13 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.001 / url checked

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bulk URL Status Checker — Broken Links, Redirects & SSL

Audit thousands of URLs in one run. Feed the Actor any list of links and it reports
each one's **HTTP status, whether it's broken, the full redirect chain, response
time, content type, page title, and SSL certificate expiry**.

Great for **broken-link audits, redirect/migration QA, uptime spot-checks, sitemap
validation, and SSL-expiry monitoring**. Export results to JSON, CSV or Excel.

![Bulk URL Status Checker input — a list of URLs with SSL and title checks in the Apify Console](https://api.apify.com/v2/key-value-stores/SUfvnaFLd9z9eBCtV/records/bulk-url-checker-input.png?v=2)

### What you get per URL

![Bulk URL Status Checker output example — status code, broken/blocked flags, redirect chain and SSL as structured JSON](https://api.apify.com/v2/key-value-stores/SUfvnaFLd9z9eBCtV/records/bulk-url-checker-output.png?v=5)

| Field | Notes |
|---|---|
| `statusCode` | Final HTTP status (200, 301, 404, 410, 500, …). |
| `ok` / `broken` / `blocked` | `ok` = 2xx/3xx; `broken` = genuinely dead (404/410/5xx); `blocked` = access-restricted (401/403/429, usually bot-protection — try a proxy). Keeps blocks from being mistaken for dead links. |
| `redirectChain` | Every hop: `{url, status, location}` — see exactly where a link lands. |
| `redirectCount` | Number of redirects followed. |
| `finalUrl` | Where the URL ended up after all redirects. |
| `responseTimeMs` | End-to-end time for the whole chain. |
| `contentType`, `contentLength`, `server` | From the final response headers. |
| `title` | `<title>` of successful HTML pages (toggle off for pure speed). |
| `ssl` | For https: `{ issuer, validTo, daysToExpiry, authorized }` — catch expiring certs. |
| `error` | Classified failure: `dns-error`, `timeout`, `connection-refused`, `ssl-error`, `too-many-redirects`, … |

#### Why it's more than a status checker

Besides the status code it traces the **complete redirect path** (not just the final
landing), measures **latency**, grabs the **page title** so a report is human-readable,
and checks the **TLS certificate expiry** — so one run doubles as a broken-link audit
*and* an SSL-expiry watch.

### Input

```json
{
  "urls": ["https://apify.com", "https://apify.com/this-page-does-not-exist"],
  "checkSsl": true,
  "fetchTitle": true,
  "maxConcurrency": 20
}
```

- **urls** — links to check, one per line. (Or use **startUrls** for a request list.)
- **maxRedirects** — hops to trace before giving up (default 10).
- **fetchTitle** — read `<title>` of HTML pages (default on; turn off for max speed).
- **checkSsl** — report certificate expiry for https URLs (default on).
- **maxConcurrency** — URLs checked in parallel (default 20).
- **maxItems** — cap total URLs (0 = all).
- **proxyConfiguration** — optional; enable for reliable access at scale.

### Output (one row per URL)

```json
{
  "input": "https://apify.com/this-page-does-not-exist",
  "url": "https://apify.com/this-page-does-not-exist",
  "statusCode": 404,
  "ok": false,
  "broken": true,
  "redirectCount": 0,
  "finalUrl": "https://apify.com/this-page-does-not-exist",
  "responseTimeMs": 220,
  "contentType": "text/html; charset=utf-8",
  "title": "Page not found",
  "ssl": { "issuer": "Google Trust Services", "daysToExpiry": 61, "authorized": true },
  "error": null
}
```

#### Output schema

| Field | Type | Description |
| --- | --- | --- |
| `input` | string (URL) | The original URL you supplied. |
| `url` | string (URL) | The URL that was checked. |
| `ok` | boolean | True when the URL responded with a 2xx/3xx status. |
| `broken` | boolean | True when the URL is genuinely dead (404/410/5xx). |
| `blocked` | boolean | True when access was restricted (401/403/429). |
| `statusCode` | string | Final HTTP status code after redirects. |
| `finalUrl` | string (URL) | The URL the request landed on after all redirects. |
| `redirectCount` | integer | Number of redirects followed. |
| `redirectChain` | array | Each redirect hop with its URL, status and location. |
| `responseTimeMs` | integer | End-to-end response time in milliseconds. |
| `contentType` | string | Content-Type header of the final response. |
| `contentLength` | string | Content-Length header of the final response. |
| `server` | string | Server header of the final response. |
| `title` | string | `<title>` text of successful HTML pages. |
| `ssl` | string | SSL certificate details: issuer, expiry date, days to expiry and whether it is trusted. |
| `error` | string | Classified failure reason, or null when the check succeeded. |

### Pricing

Pay per URL checked. No monthly fee — you only pay for what you run.

### FAQ

**How many URLs can I check per run?**
Thousands in a single run. `maxItems` caps the total (0 = all) and `maxConcurrency` controls how many URLs are checked in parallel (default 20).

**Is bulk URL checking legal?**
The Actor only reads the HTTP response of the URLs you supply. You are responsible for having the right to audit those targets and for respecting each site's terms and rate limits.

**What's the output format?**
A JSON dataset with one row per URL (status, broken/blocked flags, redirect chain, response time, title, SSL details). Export as JSON, CSV, or Excel from the Apify Console or API.

**Can I filter or limit results?**
Yes. Use `maxItems`, `maxConcurrency`, and `maxRedirects`, and toggle `checkSsl` and `fetchTitle` on or off to trade detail for speed.

**Can I connect this Actor to other apps?**
The Bulk URL Status Checker can be connected with almost any cloud service or web app thanks to [integrations on the Apify platform](https://apify.com/integrations). It works with [Make](https://apify.com/integrations/make), [Zapier](https://apify.com/integrations/zapier), [Slack](https://docs.apify.com/platform/integrations/slack), [Airbyte](https://docs.apify.com/platform/integrations/airbyte), [GitHub](https://docs.apify.com/platform/integrations/github), [Google Drive](https://docs.apify.com/platform/integrations/drive) and [many more](https://apify.com/integrations), plus the [Apify API](https://docs.apify.com/api/v2), JavaScript/Python clients and MCP. Or use [webhooks](https://docs.apify.com/platform/integrations/webhooks) to trigger an action whenever a run finishes.

### Related Actors

Combine this with other web-diagnostics and archival tools:

- [Domain Inspector](https://apify.com/hipersoft/domain-inspector) — WHOIS/RDAP, DNS, and SSL details for any domain.
- [Wayback Machine Scraper](https://apify.com/hipersoft/wayback-machine-scraper) — list archived snapshots of a URL or domain.
- [Bulk Image Downloader](https://apify.com/hipersoft/bulk-image-downloader) — fetch and store images at scale from a URL list.
- [Website Content Crawler](https://apify.com/hipersoft/website-content-crawler) — crawl a site into clean text for analysis or RAG.

### Notes

Checks only the HTTP response of URLs you supply. You are responsible for having the
right to audit the target URLs.

# Actor input Schema

## `urls` (type: `array`):

List of URLs to check (e.g. "https://apify.com", "example.com/page"). One per line.

## `startUrls` (type: `array`):

Alternative to "URLs": a request list of {"url": "..."} objects, e.g. from a linked dataset or Key-Value store.

## `maxRedirects` (type: `integer`):

Upper bound on redirect hops traced per URL before reporting "too-many-redirects".

## `fetchTitle` (type: `boolean`):

Read the <title> of successful HTML pages. Turn off for maximum speed (headers only).

## `checkSsl` (type: `boolean`):

For https URLs, report the certificate issuer and days until expiry — catch soon-to-expire certs.

## `maxConcurrency` (type: `integer`):

How many URLs to check in parallel.

## `maxItems` (type: `integer`):

Cap on how many input URLs to check (0 = no cap, check all).

## `proxyConfiguration` (type: `object`):

Proxy configuration. Leave the default — it is tuned for reliable results.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://apify.com/this-page-does-not-exist"
  ],
  "maxRedirects": 10,
  "fetchTitle": true,
  "checkSsl": true,
  "maxConcurrency": 20,
  "maxItems": 0,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "https://apify.com",
        "https://apify.com/this-page-does-not-exist"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("hipersoft/bulk-url-checker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "urls": [
        "https://apify.com",
        "https://apify.com/this-page-does-not-exist",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("hipersoft/bulk-url-checker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "https://apify.com",
    "https://apify.com/this-page-does-not-exist"
  ]
}' |
apify call hipersoft/bulk-url-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hipersoft/bulk-url-checker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/tFNjQKmbWTtQMPSkF/builds/cnoPsPAI9RpXeWbKb/openapi.json
