# HTTP URL Probe (`skilled_glee/http-url-probe`) Actor

Check up to 50 URLs per run with HEAD or GET: HTTP status code, final URL after redirects, redirect count, Content-Type header, and timing. No page body is read.

- **URL**: https://apify.com/skilled_glee/http-url-probe.md
- **Developed by:** [EchoEmpire Machine Foundry (EchoEmpire LLC)](https://apify.com/skilled_glee) (community)
- **Categories:** Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.40 / 1,000 url probeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## HTTP URL Probe

#### First run in two steps

1. **Cheapest single probe.** Run with one public URL and default `HEAD`. Cost = **$0.0004** for that URL on the current Pricing tab (`url-probed`; no start fee; rates can change). Set a run spending limit (`maxTotalChargeUsd`) before you run so a larger batch cannot overspend.

```json
{
  "urls": ["https://example.com/"],
  "method": "HEAD",
  "timeoutSecs": 15,
  "followRedirects": true
}
```

You get one dataset row: status code, final URL after redirects, redirect count, `Content-Type`, and timing. The page body is never read.

2. **Same shape, two outcomes.** Re-run with a small list so you see a success row and an HTTP-error row in one batch. Still **$0.0004 × number of URLs that got a network attempt** (invalid or private/loopback URLs are not charged; do not use those as a free path).

```json
{
  "urls": [
    "https://example.com/",
    "https://httpbin.org/status/404"
  ],
  "method": "HEAD",
  "timeoutSecs": 15,
  "followRedirects": true
}
```

If a host answers `HEAD` with `405` (or you need headers that only arrive on `GET`), keep the same `urls` and set `method` to `"GET"`. The body is still not downloaded.

Store API / client examples for this Actor: the API section on the listing page.

Check whether URLs answer over HTTP, and where they end up. For each URL the Actor sends one `HEAD` (default) or `GET` request, follows redirects if you allow it, and returns one flat row with the status code, final URL, redirect count, `Content-Type` header and timing.

It is meant as a cheap first step before heavier work: prune dead links, record final URLs after redirects, or decide which URLs are worth sending to a content extractor.

### What it does not do

- It does **not** read, return or analyze the page body. `GET` is only used to get headers.
- It does **not** check SEO, indexability, robots.txt, content or "uptime".
- It does **not** use proxies, rotate IPs or bypass bot protection. Requests come from Apify datacenter IPs, so some sites answer `403`, `429` or refuse `HEAD`. That status is what you get back.
- It does **not** switch from `HEAD` to `GET` on its own. If a host answers `HEAD` with `405`, run it again with `method: "GET"`.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `urls` | array of strings | required | 1 to 50 absolute `http://` or `https://` URLs per run. |
| `method` | `HEAD` or `GET` | `HEAD` | |
| `timeoutSecs` | integer | `15` | 1 to 30. Total time per URL, including redirects. |
| `followRedirects` | boolean | `true` | Up to 10 hops. If `false`, the first response (e.g. `301`) is reported. |
| `userAgent` | string | `EchoEmpire-HTTP-URL-Probe/0.1 (+https://apify.com/skilled_glee/http-url-probe)` | Up to 200 printable characters. |

```json
{
  "urls": ["https://example.com/", "https://httpbin.org/status/404"],
  "method": "HEAD",
  "timeoutSecs": 15,
  "followRedirects": true
}
```

If `urls` is missing or empty, the run fails with a clear message. There is no built-in example input that runs in its place.

### Output

One dataset row per input URL, in input order:

| Field | Meaning |
|---|---|
| `url` | The input URL as given. |
| `finalUrl` | URL of the last response after redirects, or `null` if there was no HTTP response. |
| `statusCode` | HTTP status of the last response, or `null`. |
| `ok` | `true` when `statusCode` is 200–399 and there is no error. |
| `redirectCount` | Redirects followed. |
| `contentType` | `Content-Type` response header as sent by the server, or `null`. |
| `elapsedMs` | Milliseconds until response headers, or until the failure. |
| `error` | `null`, or one of: `http_status` (status 400+), `timeout`, `dns`, `tls`, `connection`, `too_many_redirects`, `invalid_url`, `blocked_address`. |

Rows from a real cloud run (2026-10-25):

```json
{"url": "http://github.com/", "finalUrl": "https://github.com/", "statusCode": 200, "ok": true, "redirectCount": 1, "contentType": "text/html; charset=utf-8", "elapsedMs": 109, "error": null}
{"url": "https://httpbin.org/status/404", "finalUrl": "https://httpbin.org/status/404", "statusCode": 404, "ok": false, "redirectCount": 0, "contentType": "text/html; charset=utf-8", "elapsedMs": 91, "error": "http_status"}
{"url": "https://does-not-exist.invalid/", "finalUrl": null, "statusCode": null, "ok": false, "redirectCount": 0, "contentType": null, "elapsedMs": 76, "error": "dns"}
```

Partial failures are isolated: a bad URL never stops the batch. It becomes a row with `ok: false` and an `error`. A run summary (counts per outcome, URLs charged, whether a spending limit stopped the run) is saved as `SUMMARY` in the default key-value store.

`invalid_url` means the string is not an absolute http(s) URL, or it contains credentials. `blocked_address` means the host resolves to a private, loopback or link-local address; such URLs are not requested.

### Pricing (pay per event, platform costs included)

| Event | When | Price |
|---|---|---|
| `url-probed` | Once per URL that got a network attempt, whatever the outcome (`ok`, `http_status`, `timeout`, `dns`, `tls`, `connection`, `too_many_redirects`) | $0.0004 |

No start fee and no minimum charge. Not charged: rows with `invalid_url` or `blocked_address` (no request was sent), and dataset items as such. Example: 50 URLs in one run cost 50 × $0.0004 = $0.02.

If you set a maximum charge per run, the Actor stops before it would exceed it; URLs that were not probed get no row and are counted in `SUMMARY.skippedForSpendingLimit`.

### Limitations

- 50 URLs per run; 10 requests in parallel.
- Redirects: at most 10 hops; more gives `too_many_redirects`.
- TLS certificates are verified; an invalid certificate gives `tls`.
- Many sites answer `HEAD` with `405`, or block datacenter IPs with `403`/`429`. These are reported as the real status (`ok: false`, `error: "http_status"`), not hidden or retried.
- `elapsedMs` is measured from the Apify cloud and is not a latency benchmark for end users.

# Actor input Schema

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

1 to 50 absolute http:// or https:// URLs. Each URL becomes one dataset row. URLs with credentials, other schemes, or hosts that resolve to private/loopback addresses are returned as rows with an error and are not charged.

## `method` (type: `string`):

HEAD (default) asks for headers only. Use GET for hosts that refuse HEAD; with GET the body is still not downloaded. The Actor does not switch methods on its own.

## `timeoutSecs` (type: `integer`):

Total time allowed for one URL, including any redirects. 1 to 30.

## `followRedirects` (type: `boolean`):

Follow 3xx redirects, up to 10 hops. If off, the first response (for example 301) is reported as-is.

## `userAgent` (type: `string`):

Optional User-Agent header (up to 200 printable characters). Default: EchoEmpire-HTTP-URL-Probe/0.1 (+https://apify.com/skilled_glee/http-url-probe).

## Actor input object example

```json
{
  "urls": [
    "https://example.com/"
  ],
  "method": "HEAD",
  "timeoutSecs": 15,
  "followRedirects": true
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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://example.com/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("skilled_glee/http-url-probe").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://example.com/"] }

# Run the Actor and wait for it to finish
run = client.actor("skilled_glee/http-url-probe").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://example.com/"
  ]
}' |
apify call skilled_glee/http-url-probe --silent --output-dataset

```

## MCP server setup

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

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/R1wYKTcTyWamK1ddw/builds/0HKbvlw6W3uvDGSCY/openapi.json
