{
  "openapi": "3.0.1",
  "info": {
    "title": "TikTok Profile Scraper — TikTok Followers, Emails & Commenters",
    "description": "TikTok profile scraper: TikTok profile data, no login — paste a list of usernames for one row per creator, search creators by keyword or hashtag, or pull followers, following and commenters. Profiles return emails, bio links, country, follower, video stats: leads, email lists, influencer contacts.",
    "version": "0.0",
    "x-build-id": "d3biKc7No9DSbXRb7"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/afanasenko~tiktok-profile-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-afanasenko-tiktok-profile-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/afanasenko~tiktok-profile-scraper/runs": {
      "post": {
        "operationId": "runs-sync-afanasenko-tiktok-profile-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/afanasenko~tiktok-profile-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-afanasenko-tiktok-profile-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "operationMode"
        ],
        "properties": {
          "operationMode": {
            "title": "1. Choose Operation Mode",
            "enum": [
              "analyzeFollowersFollowing",
              "analyzeSpecificAccounts",
              "analyzeEngagedAudience",
              "searchCreators"
            ],
            "type": "string",
            "description": "Operation mode — selects how profiles are sourced. \"analyzeFollowersFollowing\" (Mode 1) scrapes the followers and/or following of one or more target accounts. \"analyzeSpecificAccounts\" (Mode 2) enriches a list of usernames you provide. \"analyzeEngagedAudience\" (Mode 3) discovers users actively commenting on a target account's posts. \"searchCreators\" (Mode 4) finds creators by search words and hashtags."
          },
          "targetUsernames": {
            "title": "Target Accounts",
            "type": "array",
            "description": "Target accounts for Mode 1 — TikTok usernames or full profile URLs (one per line, case-insensitive). The actor scrapes each target's followers and/or following list as input candidates for enrichment. Free plan: up to 3 target accounts per run. Start with a big public creator (e.g. willsmith) to verify your setup, then switch to your own targets.",
            "default": [
              "willsmith"
            ],
            "items": {
              "type": "string"
            }
          },
          "analyzeFollowers": {
            "title": "Scrape Followers",
            "type": "boolean",
            "description": "When true, includes the target's followers list as input candidates for analysis. Set false to skip followers (you may still scrape Following separately). At least one of analyzeFollowers / analyzeFollowing must be true.",
            "default": true
          },
          "analyzeFollowing": {
            "title": "Scrape Following",
            "type": "boolean",
            "description": "When true, includes the target's Following list as input candidates for analysis. Off by default — most use cases focus on followers. Combine with analyzeFollowers=true to scrape both lists.",
            "default": false
          },
          "maxCount": {
            "title": "Max profiles to process (cost control)",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum number of profiles to collect and analyze in Mode 1 — hard cost ceiling because each profile is one paid event ($0.002). 0 = no limit. Free plan ceiling: 100 profiles per run regardless of this value. Counts every profile fetched, including those filtered out post-fetch.",
            "default": 0
          },
          "specificUsernamesList": {
            "title": "List of Profiles to Analyze",
            "type": "array",
            "description": "Profiles to enrich in Mode 2 — usernames or full profile URLs to look up directly (one per line, case-insensitive). The actor enriches each one with metrics, language, and contacts; it does not scrape their follower lists. Free plan: 100 profiles per run.",
            "default": [
              "therock",
              "khaby.lame"
            ],
            "items": {
              "type": "string"
            }
          },
          "maxCountList": {
            "title": "Max profiles to process from the list",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum profiles from your Mode 2 list to process — hard cost ceiling, $0.002 per profile. 0 = no limit. Useful when you paste a long list but want to spend only N events this run.",
            "default": 0
          },
          "engagedAudienceTargetUsernames": {
            "title": "Target Accounts",
            "type": "array",
            "description": "Target accounts for Mode 3 — usernames or profile URLs whose engaged commenters you want to discover (one per line). The actor reads each target's recent posts, collects unique commenters, then enriches every one of them. Free plan: up to 3 target accounts.",
            "default": [
              "willsmith"
            ],
            "items": {
              "type": "string"
            }
          },
          "maxEngagedProfiles": {
            "title": "Max profiles to analyze",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum unique engaged profiles to collect and analyze in Mode 3 — hard cost ceiling, $0.002 per profile. 0 = no limit. Use it to bound a discovery run when a target's posts have thousands of commenters.",
            "default": 0
          },
          "searchKeywords": {
            "title": "Search Words",
            "type": "array",
            "description": "Search words for Mode 4 — one search per line, for example «fitness coach» or «real estate agent». Each search returns the accounts TikTok's own account search shows for it — up to about 50 different creators per search. Every creator found is then analyzed like a username you typed, so all filters, the email and every column apply. The search itself is free; each analyzed profile is $0.002. Free plan: up to 3 searches in all.",
            "items": {
              "type": "string"
            }
          },
          "searchHashtags": {
            "title": "Hashtags",
            "type": "array",
            "description": "Hashtags for Mode 4 — one per line, with or without «#», for example «dogtraining». The actor reads recent videos posted under the hashtag and collects their creators: from a dozen for a small hashtag to several hundred for a big one (at most 500 videos per hashtag). Best for finding active creators in a niche. The search itself is free; each analyzed profile is $0.002.",
            "items": {
              "type": "string"
            }
          },
          "maxSearchProfiles": {
            "title": "Max profiles to analyze (Mode 4)",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum creators to analyze across all your Mode 4 searches — hard cost ceiling, $0.002 per profile. The limit is shared between the searches; what one cannot use passes to the others. 0 = no limit (a big hashtag can bring several hundred creators). Free plan: 100 per run.",
            "default": 0
          },
          "extractEmail": {
            "title": "Extract Email",
            "type": "boolean",
            "description": "When true, the actor parses any email address out of the bio text and emits an Email column. Set false to skip; the Email column will then be omitted from the output. No extra API call — derived from data already fetched.",
            "default": true
          },
          "extractWebsiteUrl": {
            "title": "Extract Website URL",
            "type": "boolean",
            "description": "When true, captures the bio link URL when one is set on the profile and emits a Website column. Set false to omit the column. No extra API call.",
            "default": true
          },
          "extractPhone": {
            "title": "Extract Phone Number",
            "type": "boolean",
            "description": "When true, adds a Phone column with a phone number the creator wrote in the bio (\"N/A\" when there is none). Only numbers the account published are returned. Off by default. No extra cost.",
            "default": false
          },
          "extractSocialLinks": {
            "title": "Extract Linked Instagram & YouTube",
            "type": "boolean",
            "description": "When true, adds Instagram and YouTube columns: the Instagram account and YouTube channel the creator linked on their TikTok profile, as profile URLs (\"N/A\" when none is linked). Off by default. No extra cost.",
            "default": false
          },
          "lookBehindBioLink": {
            "title": "Find Email or Phone Behind the Bio Link",
            "type": "boolean",
            "description": "When true and a saved profile shows no email (or no phone, with Extract Phone Number on), the actor opens its bio link — a link-in-bio page such as Linktree, a WhatsApp link, or the creator's own website (home page and one contact page) — and takes the email or phone published there. Adds Email Source / Phone Source columns. At most 3 pages and about 10 seconds per profile, so runs are slower. Off by default. No extra charge.",
            "default": false
          },
          "includePostingAnalytics": {
            "title": "Add Posting Analytics",
            "type": "boolean",
            "description": "When true, adds five columns computed from the creator's ~10 latest videos: Videos per Week, ER by Views (%) (engagement per view, not per follower), Best Posting Hour (UTC) (the hour whose videos got the most views — a hint from few videos), Top Hashtags and Top Sounds. Pinned videos are left out of the numbers. Off by default. No extra cost.",
            "default": false
          },
          "postExtractionMode": {
            "title": "Extract Post Captions",
            "enum": [
              "none",
              "recent",
              "popular"
            ],
            "type": "string",
            "description": "Post-caption extraction mode — controls whether and how recent video captions are emitted as Post 1, Post 2, … columns. \"none\" (default) skips post-text capture for cheaper runs. \"recent\" returns the most recent posts; \"popular\" returns the most-viewed. Required when keywordLocation is \"posts\" or \"anywhere\".",
            "default": "none"
          },
          "numberOfPosts": {
            "title": "Number of posts to extract",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Number of post captions to emit when postExtractionMode is set — controls how many Post N columns appear (Post 1 through Post N). Range 1–20. Default 8. No effect when postExtractionMode is \"none\".",
            "default": 8
          },
          "keywords": {
            "title": "Filter by Keywords",
            "type": "array",
            "description": "Keyword filter — only include profiles where any keyword appears (case-insensitive OR-match) in the location chosen by keywordLocation. Empty = no keyword filter. Examples: «fitness, workout, training», «luxury, travel, hotel». Multi-word phrases match as substrings.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "keywordLocation": {
            "title": "Search Keywords In",
            "enum": [
              "bio_or_name",
              "bio",
              "name",
              "posts",
              "anywhere"
            ],
            "type": "string",
            "description": "Where to look for keyword matches — \"bio_or_name\" (default) checks bio text and display name; \"bio\" / \"name\" / \"posts\" target one location only; \"anywhere\" combines all three. \"posts\" and \"anywhere\" require postExtractionMode to be \"recent\" or \"popular\".",
            "default": "bio_or_name"
          },
          "profileLanguages": {
            "title": "Filter by Profile Language",
            "enum": [
              "any",
              "English",
              "Spanish",
              "German",
              "French",
              "Russian",
              "Italian",
              "Portuguese",
              "Chinese",
              "Japanese",
              "Korean",
              "Arabic",
              "Hindi",
              "Indonesian",
              "Turkish",
              "Dutch",
              "Polish",
              "Swedish",
              "Ukrainian",
              "Thai",
              "Vietnamese",
              "Romanian",
              "Czech",
              "Greek",
              "Hungarian",
              "Finnish",
              "Norwegian",
              "Danish",
              "Hebrew"
            ],
            "type": "string",
            "description": "Language filter — only include profiles whose detected content language matches your selection. Detection runs on post captions first (most accurate), bio as fallback; profiles with very little text show N/A and are dropped when a specific language is selected here. \"any\" disables the filter.",
            "default": "any"
          },
          "minFollowers": {
            "title": "Follower Count Range: Min",
            "type": "integer",
            "description": "Minimum follower count — profiles below this are skipped. 0 = no minimum. Combine with maxFollowers for a band (e.g. 1 000–10 000 for nano-influencers, 10 000–100 000 for micro).",
            "default": 0
          },
          "maxFollowers": {
            "title": "and Max",
            "type": "integer",
            "description": "Maximum follower count — profiles above this are skipped. 0 = no maximum. Useful for excluding mega-accounts when you target nano or micro creators.",
            "default": 0
          },
          "minLikes": {
            "title": "Min Likes Count",
            "type": "integer",
            "description": "Minimum total likes across all videos on the profile — profiles below this are skipped. 0 = disabled. Total-likes is a coarse signal; combine with engagement-rate filters for quality.",
            "default": 0
          },
          "minMedianViews": {
            "title": "Min Median Views on Recent Videos",
            "type": "integer",
            "description": "Minimum median views on the profile's ~10 most recent videos (pinned videos are left out) — profiles below this are skipped. The median resists outliers (one viral video doesn't inflate it). 0 = disabled. Posts are fetched for this calculation even when postExtractionMode is \"none\".",
            "default": 0
          },
          "minAvgShares": {
            "title": "Min Average Shares on Recent Videos",
            "type": "number",
            "description": "Minimum average shares on recent videos — profiles below this are skipped. Share count is a virality signal independent of follower size. 0 = disabled.",
            "default": 0
          },
          "minEngagementRatio": {
            "title": "Min Engagement Ratio (%)",
            "type": "number",
            "description": "Minimum engagement rate filter, as a percentage — profiles below this are skipped. Computed as ((avg likes + avg comments + avg shares) / followers) * 100 over the recent video sample. 0 = disabled. Typical thresholds: 1–3 % for mid-size creators, 5 %+ for highly engaged niches.",
            "default": 0
          },
          "lastPostDays": {
            "title": "Filter by Last Post Date (Days Ago)",
            "type": "integer",
            "description": "Last-post-recency filter — only include profiles that posted within the last N days. 0 = disabled. Examples: 7 for very active creators, 30 for typical-active, 90 for any-recent. Profiles with no posts are dropped when this is set.",
            "default": 0
          },
          "accountType": {
            "title": "Filter by Account Type",
            "enum": [
              "any",
              "professional",
              "business",
              "creator",
              "personal"
            ],
            "type": "string",
            "description": "Keep only one kind of account. «Any» is the default. TikTok has three: business and creator are both professional, personal is an ordinary account. Measured on 139 accounts from real runs: personal 77%, creator 11%, business 11% — so any filter here cuts the list hard. Running an influencer campaign? Pick «Creator», not «Personal».",
            "default": "any"
          },
          "countries": {
            "title": "Filter by Country",
            "type": "array",
            "description": "Keep only creators who post from these countries — two-letter codes such as US, GB or DE, or English names (United Kingdom), one per line. The country is the one most of the creator's recent videos were posted from; a creator with no single majority country is skipped. It is not a nationality or the audience's location. Empty = no country filter. Like every filter here, a skipped profile is still charged. Every row carries a Country column.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "mustBeVerified": {
            "title": "Filter by Verification",
            "type": "boolean",
            "description": "When true, only profiles with the TikTok blue verification checkmark pass. Off by default. Useful for celebrity/brand-only campaigns; far too restrictive for general influencer discovery.",
            "default": false
          },
          "filterForInfluencers": {
            "title": "Filter for Influencers Only (by Category)",
            "type": "boolean",
            "description": "When true, only profiles with a creator/influencer category (Public Figure, Musician/Band, Creator & Influencer, Sports/Fitness, Beauty, etc.) pass — filters out brands and uncategorized accounts. Off by default. Use it for influencer marketing where brand pages are noise.",
            "default": false
          },
          "categoryFilter": {
            "title": "Filter by Specific Business Category",
            "enum": [
              "any",
              "Public Figure",
              "Musician/Band",
              "Media & Entertainment",
              "Creator & Influencer",
              "Sports, Fitness & Outdoors",
              "Shopping & Retail",
              "Clothing & Accessories",
              "Beauty & Personal Care",
              "Food & Beverage",
              "Restaurants & Bars",
              "Travel & Tourism",
              "Art & Design",
              "Health & Wellness",
              "Education & Training",
              "Finance & Investing",
              "Technology & Computing",
              "Electronics",
              "Automotive",
              "Real Estate",
              "Home & Garden",
              "Pets & Animals",
              "Gaming",
              "Photography",
              "Non-Profit & Social Cause",
              "Government & Politics",
              "Others"
            ],
            "type": "string",
            "description": "Business-category filter — restrict to profiles labeled with the chosen TikTok business category. \"any\" disables. The list mirrors TikTok's own taxonomy: Public Figure, Musician/Band, Sports/Fitness, Shopping & Retail, Beauty, Food & Beverage, Travel, Health, Education, Finance, Tech, Automotive, Real Estate, Gaming, and more.",
            "default": "any"
          },
          "clearSavedData": {
            "title": "Start a Fresh Run",
            "type": "boolean",
            "description": "When true (default), the actor clears any checkpoint data from previous runs and starts fresh. Set false to resume — the run continues from the last successfully processed batch instead of re-scraping. Useful after an aborted run or when iterating on filters with the same target list.",
            "default": true
          },
          "maxBudgetUsd": {
            "title": "Max Budget (USD)",
            "type": "number",
            "description": "Maximum spend in USD for this run — the actor stops gracefully when the budget is about to be exceeded. 0 uses the platform default ($5 on free plans, $1 000 on paid). Each profile retrieved is $0.002, so a $5 cap covers up to ~2 500 profiles before auto-stop.",
            "default": 0
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}