# Email OSINT Account Search (`khadinakbar/email-osint-search`) Actor

Check email addresses for public account-registration signals across a pinned 121-service catalog. Returns one privacy-safe scan record per email with found sites, categories, uncertainty, source domains, and timestamps for authorized OSINT research.

- **URL**: https://apify.com/khadinakbar/email-osint-search.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Lead generation, Social media, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $100.00 / 1,000 email scanned across selected account-check sites

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?

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

## Email OSINT Account Search — 120+ Sites

Email OSINT Account Search checks an authorized email address against a pinned catalog of 121 public account-registration modules and returns one structured scan record per email. It is designed for consent-based security testing, personal account-footprint reviews, brand protection, and threat-intelligence triage. Each service result is labeled `FOUND`, `NOT_FOUND`, or `INCONCLUSIVE`; a positive response is an account-registration signal, not proof of identity, ownership, or activity.

### Best fit

Use this Actor when you start with one to three full email addresses and need a broad, repeatable account-signal sweep across social, developer, shopping, media, gaming, forum, productivity, business, and other services. The output preserves the catalog version, selected service names, source domains, detection method, rate-limit state, and scan timestamp so an analyst can review the result instead of treating a green check as certainty.

### Scope boundary

This Actor is intended for authorized assessments such as personal account-footprint reviews, consent-based security work, defensive brand protection, and documented threat-intelligence triage. Its read-only probes provide account-registration signals; credentials, password submission, reset completion, messages, private profiles, full recovery contacts, and raw provider payloads stay outside the product surface. Email deliverability workflows belong with an email validation tool.

### Output: one record per email

One dataset item represents one completed email scan. By default, `results` contains positive and inconclusive service signals; set `includeNotFound` to `true` when you need every checked service.

| Field | Meaning |
|---|---|
| `email` | Normalized input address matched to the scan record |
| `catalogVersion` | Pinned module catalog version (`holehe-1.61`) |
| `sitesTargeted` / `sitesChecked` | Selected and completed service-module counts |
| `accountsFound` | Count of `FOUND` service responses |
| `notFoundCount` | Count of negative service responses |
| `inconclusiveCount` | Rate-limited, challenge, timeout, or transport-response rows |
| `scanIncomplete` | Whether the per-email timeout left modules pending |
| `sitesTargetedNames` | Stable names of every selected module, including hidden negative rows |
| `results[]` | Service, domain, category, status, detection method, and rate-limit signal |
| `scannedAt` | ISO 8601 persistence timestamp |

Example result shape (illustrative values; the run output is the source of truth):

```json
{
  "email": "analyst@example.com",
  "scannedAt": "ISO-8601 scan timestamp",
  "catalogVersion": "holehe-1.61",
  "sitesTargeted": 121,
  "sitesChecked": 121,
  "accountsFound": 2,
  "notFoundCount": 116,
  "inconclusiveCount": 3,
  "scanIncomplete": false,
  "scanDurationMs": 48200,
  "resultsReturned": 5,
  "sitesTargetedNames": ["github", "gravatar", "instagram"],
  "filters": {
    "includeAdultSites": true,
    "includeRecoveryChecks": true,
    "includeNotFound": false,
    "includeInconclusive": true,
    "siteCategories": [],
    "maxSites": 121
  },
  "results": [
    {
      "site": "github",
      "domain": "github.com",
      "sourceUrl": "https://github.com",
      "category": "developer",
      "status": "FOUND",
      "detectionMethod": "register",
      "isAdult": false,
      "rateLimited": false,
      "signalType": "site_registration_response"
    },
    {
      "site": "instagram",
      "domain": "instagram.com",
      "sourceUrl": "https://instagram.com",
      "category": "social",
      "status": "INCONCLUSIVE",
      "detectionMethod": "register",
      "isAdult": false,
      "rateLimited": true,
      "signalType": "rate_limited_or_error",
      "errorClass": "module_exception"
    }
  ],
  "_note": "FOUND means the service returned an account-registration signal; it is not proof of identity or account ownership."
}
```

### Input

The required input is an `emails` array with one to three full addresses. The email field is marked secret in the Apify schema; keep credentials and unrelated personal data out of the other fields.

```json
{
  "emails": ["analyst@example.com"],
  "includeAdultSites": true,
  "includeRecoveryChecks": true,
  "includeNotFound": false,
  "includeInconclusive": true,
  "siteCategories": [],
  "maxSites": 121,
  "concurrency": 25,
  "requestTimeoutSecs": 8,
  "scanTimeoutSecs": 90,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

The full catalog is the default. Set `includeAdultSites` to `false` for a narrower investigation, `includeRecoveryChecks` to `false` when recovery-style signals are out of scope, or use `siteCategories` and `maxSites` to keep a run small. `concurrency`, request timeout, and total per-email timeout control runtime and rate pressure; they leave the account-signal meaning unchanged.

### How it works

1. Input is normalized and validated without writing target addresses to logs or terminal summaries.
2. The pinned Holehe 1.61 package is loaded without invoking its CLI or update checker.
3. Selected modules run with bounded concurrency through one consistent proxy session per email.
4. Raw module responses are reduced to service domain, category, detection method, status, and rate-limit state. Masked recovery hints and unrelated metadata stay out of the dataset.
5. One validated dataset row is written per completed email and coupled to the `email-scanned` event. `OUTPUT`, `RUN_SUMMARY`, and `SUMMARY` record the terminal result.

### Interpret the statuses

- `FOUND`: the service returned a positive account-registration signal for the supplied address.
- `NOT_FOUND`: the service returned its negative/no-registration response.
- `INCONCLUSIVE`: the service was rate-limited, presented a challenge, timed out, raised an exception, or returned no usable module response.

`FOUND` is an account-registration signal, not an identity match. Services can have stale accounts, shared addresses, alias behavior, false positives, or changing anti-enumeration responses. Treat the output as a lead for authorized review and corroborate it through lawful, independent evidence.

### Workflow story

An incident responder starts with an address from an approved case file, runs one bounded scan, and reviews `accountsFound`, `inconclusiveCount`, `category`, `sourceUrl`, and `scannedAt`. The responder exports the compact positive and uncertain rows to the case record, expands to `includeNotFound: true` when a complete service matrix is needed, and records every conclusion alongside independent evidence. A single service response is treated as one lead in the investigation rather than as identity proof.

### Focused standalone workflow

This Actor is designed as a focused standalone workflow: email in, account-registration signals out. Its one-record-per-email contract keeps the scan easy for an operator or AI agent to call, review, and pass into an authorized case-management process.

### Pricing

The Actor uses Pay per event plus Apify platform usage. The primary event is `email-scanned`, charged once per completed email scan; the Actor Start event is charged separately by Apify. The live Pricing tab is the source of truth for the effective event price and platform-usage setting.

The initial event price is designed for a bounded full-catalog scan:

```text
event cost = completed email scans × email-scanned price
estimated total = event cost + Apify platform usage and proxy usage
```

For example, a one-address scan creates at most one `email-scanned` event. Use one-email runs for the simplest cost and evidence boundary. Residential proxy usage can be the larger variable cost for a 121-service sweep.

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/khadinakbar~email-osint-search/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": ["analyst@example.com"],
    "includeAdultSites": false,
    "includeRecoveryChecks": true,
    "includeNotFound": false,
    "maxSites": 121,
    "concurrency": 25,
    "requestTimeoutSecs": 8,
    "scanTimeoutSecs": 90
  }'
```

After processing finishes, read the returned `defaultDatasetId` and fetch `https://api.apify.com/v2/datasets/{DATASET_ID}/items?clean=true&format=json`. The `OUTPUT` and `RUN_SUMMARY` KV records explain partial scans, inconclusive responses, and charge-limit stops.

### Use with AI agents through Apify MCP

The regular run Actor is exposed through the Apify MCP server. An agent should have an authorized email address, choose the minimum scope needed, and preserve the distinction between `FOUND` and `INCONCLUSIVE`.

> Run an authorized email OSINT account-signal scan for `analyst@example.com`. Check the default 121-service catalog, omit adult modules, return FOUND and INCONCLUSIVE rows, and summarize the source domain, category, detection method, and rate-limit state. Treat FOUND as a registration signal for authorized review, with identity and ownership corroborated separately.

Tool identity: `khadinakbar/email-osint-search` through [Apify MCP](https://docs.apify.com/platform/integrations/mcp).

### Reliability and limits

- The catalog is pinned to `holehe==1.61` so module discovery is reproducible between builds; service endpoints and anti-automation behavior can still change.
- A full scan means 121 configured modules in the pinned dependency, not a guarantee that every service is reachable or that every service supports the same signal quality.
- The Actor preserves uncertainty rather than treating blocks or timeouts as negative results.
- Maximum input is three addresses per run, and the default scan has a 90-second per-email bound.
- Use an Apify Residential proxy or a caller-managed route when the target services rate-limit shared cloud IPs. Platform and proxy usage are additional to event charges.
- Cookies, passwords, login sessions, password-reset completion, email delivery, private content, full recovery contacts, and raw response bodies stay outside the collection contract.

### Builder's note

I built the wrapper around a pinned upstream module catalog because the useful part of this workflow is the consistent result contract, not a claim that every service behaves identically. I designed `INCONCLUSIVE` as a first-class status after seeing how quickly account-enumeration endpoints change their response shape or apply rate limits. That decision keeps a partial scan useful while making uncertainty visible to both operators and agents.

### Third-party attribution

This Actor installs the upstream `holehe==1.61` Python package at build time. Holehe is GPL-3.0 licensed and its upstream module catalog is the source of the 121 checks. See `THIRD_PARTY_NOTICES.md` in the project source for attribution and the exact pinned dependency. The Actor wrapper and Apify schemas are separate project code.

### Legal and responsible-use notice

Use this Actor for addresses and services you are authorized to assess, such as your own accounts, a consent-based security engagement, or a documented defensive investigation. Account-existence checks can expose sensitive personal information and may be restricted by law, contracts, or a service's terms. The operator is responsible for authorization, notice, retention, access controls, and lawful handling of every result.

# Actor input Schema

## `emails` (type: `array`):

Use this when you need an account-footprint scan for one or more addresses you are authorized to investigate. Pass full strings such as \["name@example.com"] or \["a@example.com", "b@example.org"]. Up to 3 addresses are accepted per run and each completed address is one billable scan. This is not a username or domain-only input.

## `includeAdultSites` (type: `boolean`):

Use this when adult-site registration signals are in scope for an authorized brand-protection or security investigation. Set true to include the adult-tagged modules in the 120+ catalog; it defaults to true so a full catalog scan is the normal behavior. Set false to omit those modules and their results. This does not retrieve adult content or profile data.

## `includeRecoveryChecks` (type: `boolean`):

Use this when the investigation permits public password-recovery or login-form account-existence signals. It defaults to true to preserve the full Holehe 1.61 catalog, including four recovery-style modules. Set false to omit those modules when your rules prohibit that signal type. The Actor never submits a password, completes a reset, or sends a message.

## `includeNotFound` (type: `boolean`):

Use this when you need an auditable row for every checked service, including services that returned no registration signal. It defaults to false so the dataset focuses on FOUND and INCONCLUSIVE results while counts still report NOT\_FOUND totals. Set true to return every service result. This does not change which services are checked or billed.

## `includeInconclusive` (type: `boolean`):

Use this when blocked, rate-limited, timed-out, or error responses need to remain visible for review. It defaults to true because an inconclusive response must not be mistaken for NOT\_FOUND. Set false only when you want a compact FOUND-only or FOUND-plus-NOT\_FOUND result list. The top-level inconclusive count remains available either way.

## `siteCategories` (type: `array`):

Use this to limit a scan to named categories and reduce runtime or scope. Pass values such as \["social", "developer"] or \[] for all available categories. The default is \[] and categories are deduplicated before selection. This is not a list of individual site names; use maxSites for a simple cap.

## `maxSites` (type: `integer`):

Use this to cap the number of site modules selected after category and safety filters. Values from 1 to 121 are accepted and the default is 121 for the full pinned catalog. The first modules are selected in stable alphabetical order, which makes repeated runs comparable. This is a site-count cap, not a concurrency control.

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

Use this to control how many site modules run at once for each email. Values from 1 to 50 are accepted and the default is 25 for a balanced 512 MB run. Lower it when a target service is rate-sensitive; raise it only when you accept more simultaneous requests. This does not run multiple email addresses concurrently.

## `requestTimeoutSecs` (type: `integer`):

Use this to bound the wait for each public site response. Values from 3 to 30 seconds are accepted and the default is 8 seconds, which keeps the full catalog inside ordinary Actor health-test windows. A timeout becomes an INCONCLUSIVE result rather than a false NOT\_FOUND. This is not the total scan timeout.

## `scanTimeoutSecs` (type: `integer`):

Use this to cap the complete site sweep for each email. Values from 30 to 180 seconds are accepted and the default is 90 seconds. Pending modules are returned as INCONCLUSIVE when this limit is reached, so partial evidence remains visible. This is not a guarantee that every target service responds within the limit.

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

Use this when target services require an Apify proxy or a caller-managed proxy policy. The default uses Apify Residential proxies, while an empty object disables the proxy. Supply only Apify-supported proxy configuration and never put credentials in this field. This controls network routing, not account authentication.

## Actor input object example

```json
{
  "emails": [
    "security-test@example.com"
  ],
  "includeAdultSites": true,
  "includeRecoveryChecks": true,
  "includeNotFound": false,
  "includeInconclusive": true,
  "siteCategories": [],
  "maxSites": 121,
  "concurrency": 25,
  "requestTimeoutSecs": 8,
  "scanTimeoutSecs": 90,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

Default dataset with one record per completed email scan and its per-service account signals.

## `datasetItemsCsv` (type: `string`):

Default dataset exported as CSV for review or downstream processing.

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

Compact run totals and terminal outcome without repeating target email values.

## `output` (type: `string`):

Terminal outcome, scan counts, found account-signal totals, and charged-event counts.

## `runSummary` (type: `string`):

Detailed outcome contract including filters, warning categories, errors, and charge-limit state.

## `consoleRun` (type: `string`):

Direct link to inspect logs, dataset rows, and terminal KV records.

# 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 = {
    "emails": [
        "security-test@example.com"
    ],
    "maxSites": 121,
    "concurrency": 25,
    "requestTimeoutSecs": 8,
    "scanTimeoutSecs": 90
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/email-osint-search").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 = {
    "emails": ["security-test@example.com"],
    "maxSites": 121,
    "concurrency": 25,
    "requestTimeoutSecs": 8,
    "scanTimeoutSecs": 90,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/email-osint-search").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 '{
  "emails": [
    "security-test@example.com"
  ],
  "maxSites": 121,
  "concurrency": 25,
  "requestTimeoutSecs": 8,
  "scanTimeoutSecs": 90
}' |
apify call khadinakbar/email-osint-search --silent --output-dataset

```

## MCP server setup

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

```

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/3AfTCyKVNLGO7rIC2/builds/Rxh9lSJY7YaEDQCtR/openapi.json
