# TikTok Public Business Email Scraper (`automation-lab/tiktok-public-business-emails`) Actor

Extract explicitly published professional contact emails from supplied public TikTok profile bios, with creator identity and source attribution. No guessed emails or verification.

- **URL**: https://apify.com/automation-lab/tiktok-public-business-emails.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Lead generation, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.34 / 1,000 published business emails

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?

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

## TikTok Public Business Email Scraper

Refresh supplied creator rosters with TikTok profile emails explicitly published for professional contact. This Actor reads public TikTok bios and returns one source-attributed row per qualifying email. It does not guess addresses, consult a private database, message creators or claim deliverability.

### Who is it for?

Creator partnership teams and agencies can refresh an existing list of public creator handles before manually reviewing professional contact options. Researchers can retain the profile URL, observed context and timestamp for attribution. This is not a people-search or private-contact product.

### Why use this Actor?

- Only literal addresses observed on the supplied public profile are candidates.
- Professional wording must accompany the address; an unlabeled email is omitted.
- No browser login, customer cookies, external-link crawling or paid enrichment is required.
- You receive the evidence line, not an opaque confidence score.
- Missing professional contacts create no placeholder dataset rows or contact event charges.

### Getting started

1. Supply 1–100 creator usernames or canonical public profile URLs.
2. Choose a global contact-row limit, or keep the default of 100.
3. Run the Actor and inspect the default dataset.
4. Review `contactContext` and `sourceUrl` before any permitted downstream use.
5. Export with Apify's normal JSON, CSV or spreadsheet dataset tools.

Example input:

```json
{"profiles":["mikaylanogueira","gordonramsayofficial"],"maxItems":100}
```

These profiles are examples, not guaranteed contact sources. Bios change independently of the Actor.

### Input parameters

| Field | Meaning |
| --- | --- |
| `profiles` | Required array of 1–100 usernames, @handles or HTTPS `tiktok.com/@handle` URLs. |
| `maxItems` | Global accepted email-row limit, omitted-input default 100, Console prefill 10, minimum 1, maximum 1000. |

Handles are trimmed and compared case-insensitively. Duplicate input handles are fetched once, in input order. Profile URLs cannot contain query strings, fragments, credentials or video paths. Other input fields are rejected rather than silently ignored.

The row limit applies after contact exclusions and within-profile email deduplication. Fetching stops when the limit is reached. A profile can yield several rows. The same address published on two different profiles remains two attributable records. There is no unlimited mode or profile discovery.

### How professional context is selected

The email's line must contain a whole-word professional cue such as business, PR, press, collab, collaboration, partnership, booking, management, sponsorship, commercial, inquiry or enquiry (including supported plural forms). Matching is case-insensitive. Alternatively, the immediately preceding line can be the professional label, provided that label line contains no email.

The Actor conservatively skips a bio containing explicit personal/private, school/homework, dating, donation, minor, under-18 or ages 10–17 years-old wording. Private accounts are excluded. This heuristic can omit legitimate business contacts and cannot establish a person's age or legal status. Public availability is not consent to contact someone.

An email alone, an envelope emoji, or a generic “email” label is insufficient. Obfuscated addresses such as `name [at] company` are not reconstructed. External websites, Linktree, comments and other social profiles are not followed.

### Extracted data

| Field | Meaning |
| --- | --- |
| `username` | Observed TikTok handle. |
| `displayName` | Public display name, possibly empty. |
| `userId` | TikTok identifier stored as a string. |
| `email` | Literal published address, preserving observed case. |
| `profileUrl` | Canonical creator URL. |
| `sourceUrl` | Public profile where the contact was observed. |
| `contactContext` | Email line and preceding professional label when used. |
| `observedAt` | UTC observation time, not the profile's update date. |

One row has this shape (identity and address anonymized):

```json
{
  "username":"examplecreator",
  "displayName":"Example Creator",
  "userId":"7123456789012345678",
  "email":"business@example.com",
  "profileUrl":"https://www.tiktok.com/@examplecreator",
  "sourceUrl":"https://www.tiktok.com/@examplecreator",
  "contactContext":"Business: business@example.com",
  "observedAt":"2026-10-18T12:00:00.000Z"
}
```

### How much does it cost to extract TikTok business emails?

Pay-per-event pricing includes one $0.005 start event per run and one event per saved qualifying contact row. The BRONZE contact price is $0.00556. Example totals including the start fee: 1 row — $0.01056; 10 rows — $0.0606; 100 rows — $0.561. Your plan's applicable rate appears in the pricing panel.

No contact event is charged for duplicates within a profile, excluded addresses, failed requests or profiles with no qualifying contact. The start fee still applies to a valid run with zero contacts. Invalid input is rejected before the start charge. Previously saved rows in a later-failing run remain partial results and can already be charged.

### Limits and failure behavior

TikTok may return a challenge, throttle requests or change its profile response. Missing hydration, mismatched profile identity and unknown upstream errors fail the run rather than pretending no contacts exist. Explicit not-found responses and private accounts produce no contacts.

Requests are sequential, with a 20-second request timeout. Transient network errors, HTTP 429 and HTTP 5xx can receive one retry. There is no automatic residential fallback, proxy input or login mode. The default run timeout is 300 seconds; large or slow lists can time out and should be split into smaller batches. A failed run's dataset may be partial.

### Run summary

The key-value store record `RUN_SUMMARY` reports requested and scanned profiles, accepted contacts, request and retry counts, response bytes and whether the row limit was reached. It is written on normal completion and is included in the run. An empty dataset plus a successful summary means no qualifying contacts were observed, not that all supplied profiles contain no email anywhere.

### Integrations

Use Apify dataset exports with Sheets for manual contact review, or connect the dataset to your existing Make, Zapier or CRM workflow under your own lawful-use controls. To refresh a roster, schedule this Actor with the same input and compare `username` plus `email` downstream. The Actor does not maintain history, calculate changes, monitor creators or send alerts itself.

### API usage

Start a run with your token held in an environment variable:

```bash
curl -X POST 'https://api.apify.com/v2/acts/automation-lab~tiktok-public-business-emails/runs' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"profiles":["mikaylanogueira"],"maxItems":10}'
```

JavaScript using the official client:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/tiktok-public-business-emails')
  .call({ profiles: ['mikaylanogueira'], maxItems: 10 });
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 10 });
console.log(items);
```

Python:

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/tiktok-public-business-emails').call(
    run_input={'profiles': ['mikaylanogueira'], 'maxItems': 10})
print(client.dataset(run['defaultDatasetId']).list_items(limit=10).items)
```

### MCP setup

Select a stable Actor-specific tool subset:

```bash
claude mcp add --transport http apify \
  'https://mcp.apify.com?tools=automation-lab/tiktok-public-business-emails'
```

Equivalent Claude Desktop, Cursor and VS Code configuration:

```json
{"mcpServers":{"apify":{"url":"https://mcp.apify.com?tools=automation-lab/tiktok-public-business-emails"}}}
```

Example prompt: “Read these supplied public TikTok profiles for explicitly published professional contact emails. Return the email and source context, without guessing or sending messages.”

Use scoped `tools/list` to discover actual argument schemas. Actor selection also exposes run and storage helper tools, not exactly one tool. Discovery does not authorize execution.

For an authorized run, start once and keep the returned run and storage IDs. A call may return before completion. Follow the same run with bounded backoff (2, 4, 8 seconds, capped at 10), stopping after a 120-second consumer deadline. Set client timeouts above the selected server wait plus transport margin. Recover a known run after client timeout; never blindly restart. At deadline report pending with its run ID. Terminal failures remain failures, with any rows labeled partial.

After success, read bounded dataset pages using explicit limit, offset and required fields. For example, process pages of 20 host-side, admitting at most 100 rows or 64 KiB serialized UTF-8 into model context. Track source offsets; stop at exhaustion or budget and disclose the continuation offset and any truncation. Enforce byte limits before model injection, including oversized rows. Without interception, do not promise a hard byte guarantee. Full exports stay outside model context. These are consumer context limits, not Actor collection limits. Client caching or progressive loading does not imply universal token savings.

### Legality, responsible use and privacy

Use only professional public-profile inputs you are entitled to process. Respect applicable law, TikTok terms, platform restrictions and removal requests. No consent, legal basis, accuracy, mailbox ownership or deliverability is inferred from a public address. This Actor is not intended to collect minors' contacts or private/personal contact details. Review results before downstream processing; do not use them for spam or harassment.

This independently operated Actor is not affiliated with or endorsed by TikTok or Apify. No AI processes input or extracted contacts. Only TikTok, Apify storage/compute and our private diagnostics service receive runtime data; there is no paid external API or hidden dependency fee.

Output remains in your Apify run storage under your account's retention settings until expiration or deletion; delete datasets and key-value stores through Console or the API. No cross-run cache or separate contact database is created. Contact Support through this Actor's Store Issues tab with a run ID; do not post private input or credentials.

Failed operations send sanitized diagnostic input, exceptions and actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL queries are removed and reports are retained for 30 days.

### FAQ and troubleshooting

**Why are there zero rows?** The profile may lack a literal email with the required professional wording. Generic email labels, ambiguous contexts and private profiles are deliberately excluded. Check the public bio and completed summary.

**Does it verify addresses?** No. No SMTP, MX, private database, pattern guessing or deliverability check is performed.

**Can it find creators by keyword?** No. Supply known creator handles or canonical profile URLs.

**Why did a valid handle fail?** TikTok can block automated requests or change hydration. Check the run error, reduce batch size where appropriate, and retain the run ID for support. Do not treat failed partial output as a complete roster.

**Does scheduling detect changes?** Scheduling repeats extraction. Comparison, retention and alerts must be implemented in your downstream workflow.

### Related Actors

- [TikTok Profile Scraper](https://apify.com/automation-lab/tiktok-profile-scraper) for general profile metadata rather than conservative business-contact rows.
- [Email Finder & Verifier](https://apify.com/automation-lab/email-enrichment) for a separate, appropriately authorized downstream verification workflow; verification is not included here.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/tiktok-public-business-emails/changelog.md

# Actor input Schema

## `profiles` (type: `array`):

1–100 usernames (with or without @) or canonical HTTPS tiktok.com/@username profile URLs. Queries, video links and other domains are rejected. Duplicate handles are compared case-insensitively and fetched once, in input order.

## `maxItems` (type: `integer`):

Global run limit on accepted email rows, after deduplication within each profile and professional-context exclusions. Default 100; 1–1000 only. Stops fetching profiles when reached. The same email on different profiles remains separately attributed. No rows are emitted for profiles without qualifying contacts.

## Actor input object example

```json
{
  "profiles": [
    "mikaylanogueira",
    "gordonramsayofficial"
  ],
  "maxItems": 10
}
```

# Actor output Schema

## `dataset` (type: `string`):

One row per observed qualifying email and profile.

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

Profile, request, retry, byte and contact counts.

# 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 = {
    "profiles": [
        "mikaylanogueira",
        "gordonramsayofficial"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/tiktok-public-business-emails").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 = {
    "profiles": [
        "mikaylanogueira",
        "gordonramsayofficial",
    ],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/tiktok-public-business-emails").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 '{
  "profiles": [
    "mikaylanogueira",
    "gordonramsayofficial"
  ],
  "maxItems": 10
}' |
apify call automation-lab/tiktok-public-business-emails --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/tiktok-public-business-emails"
        }
    }
}
```

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/FwaQGPDnU2AoEcJaE/builds/4OJMqVwTe6cG3Bwl6/openapi.json
