# Subdomain Finder - CT Log Enumeration + Live DNS Check (`eliai/subdomain-finder`) Actor

Enumerate a domain's subdomains from Certificate Transparency logs, with an optional live DNS resolve. All subdomains in one record. $0.005 per domain (not per subdomain), far cheaper than paid finders; failures are free.

- **URL**: https://apify.com/eliai/subdomain-finder.md
- **Developed by:** [Broke to Built](https://apify.com/eliai) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 checked domains

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 - CT-log enumeration + live DNS check

Discover a domain's **subdomains** from public **Certificate Transparency logs** (crt.sh), then
optionally **DNS-resolve** each one to see which are live and collect their IPs. One clean record
per domain listing every subdomain found. Built for attack-surface mapping, asset inventory, and
recon.

**$0.005 per domain - all its subdomains in one record, not per subdomain.** Every other paid
subdomain actor bills **per subdomain**, so a domain with 100+ subdomains costs dollars there and
half a cent here. Failures are recorded free.

### What you get

- **CT-log enumeration** via crt.sh for `%.<domain>` - catches subdomains that never appear in DNS brute-force lists.
- **Optional live DNS check** (`resolve`): A/AAAA lookup + CNAME fallback, marks `resolves` and collects `ips`.
- **De-duplicated**, scoped strictly to the target domain, sorted.
- **Fail-soft**: a domain with no CT records returns `subdomainCount: 0` gracefully.

### Input

```json
{ "domain": "github.com", "domains": ["example.com"], "resolve": true, "maxDomains": 25 }
```

### Output (real run, 2026-08-07 - 115 subdomains for github.com)

```json
{
  "ok": true,
  "domain": "github.com",
  "subdomainCount": 115,
  "subdomains": [
    { "name": "api.mcp.github.com", "resolves": null, "ips": [] },
    { "name": "api.security.github.com", "resolves": null, "ips": [] },
    { "name": "camo.github.com", "resolves": null, "ips": [] }
  ],
  "checkedAt": "2026-08-07T21:12:00.000Z"
}
```

With `resolve: true`, each subdomain also carries `resolves: true/false` and an `ips` array.

### Pricing - $0.005 per domain, all subdomains included

Every incumbent bills per subdomain; this actor bills per **domain**. Prices checked via the Apify
Store API on 2026-08-07:

| Actor | Pricing | A domain with 115 subdomains |
|---|---|---|
| **This actor** | **$0.005 per domain** | **$0.005** |
| happitap/subdomain-finder | $0.0008 per subdomain | $0.092 |
| andok/subdomain-finder | $0.001 per subdomain | $0.115 |
| ntriqpro/subfinder-osint | $0.01 per subdomain-found | $1.15 |

Per-subdomain billing is only cheaper for domains with fewer than ~6 subdomains; for any real
target this actor is far cheaper.

### Limits (honest ones)

- Source is Certificate Transparency (crt.sh) - subdomains that never had a public certificate won't appear (no DNS brute-forcing).
- crt.sh is a third-party service; a rare timeout returns a graceful `{ok:false, error}` record, uncharged.
- With `resolve: true`, large domains take longer (DNS per subdomain, bounded concurrency).
- `maxDomains` capped at 100 per run.

### FAQ

- **Where do the subdomains come from?** Public Certificate Transparency logs via crt.sh - real certificates issued for the domain.
- **Does it brute-force names?** No - CT logs only. That avoids noise and rate-limiting, and finds names a wordlist would miss.
- **What does `resolve` do?** Runs a live DNS lookup on each subdomain so you can tell which are actually up.
- **Why one record per domain?** So you pay once per target, however many subdomains it has.

### When not to use this

- **You need internal or never-certificated hosts.** CT logs only contain names that appeared on a
  public certificate. A staging box on plain HTTP, or one behind a wildcard cert, will not show up.
  A DNS brute-forcer with a wordlist is the tool for that, and it costs far more per target.
- **You need real-time discovery.** CT logs lag issuance by minutes to hours, and crt.sh indexes on
  its own schedule. A subdomain created five minutes ago may not be there yet.
- **You want port scans, tech fingerprints or screenshots of each host.** This returns names and (with
  `resolve: true`) IPs. Feed those into a scanner or into our HTTP Headers Inspector for the next step.
- **You only care about one known hostname's DNS records.** Use a DNS records lookup instead - this
  actor's job is discovering names you did not know about.
- **You are not authorized to enumerate the target.** CT logs are public, but what you do with an
  attack-surface map is your responsibility.

### Use from code or AI agents

```bash
curl -X POST "https://api.apify.com/v2/acts/EliAI~subdomain-finder/runs?token=YOUR_APIFY_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"domain":"github.com","resolve":true}'
```

Callable as an agent tool through the Apify MCP server (`mcp.apify.com`).

### Related actors

- **DNS Records Lookup** (`EliAI/dns-records-lookup`) - returns every DNS record type (A, AAAA, MX, TXT, NS, CNAME, SOA, CAA, SRV) for a single domain. This actor **discovers subdomain names** from Certificate Transparency logs; that one **dumps the DNS records** of a name you already have.

# Actor input Schema

## `domain` (type: `string`):

A single domain to find subdomains for (e.g. github.com). Scheme/path/wildcards are stripped automatically.

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

Multiple domains to scan in one run.

## `resolve` (type: `boolean`):

Resolve each discovered subdomain to mark it live and collect IPs. Turn off for a faster passive-only listing.

## `maxDomains` (type: `integer`):

Cap on how many domains to process per run.

## Actor input object example

```json
{
  "domain": "github.com",
  "domains": [
    "apify.com"
  ],
  "resolve": true,
  "maxDomains": 25
}
```

# Actor output Schema

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

Every item this run produced, as JSON.

## `resultsCsv` (type: `string`):

The same items as a spreadsheet-ready CSV.

# 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 = {
    "domain": "github.com",
    "domains": [
        "apify.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("eliai/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 = {
    "domain": "github.com",
    "domains": ["apify.com"],
}

# Run the Actor and wait for it to finish
run = client.actor("eliai/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 '{
  "domain": "github.com",
  "domains": [
    "apify.com"
  ]
}' |
apify call eliai/subdomain-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,eliai/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/FtcOONk3k0kWDz46c/builds/1BvShgcJ2tNzAMWSG/openapi.json
