# TLSX - TLS Data Gathering and Analysis (`rl1987/pd-tlsx`) Actor

Apify Actor wrapper for ProjectDiscovery's tlsx, a fast and configurable TLS grabber for TLS-based data collection and analysis.

- **URL**: https://apify.com/rl1987/pd-tlsx.md
- **Developed by:** [R.L.](https://apify.com/rl1987) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / actor invocation

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## TLSX — TLS Recon & Subdomain Discovery from X.509 Certificates

Cloud-hosted wrapper around ProjectDiscovery's [tlsx](https://github.com/projectdiscovery/tlsx). Point it at hosts, IP ranges, or ASNs and pull back structured TLS/certificate data — no local Go toolchain, no binary to install.

### Why use this

TLS certificates leak infrastructure. The **Subject Alternative Name (SAN)** and **Common Name (CN)** fields on a cert routinely list every hostname it covers — internal tools, staging environments, forgotten subdomains — even ones that never show up in DNS brute-force wordlists or search-engine indexes. This actor grabs that data at scale and hands it back as clean JSON rows, ready to feed into a dataset, a spreadsheet, or the next stage of a recon pipeline.

Typical use cases:

- **Subdomain discovery for bug bounty / pentest recon** — scan a target's IP ranges (CIDR) or ASN and collect every hostname referenced in certs served on those IPs. Great for finding hosts that DNS enumeration misses.
- **Attack surface mapping** — enumerate TLS/cipher support, flag expired, self-signed, mismatched, revoked, or untrusted certificates across a fleet of hosts.
- **Fingerprinting** — grab JARM/JA3 TLS fingerprints to cluster or identify backend infrastructure (e.g. shared C2, CDN, or hosting provider) across otherwise unrelated hostnames.
- **Cert monitoring** — check expiry dates and issuer chains across your own domains before something breaks in production.
- **Certificate Transparency (CT) log streaming** — tap the live CT log firehose for near-real-time discovery of newly issued certs matching infrastructure you care about.

Only scan targets you're authorized to test.

### Input

Give it targets and (optionally) which data to pull. Targets accept IP, CIDR, ASN, hostname, hostname:port, or full URL:

```json
{
  "host": ["example.com", "173.0.84.0/24", "AS1449"]
}
```

For subdomain discovery from certs, the default settings already return SAN/CN data in every result — no extra flags needed. Just feed it hosts or IP ranges and read `subject_an` / `subject_cn` from the output.

The full input schema (`.actor/actor.json`) mirrors nearly every `tlsx` CLI flag, grouped by purpose:

- **Targets & scan mode** — hosts/CIDR/ASN, ports, IP version, `ctls`/`ztls`/`openssl`/`auto` connection mode, pre-handshake early termination
- **Probes** — fingerprint hashes, JARM, JA3, wildcard cert detection, TLS version / cipher enumeration, certificate serial
- **Misconfiguration checks** — expired, self-signed, mismatched, revoked, untrusted certificates
- **Connection config** — custom resolvers, SNI, min/max TLS version, custom ciphers, SOCKS5 proxy, cert verification
- **Optimizations** — concurrency, per-target timeout, retries, delay
- **CT log streaming** — live firehose mode, bounded by `maxRuntimeSecs` since it otherwise never terminates
- **PDCP dashboard upload** — push results to ProjectDiscovery's Cloud Platform

An `extraFlags` field is included as an escape hatch for anything not explicitly modeled.

Notes:

- The JSON output always includes SAN/CN/cipher/TLS-version/probe-status regardless of the remaining display-only probe flags (`-tv`, `-cipher`, ...) — those only affect plain-text CLI output, which this actor doesn't use. `-san`/`-cn` aren't exposed as inputs at all: `tlsx` hard-rejects combining them with any other display probe, and the JSON output includes that data unconditionally anyway.
- `cacert` expects inline PEM content (pasted in), not a filesystem path.

### Output

One dataset row per scanned host/port, in `tlsx`'s native JSON shape:

```json
{
  "host": "example.com",
  "ip": "93.184.216.34",
  "port": "443",
  "probe_status": true,
  "tls_version": "tls13",
  "cipher": "TLS_AES_256_GCM_SHA384",
  "subject_cn": "www.example.org",
  "subject_an": ["www.example.org", "example.net", "example.com", "..."],
  "issuer_cn": "DigiCert TLS RSA SHA256 2020 CA1",
  "not_before": "2022-03-14T00:00:00Z",
  "not_after": "2023-03-14T23:59:59Z"
}
```

`subject_an` is the field to pull for subdomain discovery — export it, dedupe, and feed into DNS resolution or an HTTP prober for the next recon step. The raw newline-delimited JSON is also saved to the key-value store under `RAW_OUTPUT`.

# Actor input Schema

## `host` (type: `array`):

Target host(s) to scan. Accepts IP, CIDR, ASN, DNS name, DNS name with port, or URL (-u/-host).

## `port` (type: `array`):

Target port(s) to connect to (-p/-port). Default 443.

## `scanMode` (type: `string`):

TLS connection mode to use (-sm/-scan-mode).

## `preHandshake` (type: `boolean`):

Enable pre-handshake TLS connection using ztls (-ps/-pre-handshake).

## `scanAllIps` (type: `boolean`):

Scan all resolved IPs for a host (-sa/-scan-all-ips).

## `ipVersion` (type: `array`):

IP version(s) to use (-iv/-ip-version). Values: 4, 6.

## `so` (type: `boolean`):

-so

## `tlsVersion` (type: `boolean`):

-tv/-tls-version

## `cipher` (type: `boolean`):

-cipher

## `hash` (type: `array`):

-hash. Values: md5, sha1, sha256.

## `jarm` (type: `boolean`):

-jarm

## `ja3` (type: `boolean`):

-ja3

## `wildcardCert` (type: `boolean`):

-wc/-wildcard-cert

## `probeStatus` (type: `boolean`):

-tps/-probe-status

## `versionEnum` (type: `boolean`):

-ve/-version-enum

## `cipherEnum` (type: `boolean`):

-ce/-cipher-enum

## `cipherType` (type: `array`):

-ct/-cipher-type. Values: all, secure, insecure, weak.

## `clientHello` (type: `boolean`):

-ch/-client-hello

## `serverHello` (type: `boolean`):

-sh/-server-hello

## `serial` (type: `boolean`):

-se/-serial

## `expired` (type: `boolean`):

-ex/-expired

## `selfSigned` (type: `boolean`):

-ss/-self-signed

## `mismatched` (type: `boolean`):

-mm/-mismatched

## `revoked` (type: `boolean`):

-re/-revoked

## `untrusted` (type: `boolean`):

-un/-untrusted

## `resolvers` (type: `array`):

-r/-resolvers

## `cacert` (type: `string`):

-cc/-cacert (path or inline PEM content, written to a temp file).

## `cipherInput` (type: `array`):

-ci/-cipher-input

## `sni` (type: `array`):

-sni

## `randomSni` (type: `boolean`):

-rs/-random-sni

## `revPtrSni` (type: `boolean`):

-rps/-rev-ptr-sni

## `minVersion` (type: `string`):

-min-version

## `maxVersion` (type: `string`):

-max-version

## `certificate` (type: `boolean`):

-cert/-certificate

## `tlsChain` (type: `boolean`):

-tc/-tls-chain

## `verifyCert` (type: `boolean`):

-vc/-verify-cert

## `hardfail` (type: `string`):

-hf/-hardfail

## `proxy` (type: `string`):

-proxy

## `concurrency` (type: `integer`):

-c/-concurrency

## `cipherConcurrency` (type: `integer`):

-cec/-cipher-concurrency

## `timeout` (type: `integer`):

-timeout

## `retry` (type: `integer`):

-retry

## `delay` (type: `string`):

-delay (e.g. 200ms, 1s)

## `ctl` (type: `boolean`):

-ctl. Streams newly issued certs. Bounded by maxRuntimeSecs since this mode never terminates on its own.

## `ctlBeginning` (type: `boolean`):

-cb/-ctl-beginning

## `ctlIndex` (type: `array`):

-cti/-ctl-index. Format logURL=index, repeatable.

## `maxRuntimeSecs` (type: `integer`):

Actor-level guard applied via `timeout` when CT log streaming is enabled, since -ctl runs indefinitely.

## `dashboard` (type: `boolean`):

-pd/-dashboard

## `auth` (type: `string`):

-auth

## `teamId` (type: `string`):

-tid/-team-id

## `assetId` (type: `string`):

-aid/-asset-id

## `assetName` (type: `string`):

-aname/-asset-name

## `extraFlags` (type: `string`):

Escape hatch: any additional tlsx flags appended verbatim to the command line.

## Actor input object example

```json
{
  "host": [
    "example.com"
  ],
  "scanMode": "auto",
  "preHandshake": false,
  "scanAllIps": false,
  "so": false,
  "tlsVersion": false,
  "cipher": false,
  "jarm": false,
  "ja3": false,
  "wildcardCert": false,
  "probeStatus": false,
  "versionEnum": false,
  "cipherEnum": false,
  "clientHello": false,
  "serverHello": false,
  "serial": false,
  "expired": false,
  "selfSigned": false,
  "mismatched": false,
  "revoked": false,
  "untrusted": false,
  "randomSni": false,
  "revPtrSni": false,
  "minVersion": "",
  "maxVersion": "",
  "certificate": false,
  "tlsChain": false,
  "verifyCert": false,
  "concurrency": 300,
  "cipherConcurrency": 10,
  "timeout": 5,
  "retry": 3,
  "ctl": false,
  "ctlBeginning": false,
  "maxRuntimeSecs": 60,
  "dashboard": 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 = {
    "host": [
        "example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("rl1987/pd-tlsx").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 = { "host": ["example.com"] }

# Run the Actor and wait for it to finish
run = client.actor("rl1987/pd-tlsx").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 '{
  "host": [
    "example.com"
  ]
}' |
apify call rl1987/pd-tlsx --silent --output-dataset

```

## MCP server setup

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

```

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/ulsO8osUgUToqSfdC/builds/uqzHXAKHVt8W5hivT/openapi.json
