# TikTok Email Scraper: Creator Contacts, Socials, Bio Links (`datagleaner/tiktok-contacts`) Actor

TikTok email finder for influencer outreach: $0.007 per creator with a public email, free when none is found. Give @handles, profile or video URLs; get the bio email, bio link, website email, Instagram, YouTube, followers and likes. No login, no CAPTCHA.

- **URL**: https://apify.com/datagleaner/tiktok-contacts.md
- **Developed by:** [Data Gleaner](https://apify.com/datagleaner) (community)
- **Categories:** Lead generation, Integrations, Social media
- **Stats:** 3 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.90 / 1,000 creator with 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 Email & Creator Contacts Finder

Find a TikTok creator's contact email from their @handle. Answers "TikTok creator contact", "TikTok influencer email", "TikTok bio link email", "influencer contacts" and "TikTok email" lookups: give it @handles, profile URLs or video URLs, and get each creator's **public email from the bio, the bio link, the emails and socials on the linked website, and their follower, like and video counts**. **You pay $0.007 only for a creator where an email was found; a creator with no email is returned free.** No login, no cookies, no API key, no CAPTCHA.

Built for influencer-outreach lists, agencies and AI agents: one row per creator, the same fields every time, and the price tied to the answer you wanted.

### What it finds

Everything the creator shows **publicly** on their profile:

- **Bio email**, including spelled-out forms such as `name(at)gmail.com`, `name [at] gmail [dot] com` and `name at gmail dot com`.
- **Bio link** (the clickable link under the bio) and any link written in the bio text.
- With `followLinks` on (default), the **emails and socials on that linked page**: the creator's website, or link-in-bio pages such as hoo.be, Komi, link.me or Stan. If that page is a link-in-bio page with no email, the creator's own website listed on it is read next; if it is a website with no email, its contact page is. At most 2 pages per creator.
- **Socials**: Instagram, YouTube, X, Facebook, LinkedIn, Snapchat, Twitch and more, from the bio link and the linked page.
- **Stats**: exact follower, following, like and video counts, the verified badge, private-account flag, account language and creation date.

Linktree, Beacons, bio.link and solo.to refuse automated visitors (Linktree's robots.txt disallows every crawler; the others answer with a Cloudflare challenge). Those links are returned as they are, never visited and never worked around.

### Use cases

- Influencer marketing: turn a list of TikTok handles into a contact sheet, paying only for creators that have an email.
- Agencies and brands enriching creators found elsewhere (a hashtag page, a competitor's tagged videos, a spreadsheet) with the contact route each creator published.
- UGC and sponsorship prospecting: filter by `minFollowers`, keep only creators with an email.
- An AI agent that needs "this TikToker's email" for a list of handles or video links.
- Finding a creator's Instagram, YouTube and website from their TikTok.

### How it works

1. Each input becomes a handle. A video URL (`/@name/video/...`, `vm.tiktok.com/...`, `tiktok.com/t/...`) is opened once to find its author and the country it was posted from.
2. The public profile page `tiktok.com/@handle` is read with plain HTTP; the profile data comes from the page's own embedded JSON.
3. Emails are read from the bio. Links are sorted into socials, link-in-bio pages and websites.
4. With `followLinks` on, up to 2 outside pages are read. Emails on a website are kept only when they plausibly belong to the creator (the site's own domain, a free mailbox such as Gmail, or a name the creator uses); store-platform and payment-processor addresses are dropped.

There is **no keyword search**: TikTok's user search needs signed requests and its robots.txt disallows it. Bring the handles; this Actor finds the contacts.

### Input

| Field | Meaning |
|---|---|
| `profiles` | `@handles`, bare handles or profile URLs (`https://www.tiktok.com/@name`). Video links work here too. |
| `videoUrls` | Video links, including `vm.tiktok.com` short links. Each stands for its author. |
| `datasetId` | Dataset of another Actor's run (see "Run it after TikTok Scraper or any scraper"). Its creators are added to `profiles`. |
| `datasetField`, `maxDatasetItems` | Field holding the handle if it is not a usual one; cap on distinct creators read from the dataset (default 1000). |
| `followLinks` | Read the bio link and at most one more page per creator (default true). |
| `onlyWithEmail` | Output only creators with a public email (default false). Creators without one are free either way. |
| `minFollowers` | Skip creators with fewer followers. |
| `maxConcurrency`, `delaySecs`, `requestTimeoutSecs`, `respectRobotsTxt`, `proxyConfiguration` | Pacing and network options. Defaults: 3 creators in parallel, a random start pause of up to 2 seconds, no proxy. |

Leave both lists empty to run 3 sample creators (about 15 seconds, at most $0.021).

```json
{
  "profiles": ["@cookingwithlynja", "https://www.tiktok.com/@emilymariko", "nutritionbykylie"],
  "videoUrls": ["https://www.tiktok.com/@scout2015/video/6718335390845095173"],
  "minFollowers": 10000,
  "onlyWithEmail": false
}
```

### Run it after TikTok Scraper or any scraper

Compatible with the output of TikTok Scraper and TikTok Profile Scraper by clockworks, and any dataset whose items carry a creator handle or TikTok URL. Open the source Actor's **Integrations** tab, add this Actor (`datagleaner/tiktok-contacts`) and set its input to:

```json
{"datasetId": "{{resource.defaultDatasetId}}"}
```

Or pass the dataset of a finished run by hand, alone or with `profiles`:

```json
{"datasetId": "SOURCE_DATASET_ID", "onlyWithEmail": true}
```

The creator is read from `authorMeta.name`, `authorMeta.profileUrl`, `webVideoUrl`, `uniqueId`, `username`, `profileUrl` or `input` (a search keyword in `input` is ignored). Many videos of one creator count once. Set `datasetField` for any other field. The status message tells how many profiles were read and how many items had none, or that the dataset could not be read. It also works as an integration: open the source Actor's Integrations tab, choose Add integration and pick this Actor, and the dataset is passed automatically.

### Output

One row per creator. Fields that were not found are empty, never invented.

```json
{
  "handle": "emilymariko",
  "profileUrl": "https://www.tiktok.com/@emilymariko",
  "nickname": "Emily Mariko",
  "bio": "Bay Area California ☀️",
  "email": "partnerships@emilymariko.com",
  "emails": [{"email": "partnerships@emilymariko.com", "source": "website", "foundOn": "https://emilymariko.com/"}],
  "hasEmail": true,
  "bioLink": "https://emilymariko.com/",
  "website": "https://emilymariko.com/",
  "socials": {"instagram": "https://www.instagram.com/emilymariko", "youtube": "https://www.youtube.com/@emilymariko", "snapchat": "https://www.snapchat.com/add/emilymariko"},
  "instagramUrl": "https://www.instagram.com/emilymariko",
  "youtubeUrl": "https://www.youtube.com/@emilymariko",
  "xUrl": null,
  "followers": 12058664,
  "following": 214,
  "likes": 857073807,
  "videoCount": 1970,
  "verified": true,
  "isPrivate": false,
  "region": null,
  "language": "en",
  "createdAt": "2018-04-15T21:45:36+00:00",
  "pagesFollowed": 1,
  "skippedLinks": [],
  "status": "ok",
  "input": "@emilymariko",
  "scrapedAt": "2026-10-09T14:37:20+00:00"
}
```

`emails[].source` is `bio` or `website`; `foundOn` is the exact page. `skippedLinks` lists links that were not read and why (for example a Linktree link). A creator that cannot be read (not found, banned, blocked) gets a row with `status: "error"` and an `error` message, and is not charged. `region` is the posting country of the video you gave; TikTok does not publish a profile's country, so it is empty for creators given by handle.

### Pricing

Pay per answer, one event:

- **`creator-with-email`: $0.007** ($7 per 1,000) for each creator where at least one public email was found.
- A creator with **no email is free**. It is still returned, with the bio link, socials and stats.
- A creator that cannot be read (`status: "error"`) is free.

**Worked example.** You check 500 handles and about 25% show a public email: 125 x $0.007 = **$0.875**. The 375 creators without an email cost nothing. Turn on `onlyWithEmail` to leave them out of the dataset; the price is the same.

Set a maximum total charge on the run and the Actor stops cleanly when it is reached.

### What to expect

On our test run of 14 well-known creators, 9 had a public email: 7 in the bio and 2 found by following the bio link. Across a wider sample of 23 of TikTok's biggest accounts, 7 bios carried an email. Mid-sized creators who take brand deals publish one more often than celebrities, and following the bio link adds more. Plan on roughly a quarter to a half of a typical influencer list.

### Limits

- One profile page per creator; nothing behind a login is read. Private accounts still return their profile fields.
- Linktree, Beacons, bio.link and solo.to links are returned but not read (see above).
- At most 2 outside pages per creator. Link-in-bio pages that render only with JavaScript may show fewer links.
- No keyword or hashtag discovery: input is handles, profile URLs and video URLs.
- `region` is known only for creators given by a video URL.
- Very large runs from one IP may be slowed by TikTok; lower `maxConcurrency`, raise `delaySecs`, or add a proxy.

### Use it from n8n, Make, Zapier or an AI agent

Actor ID: `datagleaner/tiktok-contacts`

Minimal input:

```
{"profiles": ["@cookingwithlynja", "@nutritionbykylie", "@lorengray"]}
```

Each tool below runs this Actor with your own Apify API token.

- **n8n:** add the **Apify** node (`@apify/n8n-nodes-apify`). On n8n Cloud you install it from the community node registry. Choose **Run an Actor and get dataset**, set Actor to `datagleaner/tiktok-contacts` and paste the input above.

- **Make:** use the Apify app's **Run an Actor** module, then **Get Dataset Items** to read the results. **Watch Actor Runs** can trigger a scenario when a run finishes.

- **Zapier:** use the Apify action **Run Actor**, then the search **Fetch dataset items**. The trigger **Finished Actor run** starts a Zap when a run ends.

- **AI agents (MCP):** connect to `https://mcp.apify.com/?tools=datagleaner/tiktok-contacts`. In Claude Code:

  ```
  claude mcp add --transport http apify "https://mcp.apify.com/?tools=datagleaner/tiktok-contacts"
  ```

  Then run `/mcp` to sign in to Apify in your browser. Other clients can sign in with OAuth or send the header `Authorization: Bearer YOUR_APIFY_TOKEN`. Clients that run local MCP servers can use Apify's package (`@apify/actors-mcp-server`, run with `npx -y` and `APIFY_TOKEN` set) instead. Then ask the agent in plain words, for example:

  > Find the contact emails of these TikTok creators: @cookingwithlynja, @emilymariko, @nutritionbykylie. Or: who posted this TikTok video, and how do I reach them?

  A creator without an email costs nothing, so an agent can call it freely on a long list.

- **LangChain (Python):**

```python
## pip install langchain-apify, then set APIFY_TOKEN in your environment
import json
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("datagleaner/tiktok-contacts")
result = tool.invoke({"run_input": json.loads('{"profiles": ["@cookingwithlynja", "@nutritionbykylie", "@lorengray"]}')})
```

- **Plain HTTP:**

```bash
curl -X POST "https://api.apify.com/v2/acts/datagleaner~tiktok-contacts/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"profiles": ["@cookingwithlynja", "@emilymariko"], "onlyWithEmail": true}'
```

### FAQ

**Do I need a TikTok account, cookies or an API key?** No. Only public profile pages are read, without logging in.

**Can it search TikTok by keyword or hashtag?** No. TikTok's user search requires signed requests and is disallowed to crawlers by its robots.txt, so this Actor takes handles you already have.

**Which inputs work?** `@name`, `name`, `https://www.tiktok.com/@name`, video links such as `https://www.tiktok.com/@name/video/123...`, and short links such as `https://vm.tiktok.com/...`.

**Why is `emails` empty for a creator I know has one?** The creator put it somewhere this Actor does not read: in a Linktree, behind a contact form, or in TikTok's in-app "Email" button, which needs a logged-in app.

**Why does a Linktree link show up in `skippedLinks`?** Linktree blocks automated visitors and disallows crawlers in its robots.txt, so the link is returned for you to open.

**What happens with empty input?** It runs 3 sample creators and says so in the run's status message.

### Responsible use

This Actor reads public pages only, never logs in, and keeps a polite pace. TikTok's terms discourage automated access, so keep runs proportionate to a real need. Email addresses are personal data: you are responsible for lawful use, including consent and opt-out rules for outreach (GDPR, CAN-SPAM and local law), and for respecting the terms of the platforms you use the data on.

# Actor input Schema

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

TikTok @handles or profile URLs, one per line, e.g. `@cookingwithlynja` or `https://www.tiktok.com/@cookingwithlynja`. A video link works too: it stands for the creator who posted it. Leave this and the video URLs empty to run 3 sample creators.

## `videoUrls` (type: `array`):

TikTok video links, including short vm.tiktok.com links. Each resolves to its author, whose contacts are returned. The video's posting country fills `region`.

## `datasetId` (type: `string`):

Optional. Read TikTok creators from this dataset, for example TikTok Scraper results, and add them to the profiles above. Each item's `authorMeta.name` or `authorMeta.profileUrl` (or `webVideoUrl`, `uniqueId`, `username`, `profileUrl`, `input`) is used; items without one are skipped. In an integration use `{{resource.defaultDatasetId}}`.

## `datasetField` (type: `string`):

Optional. Name of the field (dots reach into objects, e.g. `author.handle`) that holds the creator's handle or profile URL when it is not one of the usual ones. Tried first.

## `maxDatasetItems` (type: `integer`):

Read at most this many distinct creators from the dataset. Several videos of one creator count once.

## `followLinks` (type: `boolean`):

Visit the creator's bio link (and at most one more page: their website from a link-in-bio page, or the website's contact page) and collect the emails and socials shown there. Linktree, Beacons and solo.to block automated clients, so those links are returned without being visited.

## `onlyWithEmail` (type: `boolean`):

Output only creators where at least one public email was found. Creators without an email are free either way.

## `minFollowers` (type: `integer`):

Skip creators with fewer followers. Skipped creators are not billed and do not appear in the output.

## `maxConcurrency` (type: `integer`):

How many creators are processed at the same time. Keep it low; TikTok slows down heavy traffic from one IP.

## `delaySecs` (type: `integer`):

Each creator starts after a random pause of up to this many seconds. Raise it on very large runs to stay polite.

## `respectRobotsTxt` (type: `boolean`):

Skip website pages that the site's robots.txt disallows.

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

How long to wait for each page before retrying.

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

Optional. Defaults to no proxy: TikTok profile pages load from Apify's own servers. Add a proxy only if a very large run starts returning errors.

## Actor input object example

```json
{
  "profiles": [
    "@cookingwithlynja",
    "@nutritionbykylie",
    "@lorengray"
  ],
  "maxDatasetItems": 1000,
  "followLinks": true,
  "onlyWithEmail": false,
  "maxConcurrency": 3,
  "delaySecs": 2,
  "respectRobotsTxt": true,
  "requestTimeoutSecs": 30
}
```

# 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 = {
    "profiles": [
        "@cookingwithlynja",
        "@nutritionbykylie",
        "@lorengray"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagleaner/tiktok-contacts").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": [
        "@cookingwithlynja",
        "@nutritionbykylie",
        "@lorengray",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("datagleaner/tiktok-contacts").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": [
    "@cookingwithlynja",
    "@nutritionbykylie",
    "@lorengray"
  ]
}' |
apify call datagleaner/tiktok-contacts --silent --output-dataset

```

## MCP server setup

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

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/ABtnxKeiAx94bxprw/builds/wUA1Ojiz02iO8hiCW/openapi.json
