{
  "openapi": "3.0.1",
  "info": {
    "title": "TikTok Profile Scraper",
    "description": "Scrape TikTok profiles by analyzing followers, following, or direct lists. Extract 20+ data points including engagement, language, and performance metrics. Powerful filters help you find influencers and analyze competitors.",
    "version": "0.0",
    "x-build-id": "0VYV8YfSmJYjOHLAe"
  },
  "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"
            ],
            "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."
          },
          "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. Examples: «willsmith, therock, charlidamelio».",
            "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
          },
          "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
          },
          "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 ~35 most recent videos — 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",
              "business",
              "personal"
            ],
            "type": "string",
            "description": "Account-type filter — restrict to business accounts, personal accounts, or both. \"any\" (default) includes both. Most B2B targeting wants \"business\"; influencer-marketing campaigns often want \"personal\". TikTok labels accounts at the user's discretion, so the signal isn't perfect.",
            "default": "any"
          },
          "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
                  }
                }
              },
              "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}