# Subdomain Finder - Discover Every Subdomain Of A Domain (`thirdwatch/subdomain-finder`) Actor

Discover every subdomain for any apex domain. Merges 4 sources: certificate transparency (crt.sh), HackerTarget, RapidDNS, plus DNS bruteforcing of common names. Verifies each is live via DNS + HTTP probe.

- **URL**: https://apify.com/thirdwatch/subdomain-finder.md
- **Developed by:** [Thirdwatch](https://apify.com/thirdwatch) (community)
- **Categories:** Developer tools, SEO tools
- **Stats:** 11 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Subdomain Finder

The Actor now runs random-host negative controls by default. It retains every raw candidate and adds an evidence class instead of treating every resolving DNS label as a distinct asset:

- `observed`: an independent passive source saw the hostname;
- `candidate`: it resolves or responds without passive evidence;
- `wildcard-likely`: brute-force-only and matches the consensus random-host DNS/HTTP fingerprint;
- `unresolved`: it did not resolve or respond during the run.

At least two random controls must share the same fingerprint before `wildcard_detected` becomes true. The full control observations remain in `wildcard_observations` for auditability. A class describes collection evidence only; it is never a vulnerability finding.

> **Thirdwatch portfolio:** 5K users across 88 public Actors, 2M+ records delivered, and >99% run success. [Explore all Thirdwatch Actors](https://apify.com/thirdwatch).

Find every subdomain of any domain. The actor merges four independent discovery sources, deduplicates the results, and verifies each candidate with DNS resolution and a live HTTP/HTTPS probe. Each result tells you which sources found it, whether it resolves, what IPs it points to, and the HTTP status + page title behind it.

### What you can do with it

- Attack-surface monitoring for your own apex domains.
- Pre-engagement recon for security audits and bug bounty work.
- Competitive intelligence — see which services and vendors a domain exposes.
- Asset inventory automation across acquired or merged companies.

### How discovery works

Four sources run in parallel; one failing (quota, transient HTTP error) does not kill the run:

1. **Certificate transparency logs** — the gold standard; catches anything that has ever been issued a TLS cert.
2. **Public hostsearch API** — passive DNS data, free tier.
3. **Passive DNS aggregator** — long-tail historical resolutions.
4. **DNS bruteforcing** — built-in wordlists (`small` ~100 names, `medium` ~1000) tried against the apex domain. Catches infrastructure subdomains (`k8s`, `vault`, `gitlab`, `metrics`, etc.) that never appear in passive sources.

Each result lists exactly which sources saw it, so you can confidence-grade discoveries and spot source drift over time.

### Input

```json
{
  "domains": ["thirdwatch.dev"],
  "sources": ["crtsh", "hackertarget", "rapiddns", "dnsbruteforce"],
  "bruteforceWordlist": "small",
  "verifyAlive": true,
  "httpProbe": true,
  "timeoutMinutes": 5
}
```

| Field | Type | Default | Description |
|------|------|---------|-------------|
| `domains` | string\[] | — | Apex domains, no scheme/subdomain. |
| `sources` | string\[] | all 4 | Subset of `crtsh`, `hackertarget`, `rapiddns`, `dnsbruteforce`. |
| `bruteforceWordlist` | enum | `small` | `none`, `small` (~100), `medium` (~1000). |
| `verifyAlive` | boolean | `true` | DNS-resolve every candidate. |
| `httpProbe` | boolean | `true` | HTTP+HTTPS GET to capture status + title. |
| `timeoutMinutes` | integer | `5` | Per-domain budget. |
| `proxyConfiguration` | object | none | Optional Apify proxy. |

### Output (one item per subdomain)

```json
{
  "apex_domain": "thirdwatch.dev",
  "subdomain": "mcp.thirdwatch.dev",
  "dns_resolves": true,
  "ip_addresses": ["104.21.10.5"],
  "sources": ["crtsh", "hackertarget"],
  "http_status": 301,
  "https_status": 200,
  "http_title": null,
  "https_title": "Thirdwatch MCP",
  "is_alive": true,
  "discovered_at": "2026-05-04T10:00:00+00:00"
}
```

Please only enumerate domains you own or have authorization to test.

### Limitations

- Coverage depends on what each source has indexed; freshly-issued subdomains may not appear in certificate transparency logs for hours.
- The HackerTarget source has a free quota (~50 queries/day per IP); when exhausted, that source returns nothing for that day and the run continues with the others.
- DNS bruteforcing uses our built-in wordlists. Highly custom internal naming (e.g. project codenames) won't be found by brute alone — it will surface only through certificate transparency or passive DNS.
- The HTTP probe times out after 5 seconds per host; very slow hosts may show as `null` status even when alive.

### Last verified

2026-05

# Actor input Schema

## `domains` (type: `array`):

Apex domains to enumerate subdomains for. No scheme, no subdomain (e.g. 'example.com', not 'https://www.example.com/').

## `sources` (type: `array`):

Passive sources to merge. crtsh = certificate transparency, hackertarget = HackerTarget API, rapiddns = RapidDNS HTML scraping, dnsbruteforce = DNS-resolve common subdomain names from a built-in wordlist.

## `bruteforceWordlist` (type: `string`):

Built-in wordlist size for DNS bruteforcing. 'none' = skip bruteforce. 'small' = ~100 most common subdomains. 'medium' = ~1000 names.

## `verifyAlive` (type: `boolean`):

DNS-resolve each candidate subdomain. Subdomains that don't resolve are flagged with dns\_resolves=false but still returned.

## `httpProbe` (type: `boolean`):

Send HTTP and HTTPS GET requests to each subdomain to detect live web servers. Captures status code + page title.

## `wildcardChecks` (type: `boolean`):

Probe random nonexistent hostnames and classify brute-force-only rows that match the consensus DNS/HTTP fingerprint as wildcard-likely. Requires DNS verification and HTTP probing.

## `wildcardProbeCount` (type: `integer`):

Number of random negative controls. At least two must share a fingerprint before the Actor declares a wildcard baseline.

## `timeoutMinutes` (type: `integer`):

Maximum time to spend on a single apex domain before moving on.

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

Optional Apify proxy. Most public sources work without proxy.

## Actor input object example

```json
{
  "domains": [
    "onescales.com"
  ],
  "sources": [
    "crtsh",
    "hackertarget",
    "rapiddns",
    "dnsbruteforce"
  ],
  "bruteforceWordlist": "small",
  "verifyAlive": true,
  "httpProbe": true,
  "wildcardChecks": true,
  "wildcardProbeCount": 3,
  "timeoutMinutes": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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 = {
    "domains": [
        "onescales.com"
    ],
    "sources": [
        "crtsh",
        "hackertarget",
        "rapiddns",
        "dnsbruteforce"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("thirdwatch/subdomain-finder").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 = {
    "domains": ["onescales.com"],
    "sources": [
        "crtsh",
        "hackertarget",
        "rapiddns",
        "dnsbruteforce",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("thirdwatch/subdomain-finder").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 '{
  "domains": [
    "onescales.com"
  ],
  "sources": [
    "crtsh",
    "hackertarget",
    "rapiddns",
    "dnsbruteforce"
  ]
}' |
apify call thirdwatch/subdomain-finder --silent --output-dataset

```

## MCP server setup

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

```

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/i4VqBrrc0U3EL7BeT/builds/1eFaNKkmVI8MUcxDf/openapi.json
