{
  "data": {
    "id": "glvpB5jtOmv1fSco2",
    "actId": "82OM6joIyE5cLSohl",
    "userId": "NL4ThgItAwaoBlffQ",
    "startedAt": "2026-11-05T03:36:09.945Z",
    "finishedAt": "2026-11-05T03:36:51.123Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 41095,
      "runTimeSecs": 41.095,
      "computeUnits": 0.04566111111111111,
      "imageSizeBytes": 3112610816
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "zifX0mkAFMHe8CatY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"TikTok Keyword Discovery — Videos, Photos, Hashtags & Creators Input\",\n  \"description\": \"Search TikTok by keyword for videos or photo posts, or look up hashtag metadata and top posts. Optional discovery expansion finds more posts from related searches, hashtags and sounds.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"searchType\": {\n      \"title\": \"What to Search\",\n      \"type\": \"string\",\n      \"description\": \"Videos: keyword video search. Photos: slideshow/photo search. Hashtags: hashtag metadata plus its top videos (uses the Hashtags field).\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"videos\",\n        \"photos\",\n        \"hashtags\"\n      ],\n      \"enumTitles\": [\n        \"Videos by keyword\",\n        \"Photo / slideshow posts\",\n        \"Hashtags (metadata + top posts)\"\n      ],\n      \"default\": \"videos\",\n      \"prefill\": \"videos\"\n    },\n    \"queries\": {\n      \"title\": \"Search Queries\",\n      \"type\": \"array\",\n      \"description\": \"Keywords or phrases to search for (searchType=videos or photos). Each query is searched independently.\",\n      \"editor\": \"stringList\",\n      \"prefill\": [\n        \"viral\"\n      ],\n      \"example\": [\n        \"cooking recipes\",\n        \"travel vlog\",\n        \"@khaby.lame\"\n      ]\n    },\n    \"hashtags\": {\n      \"title\": \"Hashtags\",\n      \"type\": \"array\",\n      \"description\": \"Hashtags to look up (searchType=hashtags). The # is optional, e.g. coffee or #coffee.\",\n      \"editor\": \"stringList\",\n      \"example\": [\n        \"coffee\",\n        \"fitness\"\n      ]\n    },\n    \"maxResultsPerQuery\": {\n      \"title\": \"Max Results Per Query\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum posts to collect per query or hashtag, before filters. TikTok itself usually returns about 150-220 posts per query even when you ask for more. For hashtags, the metadata row is not counted against this limit.\",\n      \"default\": 30,\n      \"minimum\": 1,\n      \"maximum\": 500,\n      \"prefill\": 3\n    },\n    \"sortBy\": {\n      \"title\": \"Sort By\",\n      \"type\": \"string\",\n      \"description\": \"Client-side sort applied after collecting results. TikTok's web search does not support server-side sorting, so this only reorders the posts TikTok returned.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"relevance\",\n        \"mostLiked\",\n        \"mostViewed\",\n        \"newest\"\n      ],\n      \"enumTitles\": [\n        \"Relevance (TikTok's default order)\",\n        \"Most liked\",\n        \"Most viewed\",\n        \"Newest first\"\n      ],\n      \"default\": \"relevance\",\n      \"prefill\": \"relevance\"\n    },\n    \"publishedWithin\": {\n      \"title\": \"Published Within\",\n      \"type\": \"string\",\n      \"description\": \"Client-side filter that drops posts older than the selected window, based on each post's creation time. TikTok ranks results by relevance, not date, so a narrow window can return fewer posts than requested; the actor scans up to 5x the requested count (capped at 500) to fill it.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"all\",\n        \"day\",\n        \"week\",\n        \"month\",\n        \"3months\",\n        \"6months\"\n      ],\n      \"enumTitles\": [\n        \"All time\",\n        \"Past 24 hours\",\n        \"Past week\",\n        \"Past month\",\n        \"Past 3 months\",\n        \"Past 6 months\"\n      ],\n      \"default\": \"all\",\n      \"prefill\": \"all\"\n    },\n    \"minDurationSeconds\": {\n      \"title\": \"Minimum Duration (seconds)\",\n      \"type\": \"integer\",\n      \"description\": \"Drop videos shorter than this. Leave blank for no minimum.\",\n      \"minimum\": 0,\n      \"maximum\": 7200\n    },\n    \"maxDurationSeconds\": {\n      \"title\": \"Maximum Duration (seconds)\",\n      \"type\": \"integer\",\n      \"description\": \"Drop videos longer than this. Leave blank for no maximum.\",\n      \"minimum\": 0,\n      \"maximum\": 7200\n    },\n    \"excludeAds\": {\n      \"title\": \"Exclude Ads\",\n      \"type\": \"boolean\",\n      \"description\": \"Drop posts TikTok flags as paid advertisements.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"minLikeCount\": {\n      \"title\": \"Minimum Like Count\",\n      \"type\": \"integer\",\n      \"description\": \"Drop posts with fewer likes than this. Leave blank for no minimum.\",\n      \"minimum\": 0\n    },\n    \"minViewCount\": {\n      \"title\": \"Minimum View Count\",\n      \"type\": \"integer\",\n      \"description\": \"Drop posts with fewer plays/views than this. Leave blank for no minimum.\",\n      \"minimum\": 0\n    },\n    \"uniqueAuthors\": {\n      \"title\": \"One Post Per Author\",\n      \"type\": \"boolean\",\n      \"description\": \"Keep at most one post per creator, so the results read like a creator shortlist. When a sort is selected, the top-ranked post from each creator is kept.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"maxPostsPerAuthor\": {\n      \"title\": \"Max Posts Per Author\",\n      \"type\": \"integer\",\n      \"description\": \"Optional cap on how many posts one creator may contribute. Ignored when One Post Per Author is on.\",\n      \"minimum\": 1,\n      \"maximum\": 100\n    },\n    \"enableExpansion\": {\n      \"title\": \"Enable Discovery Expansion\",\n      \"type\": \"boolean\",\n      \"description\": \"After each keyword search, run extra searches derived from its own results: related searches, its top hashtags and its most-reused sound. Increases run time and the number of posts found. Videos only.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"expansionSources\": {\n      \"title\": \"Expansion Sources\",\n      \"type\": \"array\",\n      \"description\": \"Which discovery sources to use when expansion is on. All three can be combined.\",\n      \"editor\": \"select\",\n      \"items\": {\n        \"type\": \"string\",\n        \"enum\": [\n          \"suggestions\",\n          \"hashtags\",\n          \"sounds\"\n        ],\n        \"enumTitles\": [\n          \"Related searches\",\n          \"Hashtags\",\n          \"Sounds\"\n        ]\n      },\n      \"default\": [\n        \"suggestions\",\n        \"hashtags\",\n        \"sounds\"\n      ],\n      \"prefill\": [\n        \"suggestions\",\n        \"hashtags\",\n        \"sounds\"\n      ]\n    },\n    \"maxExpansionQueriesPerSeed\": {\n      \"title\": \"Max Expansion Searches Per Query\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum number of extra searches to run per keyword when expansion is on. Each one costs roughly as much run time as the original search.\",\n      \"default\": 3,\n      \"minimum\": 0,\n      \"maximum\": 10,\n      \"prefill\": 3\n    },\n    \"includeHashtagMetadata\": {\n      \"title\": \"Include Hashtag Metadata\",\n      \"type\": \"boolean\",\n      \"description\": \"For hashtag searches: emit a metadata row with the hashtag's post count, view count, description and images. Also attaches metadata to hashtag-expansion posts when expansion is on.\",\n      \"default\": true,\n      \"prefill\": true\n    }\n  },\n  \"required\": [\n    \"searchType\"\n  ]\n}",
    "readme": "# TikTok Keyword Discovery — Videos, Photos, Hashtags & Creators\n\nSearch TikTok by keyword and get structured video and photo posts, or look up a hashtag's own\nmetadata. Each row carries the caption, engagement counts, creator snapshot, sound details,\nhashtags and mentions, and the post's stable URL. Optional discovery expansion runs related\nsearches, top hashtags and the most-reused sound from a keyword's own results to surface more\nposts. No login, cookies or proxy setup required.\n\n## What this actor does\n\n- **Three search types:** `videos` by keyword, `photos`/slideshows by keyword, and `hashtags`\n  with metadata plus the tag's top posts\n- **Deep pagination:** keeps loading until TikTok's own result pool ends or your per-query limit\n  is reached (TikTok typically serves about 150–220 posts per query)\n- **Video and photo rows:** captions, creation time, plays, likes, comments, shares, saves,\n  reposts, creator profile snapshot, sound metadata, video technical details and slideshow images\n- **Discovery expansion:** related searches, top hashtags and sound pages, deduplicated against\n  the seed results\n- **Client-side controls:** sort by relevance/likes/views/newest, date window, duration, ads,\n  minimum likes/views, one post per creator and max posts per creator\n- **Honest empty fields:** fields TikTok does not provide for a post are omitted, never `null`\n\n## Output per post\n\n- `rowType` — `video` for all post rows (including slideshows; `postType` says which) or `hashtag` for hashtag metadata rows\n- `postId`, `postUrl`, `postType` — post identity; `postType` is `video` or `slideshow`\n- `caption`, `textLanguage`, `createTime`, `createdAt`\n- `query` — the search phrase that returned this post; `rank` — zero-based position in that\n  search; `queryVariant` — casing/spacing variant when a query pass found it\n- `searchType` — `general`, `photo`, `hashtag` or `sound`\n- `expansionSource`, `expansionTerm` — only on expansion-discovered posts\n- `playCount`, `likeCount`, `commentCount`, `shareCount`, `collectCount`, `repostCount`\n- `author.id`, `author.secUid`, `author.username`, `author.displayName`, `author.bio`,\n  `author.verified`, `author.privateAccount`, `author.avatarUrl`, `author.followerCount`,\n  `author.followingCount`, `author.heartCount`, `author.videoCount`, `author.roomId`,\n  `author.isVirtualAccount`\n- `music.id`, `music.title`, `music.authorName`, `music.original`, `music.duration`,\n  `music.album`, `music.playUrl`, `music.coverUrl`, and licensing flags\n- `video.width`, `video.height`, `video.duration`, `video.ratio`, `video.definition`,\n  `video.bitrate`, `video.codecType`, `video.format`, `video.size`, `video.videoQuality`,\n- `video.playUrl`, `video.downloadAddr` — signed CDN URLs, reference-only: TikTok's CDN can\n  reject direct downloads (HTTP 403) even while the post plays on TikTok\n- `video.cover`, `video.originCover`, `video.dynamicCover`, `video.subtitles`,\n  `video.qualityScore`, `video.qualityTags`,\n  `video.coverVariants`, `video.bitrateInfo`, `video.volumeInfo`\n- `images[]` — real image URLs for slideshow/photo posts\n- `hashtags[]`, `mentions[]`, `poi` — caption tags, @mentions and a location tag when present\n- `isAd`, `isECVideo`, `adLabelVersion`, `privateItem`, `forFriend`, `isAigc`,\n  `AIGCDescription`, `originalItem`, `categoryType`, `item_control`, `contents`,\n  `effectStickers`, `stickersOnItem`\n- `mediaUrlExpiresAt` — when the signed media URLs expire, when it can be read\n\n## Output per hashtag\n\nHashtag searches emit one metadata row (`rowType: \"hashtag\"`) before the tag's post rows:\n\n- `query` — the hashtag, e.g. `#coffee`\n- `hashtagMetadata.hashtagId`, `name`, `desc`, `isCommerce`, `videoCount`, `viewCount`,\n  `profileUrl`, `shareTitle`, `shareDesc`\n\n## Input\n\n| Field | Type | Default | Description |\n|---|---|---|---|\n| `searchType` | string | `videos` | `videos`, `photos` or `hashtags` |\n| `queries` | string[] | — | Keywords for video/photo search |\n| `hashtags` | string[] | — | Hashtags for `searchType=hashtags`; `#` optional |\n| `maxResultsPerQuery` | integer | 30 | Posts per query/tag before filters (1–500) |\n| `sortBy` | string | `relevance` | `relevance`, `mostLiked`, `mostViewed`, `newest` |\n| `publishedWithin` | string | `all` | `all`, `day`, `week`, `month`, `3months`, `6months`; narrow windows scan up to 5× the requested count |\n| `minDurationSeconds` | integer | — | Drop shorter videos |\n| `maxDurationSeconds` | integer | — | Drop longer videos |\n| `excludeAds` | boolean | false | Drop posts flagged as ads |\n| `minLikeCount` | integer | — | Drop posts with fewer likes |\n| `minViewCount` | integer | — | Drop posts with fewer plays |\n| `uniqueAuthors` | boolean | false | Keep at most one post per creator |\n| `maxPostsPerAuthor` | integer | — | Cap posts per creator (ignored when `uniqueAuthors` is on) |\n| `enableExpansion` | boolean | false | Run related searches, hashtags and sounds |\n| `expansionSources` | string[] | `[\"suggestions\", \"hashtags\", \"sounds\"]` | `suggestions`, `hashtags`, `sounds` |\n| `maxExpansionQueriesPerSeed` | integer | 3 | Extra searches per keyword (0–10) |\n| `includeHashtagMetadata` | boolean | true | Emit hashtag metadata rows/expansion metadata |\n\n## Examples\n\n### Keyword video search\n\n```json\n{\n  \"searchType\": \"videos\",\n  \"queries\": [\"cottagecore aesthetic\", \"dark academia\"],\n  \"maxResultsPerQuery\": 100,\n  \"sortBy\": \"mostLiked\",\n  \"publishedWithin\": \"month\"\n}\n```\n\n### Photo / slideshow search\n\n```json\n{\n  \"searchType\": \"photos\",\n  \"queries\": [\"coffee\"],\n  \"maxResultsPerQuery\": 50\n}\n```\n\n### Hashtag discovery\n\n```json\n{\n  \"searchType\": \"hashtags\",\n  \"hashtags\": [\"coffee\", \"#fitness\"],\n  \"maxResultsPerQuery\": 30,\n  \"includeHashtagMetadata\": true\n}\n```\n\n### Creator shortlist with expansion\n\n```json\n{\n  \"searchType\": \"videos\",\n  \"queries\": [\"skincare routine\"],\n  \"maxResultsPerQuery\": 200,\n  \"uniqueAuthors\": true,\n  \"enableExpansion\": true,\n  \"expansionSources\": [\"suggestions\", \"hashtags\"],\n  \"maxExpansionQueriesPerSeed\": 3\n}\n```\n\n## Use cases\n\n- **Content research** — see which videos and slideshows rank for a topic, newest or most liked\n- **Creator discovery** — collapse results to one post per creator, then review follower counts\n- **Brand and campaign monitoring** — track keyword mentions, hashtags and sounds across markets\n- **Trend exploration** — expand a seed keyword through TikTok's own related searches and tags\n- **Dataset building** — export structured post, engagement and creator fields for analysis\n\n## FAQ\n\n### Do I need a TikTok account or cookies?\n\nNo. The actor reads the search results TikTok shows to signed-out visitors. There is no cookie,\ntoken or proxy field to fill in. TikTok sometimes asks anonymous cloud IPs to log in; the actor\nautomatically retries with a different proxy session and never asks you for credentials.\n\n### How many results can I get per query?\n\nTikTok's own search pool usually ends around 150–220 posts per query, even when a larger limit is\nrequested. The actor follows TikTok's cursor until the pool ends, then optionally runs casing and\nspacing query passes. To collect more, add more queries or turn on discovery expansion.\n\n### Why is my result count lower than `maxResultsPerQuery`?\n\nTwo reasons: TikTok may exhaust its result pool before your limit, and the date, duration, ads,\nlikes, views and creator filters run after collection. The final dataset is always the\npost-filter set.\n\n### Are the sort and filters applied by TikTok or by the actor?\n\nBy the actor. The actor collects posts in TikTok's default relevance order and then applies your\nsort and filters locally. For a narrow date window it scans up to 5× the requested count (capped\nat 500) before applying the window; because that scan is bounded, a week or day window can\nlegitimately yield fewer posts than requested.\n\n### What is the difference between the video and photo search types?\n\nBoth return posts for a keyword. Video search uses TikTok's main search ranking; photo search\nuses its photo/slideshow vertical. Photo rows always include `images[]`; video playback fields\nare omitted because slideshows do not carry a direct video stream.\n\n### Why are some fields missing on some posts?\n\nTikTok includes fields such as subtitles, location, mentions, AR effects or quality badges only\nwhen they apply. Empty fields are omitted rather than filled with placeholders.\n\n### Do the media URLs work forever?\n\nTikTok's media URLs are signed and expire; `mediaUrlExpiresAt` shows when the actor can read the\nexpiry. Use `postUrl` as the stable reference. Cover images, avatars and sound preview URLs are\ngenerally directly accessible, but TikTok's video CDN may reject direct downloads even while the\nvideo plays on TikTok itself.\n\n### Can I search a specific country or language?\n\nQueries can be in any language and return results in that language. TikTok's web search does not\nexpose a working country filter: its `region` parameter is cosmetic and results still follow the\nrequest's network location, so no region input is offered.\n\n### Can I search for creators directly?\n\nThis actor focuses on posts and hashtags. To find creators, use `uniqueAuthors` on a keyword\nsearch (one post per creator), or turn on expansion to reach more creators through related\nsearches, hashtags and sounds. A dedicated user-search mode is not included because TikTok\nserves it inconsistently to signed-out sessions.\n\n### Is this affiliated with TikTok?\n\nNo. It is an independent tool that reads TikTok's public search results and is not run or\nendorsed by TikTok.\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "tiktok-keyword-search-and-discovery-scraper",
      "title": "TikTok Keyword Discovery — Videos, Photos, Hashtags & Creators",
      "description": "Search TikTok by keyword for videos, photo slideshows and hashtags. Get captions, engagement stats, creator profiles, sounds, hashtags and images, with optional related-search, hashtag and sound discovery.",
      "version": "1.0",
      "meta": {
        "templateId": "python-playwright"
      },
      "input": {
        "title": "TikTok Keyword Discovery — Videos, Photos, Hashtags & Creators Input",
        "description": "Search TikTok by keyword for videos or photo posts, or look up hashtag metadata and top posts. Optional discovery expansion finds more posts from related searches, hashtags and sounds.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "searchType": {
            "title": "What to Search",
            "type": "string",
            "description": "Videos: keyword video search. Photos: slideshow/photo search. Hashtags: hashtag metadata plus its top videos (uses the Hashtags field).",
            "editor": "select",
            "enum": [
              "videos",
              "photos",
              "hashtags"
            ],
            "enumTitles": [
              "Videos by keyword",
              "Photo / slideshow posts",
              "Hashtags (metadata + top posts)"
            ],
            "default": "videos",
            "prefill": "videos"
          },
          "queries": {
            "title": "Search Queries",
            "type": "array",
            "description": "Keywords or phrases to search for (searchType=videos or photos). Each query is searched independently.",
            "editor": "stringList",
            "prefill": [
              "viral"
            ],
            "example": [
              "cooking recipes",
              "travel vlog",
              "@khaby.lame"
            ]
          },
          "hashtags": {
            "title": "Hashtags",
            "type": "array",
            "description": "Hashtags to look up (searchType=hashtags). The # is optional, e.g. coffee or #coffee.",
            "editor": "stringList",
            "example": [
              "coffee",
              "fitness"
            ]
          },
          "maxResultsPerQuery": {
            "title": "Max Results Per Query",
            "type": "integer",
            "description": "Maximum posts to collect per query or hashtag, before filters. TikTok itself usually returns about 150-220 posts per query even when you ask for more. For hashtags, the metadata row is not counted against this limit.",
            "default": 30,
            "minimum": 1,
            "maximum": 500,
            "prefill": 3
          },
          "sortBy": {
            "title": "Sort By",
            "type": "string",
            "description": "Client-side sort applied after collecting results. TikTok's web search does not support server-side sorting, so this only reorders the posts TikTok returned.",
            "editor": "select",
            "enum": [
              "relevance",
              "mostLiked",
              "mostViewed",
              "newest"
            ],
            "enumTitles": [
              "Relevance (TikTok's default order)",
              "Most liked",
              "Most viewed",
              "Newest first"
            ],
            "default": "relevance",
            "prefill": "relevance"
          },
          "publishedWithin": {
            "title": "Published Within",
            "type": "string",
            "description": "Client-side filter that drops posts older than the selected window, based on each post's creation time. TikTok ranks results by relevance, not date, so a narrow window can return fewer posts than requested; the actor scans up to 5x the requested count (capped at 500) to fill it.",
            "editor": "select",
            "enum": [
              "all",
              "day",
              "week",
              "month",
              "3months",
              "6months"
            ],
            "enumTitles": [
              "All time",
              "Past 24 hours",
              "Past week",
              "Past month",
              "Past 3 months",
              "Past 6 months"
            ],
            "default": "all",
            "prefill": "all"
          },
          "minDurationSeconds": {
            "title": "Minimum Duration (seconds)",
            "type": "integer",
            "description": "Drop videos shorter than this. Leave blank for no minimum.",
            "minimum": 0,
            "maximum": 7200
          },
          "maxDurationSeconds": {
            "title": "Maximum Duration (seconds)",
            "type": "integer",
            "description": "Drop videos longer than this. Leave blank for no maximum.",
            "minimum": 0,
            "maximum": 7200
          },
          "excludeAds": {
            "title": "Exclude Ads",
            "type": "boolean",
            "description": "Drop posts TikTok flags as paid advertisements.",
            "default": false,
            "prefill": false
          },
          "minLikeCount": {
            "title": "Minimum Like Count",
            "type": "integer",
            "description": "Drop posts with fewer likes than this. Leave blank for no minimum.",
            "minimum": 0
          },
          "minViewCount": {
            "title": "Minimum View Count",
            "type": "integer",
            "description": "Drop posts with fewer plays/views than this. Leave blank for no minimum.",
            "minimum": 0
          },
          "uniqueAuthors": {
            "title": "One Post Per Author",
            "type": "boolean",
            "description": "Keep at most one post per creator, so the results read like a creator shortlist. When a sort is selected, the top-ranked post from each creator is kept.",
            "default": false,
            "prefill": false
          },
          "maxPostsPerAuthor": {
            "title": "Max Posts Per Author",
            "type": "integer",
            "description": "Optional cap on how many posts one creator may contribute. Ignored when One Post Per Author is on.",
            "minimum": 1,
            "maximum": 100
          },
          "enableExpansion": {
            "title": "Enable Discovery Expansion",
            "type": "boolean",
            "description": "After each keyword search, run extra searches derived from its own results: related searches, its top hashtags and its most-reused sound. Increases run time and the number of posts found. Videos only.",
            "default": false,
            "prefill": false
          },
          "expansionSources": {
            "title": "Expansion Sources",
            "type": "array",
            "description": "Which discovery sources to use when expansion is on. All three can be combined.",
            "editor": "select",
            "items": {
              "type": "string",
              "enum": [
                "suggestions",
                "hashtags",
                "sounds"
              ],
              "enumTitles": [
                "Related searches",
                "Hashtags",
                "Sounds"
              ]
            },
            "default": [
              "suggestions",
              "hashtags",
              "sounds"
            ],
            "prefill": [
              "suggestions",
              "hashtags",
              "sounds"
            ]
          },
          "maxExpansionQueriesPerSeed": {
            "title": "Max Expansion Searches Per Query",
            "type": "integer",
            "description": "Maximum number of extra searches to run per keyword when expansion is on. Each one costs roughly as much run time as the original search.",
            "default": 3,
            "minimum": 0,
            "maximum": 10,
            "prefill": 3
          },
          "includeHashtagMetadata": {
            "title": "Include Hashtag Metadata",
            "type": "boolean",
            "description": "For hashtag searches: emit a metadata row with the hashtag's post count, view count, description and images. Also attaches metadata to hashtag-expansion posts when expansion is on.",
            "default": true,
            "prefill": true
          }
        },
        "required": [
          "searchType"
        ]
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "TikTok Keyword Discovery — Videos, Photos, Hashtags & Creators Output",
        "properties": {
          "data": {
            "type": "string",
            "title": "Search Results",
            "description": "Dataset with one row per TikTok video/photo result (rowType='video', including slideshows) plus hashtag metadata rows (rowType='hashtag') for hashtag searches.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "dockerfile": "./Dockerfile",
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "title": "TikTok Search Results",
          "views": {
            "overview": {
              "title": "Search Results Overview",
              "description": "TikTok video and photo posts returned by keyword search with rank, query context, and engagement metrics.",
              "transformation": {
                "fields": [
                  "postId",
                  "query",
                  "rank",
                  "searchType",
                  "caption",
                  "createdAt",
                  "author",
                  "playCount",
                  "likeCount",
                  "commentCount",
                  "shareCount",
                  "postUrl"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "postId": {
                    "label": "Post ID",
                    "format": "text"
                  },
                  "query": {
                    "label": "Search Query",
                    "format": "text"
                  },
                  "rank": {
                    "label": "Rank",
                    "format": "number"
                  },
                  "searchType": {
                    "label": "Search Type",
                    "format": "text"
                  },
                  "caption": {
                    "label": "Caption",
                    "format": "text"
                  },
                  "createdAt": {
                    "label": "Created At",
                    "format": "text"
                  },
                  "playCount": {
                    "label": "Views",
                    "format": "number"
                  },
                  "likeCount": {
                    "label": "Likes",
                    "format": "number"
                  },
                  "commentCount": {
                    "label": "Comments",
                    "format": "number"
                  },
                  "shareCount": {
                    "label": "Shares",
                    "format": "number"
                  },
                  "postUrl": {
                    "label": "Post URL",
                    "format": "link"
                  }
                }
              }
            },
            "hashtags": {
              "title": "Hashtag Results",
              "description": "Hashtag metadata rows emitted by searchType=hashtags, including post and view counts.",
              "transformation": {
                "fields": [
                  "query",
                  "searchType",
                  "hashtagMetadata"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "query": {
                    "label": "Hashtag",
                    "format": "text"
                  },
                  "searchType": {
                    "label": "Search Type",
                    "format": "text"
                  },
                  "hashtagMetadata": {
                    "label": "Metadata",
                    "format": "object"
                  }
                }
              }
            }
          },
          "fields": {
            "query": {
              "type": "string",
              "title": "Search Query",
              "description": "The search keyword or phrase used to find this post"
            },
            "rank": {
              "type": "integer",
              "title": "Rank",
              "description": "0-based position of this post in the search results for the given query"
            },
            "searchType": {
              "type": "string",
              "title": "Search Type",
              "description": "How the row was found: 'general' keyword search, 'photo' search, 'hashtag' search, or 'sound' expansion."
            },
            "postId": {
              "type": "string",
              "title": "Post ID",
              "description": "TikTok's unique post/video ID (string to preserve 64-bit precision)"
            },
            "postUrl": {
              "type": "string",
              "title": "Post URL",
              "description": "Direct URL to the TikTok post"
            },
            "postType": {
              "type": "string",
              "title": "Post Type",
              "description": "Either 'video' or 'slideshow'"
            },
            "caption": {
              "type": "string",
              "title": "Caption",
              "description": "Post caption/description text including hashtags and mentions"
            },
            "textLanguage": {
              "type": "string",
              "title": "Text Language",
              "description": "Detected language code of the caption text"
            },
            "locationCreated": {
              "type": "string",
              "title": "Location Created",
              "description": "ISO country code where the post was created (e.g. 'US', 'IT')"
            },
            "createTime": {
              "type": "integer",
              "title": "Create Time (Unix)",
              "description": "Unix timestamp (seconds) when the post was created"
            },
            "createdAt": {
              "type": "string",
              "title": "Created At",
              "description": "ISO 8601 UTC datetime when the post was created"
            },
            "playCount": {
              "type": "integer",
              "title": "Play Count",
              "description": "Number of video plays"
            },
            "likeCount": {
              "type": "integer",
              "title": "Like Count",
              "description": "Number of likes/diggs"
            },
            "commentCount": {
              "type": "integer",
              "title": "Comment Count",
              "description": "Number of comments"
            },
            "shareCount": {
              "type": "integer",
              "title": "Share Count",
              "description": "Number of shares"
            },
            "collectCount": {
              "type": "integer",
              "title": "Collect Count",
              "description": "Number of times post was bookmarked/collected"
            },
            "repostCount": {
              "type": "integer",
              "title": "Repost Count",
              "description": "Number of reposts"
            },
            "stitchEnabled": {
              "type": "boolean",
              "title": "Stitch Enabled",
              "description": "Whether the creator allows stitching this video"
            },
            "shareEnabled": {
              "type": "boolean",
              "title": "Share Enabled",
              "description": "Whether sharing is enabled for this post"
            },
            "duetEnabled": {
              "type": "boolean",
              "title": "Duet Enabled",
              "description": "Whether the creator allows duets with this video"
            },
            "commentStatus": {
              "type": "integer",
              "title": "Comment Status",
              "description": "Comment permission setting (0=all, 1=friends, 2=none)"
            },
            "isAd": {
              "type": "boolean",
              "title": "Is Ad",
              "description": "Whether this post is a paid advertisement"
            },
            "privateItem": {
              "type": "boolean",
              "title": "Private Item",
              "description": "Whether the post is set to private"
            },
            "forFriend": {
              "type": "boolean",
              "title": "For Friend",
              "description": "Whether the post is restricted to friends only"
            },
            "originalItem": {
              "type": "boolean",
              "title": "Original Item",
              "description": "Whether this post is an original (non-duet, non-stitch) creation"
            },
            "isAigc": {
              "type": "boolean",
              "title": "Is AI Generated Content",
              "description": "Whether TikTok labels this as AI-generated content"
            },
            "AIGCDescription": {
              "type": "string",
              "title": "AIGC Description",
              "description": "Description for AI-generated content label"
            },
            "categoryType": {
              "type": "integer",
              "title": "Category Type",
              "description": "TikTok's internal numeric content-category ID"
            },
            "expansionSource": {
              "type": "string",
              "title": "Expansion Source",
              "description": "How this result was discovered when Enable Expansion is on: 'sound', 'hashtag', or 'suggestion'. Absent for primary/seed-query results."
            },
            "expansionTerm": {
              "type": "string",
              "title": "Expansion Term",
              "description": "The sound title, hashtag, or suggested search phrase that surfaced this result via expansion. Absent for primary/seed-query results."
            },
            "aiContentEligible": {
              "type": "boolean",
              "title": "AI Content Eligible",
              "description": "Whether TikTok's own AI-content detection flagged this post as eligible for AI-generated-content review"
            },
            "aigcLabelType": {
              "type": "integer",
              "title": "AIGC Label Type",
              "description": "TikTok's AI-generated-content moderation label type, when present"
            },
            "moderationAigcLabelType": {
              "type": "integer",
              "title": "Moderation AIGC Label Type",
              "description": "TikTok's moderation-specific AI-generated-content label type, when present"
            },
            "item_control": {
              "type": "object",
              "title": "Item Control",
              "description": "Post-level permission flags (e.g. can_repost)"
            },
            "contents": {
              "type": "array",
              "title": "Content Variants",
              "description": "Localized/alternate caption variants for this post, when TikTok provides more than one"
            },
            "effectStickers": {
              "type": "array",
              "title": "Effect Stickers",
              "description": "AR effects/filters used in the post, with usage-count stats"
            },
            "stickersOnItem": {
              "type": "array",
              "title": "Stickers On Item",
              "description": "Text/interactive sticker overlays on the post"
            },
            "isECVideo": {
              "type": "boolean",
              "title": "Is E-Commerce Video",
              "description": "Whether this is a shopping/e-commerce video"
            },
            "adLabelVersion": {
              "type": "integer",
              "title": "Ad Label Version",
              "description": "Ad label version; non-zero when the post is a sponsored ad"
            },
            "viewerRegion": {
              "type": "string",
              "title": "Viewer Region",
              "description": "ISO country code of the inferred viewer region"
            },
            "mediaUrlExpiresAt": {
              "type": "string",
              "title": "Media URL Expires At",
              "description": "ISO 8601 UTC datetime when signed media URLs (video/cover) expire"
            },
            "poi": {
              "type": "object",
              "title": "Point of Interest",
              "description": "Location tag attached to the post (restaurant, landmark, etc.) — only present when TikTok attaches a POI to the search result",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "address": {
                  "type": "string"
                },
                "city": {
                  "type": "string"
                },
                "country": {
                  "type": "string"
                },
                "category": {
                  "type": "string"
                }
              }
            },
            "author": {
              "type": "object",
              "title": "Author",
              "description": "Author/creator information at time of scraping",
              "properties": {
                "id": {
                  "type": "string",
                  "title": "User ID"
                },
                "secUid": {
                  "type": "string",
                  "title": "Secure UID"
                },
                "username": {
                  "type": "string",
                  "title": "Username"
                },
                "displayName": {
                  "type": "string",
                  "title": "Display Name"
                },
                "bio": {
                  "type": "string",
                  "title": "Bio"
                },
                "verified": {
                  "type": "boolean",
                  "title": "Verified"
                },
                "privateAccount": {
                  "type": "boolean",
                  "title": "Private Account"
                },
                "roomId": {
                  "type": "string",
                  "title": "Live Room ID (non-empty when live)"
                },
                "avatarUrl": {
                  "type": "string",
                  "title": "Avatar URL"
                },
                "followerCount": {
                  "type": "integer",
                  "title": "Followers"
                },
                "followingCount": {
                  "type": "integer",
                  "title": "Following"
                },
                "heartCount": {
                  "type": "integer",
                  "title": "Hearts/Likes"
                },
                "videoCount": {
                  "type": "integer",
                  "title": "Videos"
                },
                "isVirtualAccount": {
                  "type": "boolean",
                  "title": "Is Virtual Account",
                  "description": "Whether TikTok flags this as an AI-generated/virtual-avatar account"
                }
              }
            },
            "music": {
              "type": "object",
              "title": "Music",
              "description": "Sound/music used in the post",
              "properties": {
                "id": {
                  "type": "string",
                  "title": "Music ID"
                },
                "title": {
                  "type": "string",
                  "title": "Title"
                },
                "authorName": {
                  "type": "string",
                  "title": "Author"
                },
                "original": {
                  "type": "boolean",
                  "title": "Original Sound"
                },
                "duration": {
                  "type": "integer",
                  "title": "Duration (s)"
                },
                "isCopyrighted": {
                  "type": "boolean",
                  "title": "Is Copyrighted"
                },
                "isCommerceMusic": {
                  "type": "boolean",
                  "title": "Is Commerce Music"
                },
                "isUnlimitedMusic": {
                  "type": "boolean",
                  "title": "Is Unlimited Music"
                },
                "isPrivate": {
                  "type": "boolean",
                  "title": "Is Private Sound"
                },
                "shootDuration": {
                  "type": "number",
                  "title": "Shoot Duration (s)"
                },
                "album": {
                  "type": "string",
                  "title": "Album"
                },
                "dspLinks": {
                  "type": "array",
                  "title": "DSP Links (Spotify, Apple Music, etc.)"
                },
                "playUrl": {
                  "type": "string",
                  "title": "Play URL"
                },
                "coverUrl": {
                  "type": "string",
                  "title": "Cover URL"
                }
              }
            },
            "video": {
              "type": "object",
              "title": "Video",
              "description": "Video technical metadata and signed play/cover URLs",
              "properties": {
                "width": {
                  "type": "integer",
                  "title": "Width (px)"
                },
                "height": {
                  "type": "integer",
                  "title": "Height (px)"
                },
                "duration": {
                  "type": "integer",
                  "title": "Duration (s)"
                },
                "ratio": {
                  "type": "string",
                  "title": "Aspect Ratio"
                },
                "definition": {
                  "type": "string",
                  "title": "Definition"
                },
                "bitrate": {
                  "type": "integer",
                  "title": "Bitrate"
                },
                "codecType": {
                  "type": "string",
                  "title": "Codec"
                },
                "format": {
                  "type": "string",
                  "title": "Format"
                },
                "size": {
                  "type": "integer",
                  "title": "File Size (bytes)"
                },
                "playUrl": {
                  "type": "string",
                  "title": "Play URL",
                  "description": "Signed TikTok CDN play URL. Reference-only: the CDN can reject direct downloads (HTTP 403) outside TikTok."
                },
                "downloadAddr": {
                  "type": "string",
                  "title": "Download URL",
                  "description": "Signed TikTok CDN download URL. Reference-only: the CDN commonly rejects direct downloads (HTTP 403) outside TikTok."
                },
                "cover": {
                  "type": "string",
                  "title": "Cover Image URL"
                },
                "originCover": {
                  "type": "string",
                  "title": "Original Cover URL"
                },
                "dynamicCover": {
                  "type": "string",
                  "title": "Dynamic Cover URL"
                },
                "videoQuality": {
                  "type": "string",
                  "title": "Video Quality Label"
                },
                "bitrateInfo": {
                  "type": "array",
                  "title": "Bitrate Info",
                  "description": "All available quality/bitrate variants with play URLs"
                },
                "volumeInfo": {
                  "type": "object",
                  "title": "Volume Info",
                  "description": "Audio loudness and peak level metadata"
                },
                "subtitles": {
                  "type": "array",
                  "title": "Subtitles/Captions",
                  "description": "Available caption tracks (auto-generated or original) with expiring VTT URLs",
                  "items": {
                    "type": "object",
                    "properties": {
                      "language": {
                        "type": "string"
                      },
                      "languageCode": {
                        "type": "string"
                      },
                      "isAutoGenerated": {
                        "type": "boolean"
                      },
                      "isOriginal": {
                        "type": "boolean"
                      },
                      "format": {
                        "type": "string"
                      },
                      "url": {
                        "type": "string"
                      }
                    }
                  }
                },
                "qualityScore": {
                  "type": "number",
                  "title": "Quality Score",
                  "description": "TikTok's internal video-quality score (VQScore)"
                },
                "qualityTags": {
                  "type": "array",
                  "title": "Quality Tags",
                  "description": "UI badge labels TikTok attaches to the video (e.g. 'Top liked')"
                },
                "coverVariants": {
                  "type": "object",
                  "title": "Cover Variants",
                  "description": "Additional cover-image resolutions keyed by pixel size"
                }
              }
            },
            "images": {
              "type": "array",
              "title": "Slideshow Images",
              "description": "Images for slideshow posts (postType='slideshow')",
              "items": {
                "type": "object",
                "properties": {
                  "ordinal": {
                    "type": "integer",
                    "title": "Index"
                  },
                  "width": {
                    "type": "integer",
                    "title": "Width"
                  },
                  "height": {
                    "type": "integer",
                    "title": "Height"
                  },
                  "urlList": {
                    "type": "array",
                    "title": "Image URLs"
                  }
                }
              }
            },
            "hashtags": {
              "type": "array",
              "title": "Hashtags",
              "description": "Hashtags used in the post caption",
              "items": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "title": "Hashtag ID"
                  },
                  "name": {
                    "type": "string",
                    "title": "Hashtag Name"
                  },
                  "isCommerce": {
                    "type": "boolean",
                    "title": "Is Commerce"
                  }
                }
              }
            },
            "mentions": {
              "type": "array",
              "title": "Mentions",
              "description": "@mentions in the post caption with text offsets",
              "items": {
                "type": "object",
                "properties": {
                  "username": {
                    "type": "string",
                    "title": "Username"
                  },
                  "start": {
                    "type": "integer",
                    "title": "Start Offset"
                  },
                  "end": {
                    "type": "integer",
                    "title": "End Offset"
                  },
                  "awemeId": {
                    "type": "string",
                    "title": "Mentioned Post ID (if any)"
                  }
                }
              }
            },
            "rowType": {
              "type": "string",
              "title": "Row Type",
              "description": "'video' for all post rows (video or slideshow; use postType to distinguish) or 'hashtag' for hashtag metadata rows."
            },
            "queryVariant": {
              "type": "string",
              "title": "Query Variant",
              "description": "Casing/spacing variant of the query that found this post, when a query pass was used."
            },
            "hashtagMetadata": {
              "type": "object",
              "title": "Hashtag Metadata",
              "description": "Hashtag details from TikTok for searchType=hashtags and hashtag-expansion rows.",
              "properties": {
                "hashtagId": {
                  "type": "string",
                  "title": "Hashtag ID"
                },
                "name": {
                  "type": "string",
                  "title": "Name"
                },
                "desc": {
                  "type": "string",
                  "title": "Description"
                },
                "isCommerce": {
                  "type": "boolean",
                  "title": "Commerce Hashtag"
                },
                "videoCount": {
                  "type": "integer",
                  "title": "Videos"
                },
                "viewCount": {
                  "type": "integer",
                  "title": "Views"
                },
                "profileUrl": {
                  "type": "string",
                  "title": "Profile Image URL"
                },
                "shareTitle": {
                  "type": "string",
                  "title": "Share Title"
                },
                "shareDesc": {
                  "type": "string",
                  "title": "Share Description"
                }
              }
            }
          }
        }
      },
      "defaultMemoryMbytes": 2048,
      "minMemoryMbytes": 2048,
      "readme": "# TikTok Keyword Discovery — Videos, Photos, Hashtags & Creators\n\nSearch TikTok by keyword and get structured video and photo posts, or look up a hashtag's own\nmetadata. Each row carries the caption, engagement counts, creator snapshot, sound details,\nhashtags and mentions, and the post's stable URL. Optional discovery expansion runs related\nsearches, top hashtags and the most-reused sound from a keyword's own results to surface more\nposts. No login, cookies or proxy setup required.\n\n## What this actor does\n\n- **Three search types:** `videos` by keyword, `photos`/slideshows by keyword, and `hashtags`\n  with metadata plus the tag's top posts\n- **Deep pagination:** keeps loading until TikTok's own result pool ends or your per-query limit\n  is reached (TikTok typically serves about 150–220 posts per query)\n- **Video and photo rows:** captions, creation time, plays, likes, comments, shares, saves,\n  reposts, creator profile snapshot, sound metadata, video technical details and slideshow images\n- **Discovery expansion:** related searches, top hashtags and sound pages, deduplicated against\n  the seed results\n- **Client-side controls:** sort by relevance/likes/views/newest, date window, duration, ads,\n  minimum likes/views, one post per creator and max posts per creator\n- **Honest empty fields:** fields TikTok does not provide for a post are omitted, never `null`\n\n## Output per post\n\n- `rowType` — `video` for all post rows (including slideshows; `postType` says which) or `hashtag` for hashtag metadata rows\n- `postId`, `postUrl`, `postType` — post identity; `postType` is `video` or `slideshow`\n- `caption`, `textLanguage`, `createTime`, `createdAt`\n- `query` — the search phrase that returned this post; `rank` — zero-based position in that\n  search; `queryVariant` — casing/spacing variant when a query pass found it\n- `searchType` — `general`, `photo`, `hashtag` or `sound`\n- `expansionSource`, `expansionTerm` — only on expansion-discovered posts\n- `playCount`, `likeCount`, `commentCount`, `shareCount`, `collectCount`, `repostCount`\n- `author.id`, `author.secUid`, `author.username`, `author.displayName`, `author.bio`,\n  `author.verified`, `author.privateAccount`, `author.avatarUrl`, `author.followerCount`,\n  `author.followingCount`, `author.heartCount`, `author.videoCount`, `author.roomId`,\n  `author.isVirtualAccount`\n- `music.id`, `music.title`, `music.authorName`, `music.original`, `music.duration`,\n  `music.album`, `music.playUrl`, `music.coverUrl`, and licensing flags\n- `video.width`, `video.height`, `video.duration`, `video.ratio`, `video.definition`,\n  `video.bitrate`, `video.codecType`, `video.format`, `video.size`, `video.videoQuality`,\n- `video.playUrl`, `video.downloadAddr` — signed CDN URLs, reference-only: TikTok's CDN can\n  reject direct downloads (HTTP 403) even while the post plays on TikTok\n- `video.cover`, `video.originCover`, `video.dynamicCover`, `video.subtitles`,\n  `video.qualityScore`, `video.qualityTags`,\n  `video.coverVariants`, `video.bitrateInfo`, `video.volumeInfo`\n- `images[]` — real image URLs for slideshow/photo posts\n- `hashtags[]`, `mentions[]`, `poi` — caption tags, @mentions and a location tag when present\n- `isAd`, `isECVideo`, `adLabelVersion`, `privateItem`, `forFriend`, `isAigc`,\n  `AIGCDescription`, `originalItem`, `categoryType`, `item_control`, `contents`,\n  `effectStickers`, `stickersOnItem`\n- `mediaUrlExpiresAt` — when the signed media URLs expire, when it can be read\n\n## Output per hashtag\n\nHashtag searches emit one metadata row (`rowType: \"hashtag\"`) before the tag's post rows:\n\n- `query` — the hashtag, e.g. `#coffee`\n- `hashtagMetadata.hashtagId`, `name`, `desc`, `isCommerce`, `videoCount`, `viewCount`,\n  `profileUrl`, `shareTitle`, `shareDesc`\n\n## Input\n\n| Field | Type | Default | Description |\n|---|---|---|---|\n| `searchType` | string | `videos` | `videos`, `photos` or `hashtags` |\n| `queries` | string[] | — | Keywords for video/photo search |\n| `hashtags` | string[] | — | Hashtags for `searchType=hashtags`; `#` optional |\n| `maxResultsPerQuery` | integer | 30 | Posts per query/tag before filters (1–500) |\n| `sortBy` | string | `relevance` | `relevance`, `mostLiked`, `mostViewed`, `newest` |\n| `publishedWithin` | string | `all` | `all`, `day`, `week`, `month`, `3months`, `6months`; narrow windows scan up to 5× the requested count |\n| `minDurationSeconds` | integer | — | Drop shorter videos |\n| `maxDurationSeconds` | integer | — | Drop longer videos |\n| `excludeAds` | boolean | false | Drop posts flagged as ads |\n| `minLikeCount` | integer | — | Drop posts with fewer likes |\n| `minViewCount` | integer | — | Drop posts with fewer plays |\n| `uniqueAuthors` | boolean | false | Keep at most one post per creator |\n| `maxPostsPerAuthor` | integer | — | Cap posts per creator (ignored when `uniqueAuthors` is on) |\n| `enableExpansion` | boolean | false | Run related searches, hashtags and sounds |\n| `expansionSources` | string[] | `[\"suggestions\", \"hashtags\", \"sounds\"]` | `suggestions`, `hashtags`, `sounds` |\n| `maxExpansionQueriesPerSeed` | integer | 3 | Extra searches per keyword (0–10) |\n| `includeHashtagMetadata` | boolean | true | Emit hashtag metadata rows/expansion metadata |\n\n## Examples\n\n### Keyword video search\n\n```json\n{\n  \"searchType\": \"videos\",\n  \"queries\": [\"cottagecore aesthetic\", \"dark academia\"],\n  \"maxResultsPerQuery\": 100,\n  \"sortBy\": \"mostLiked\",\n  \"publishedWithin\": \"month\"\n}\n```\n\n### Photo / slideshow search\n\n```json\n{\n  \"searchType\": \"photos\",\n  \"queries\": [\"coffee\"],\n  \"maxResultsPerQuery\": 50\n}\n```\n\n### Hashtag discovery\n\n```json\n{\n  \"searchType\": \"hashtags\",\n  \"hashtags\": [\"coffee\", \"#fitness\"],\n  \"maxResultsPerQuery\": 30,\n  \"includeHashtagMetadata\": true\n}\n```\n\n### Creator shortlist with expansion\n\n```json\n{\n  \"searchType\": \"videos\",\n  \"queries\": [\"skincare routine\"],\n  \"maxResultsPerQuery\": 200,\n  \"uniqueAuthors\": true,\n  \"enableExpansion\": true,\n  \"expansionSources\": [\"suggestions\", \"hashtags\"],\n  \"maxExpansionQueriesPerSeed\": 3\n}\n```\n\n## Use cases\n\n- **Content research** — see which videos and slideshows rank for a topic, newest or most liked\n- **Creator discovery** — collapse results to one post per creator, then review follower counts\n- **Brand and campaign monitoring** — track keyword mentions, hashtags and sounds across markets\n- **Trend exploration** — expand a seed keyword through TikTok's own related searches and tags\n- **Dataset building** — export structured post, engagement and creator fields for analysis\n\n## FAQ\n\n### Do I need a TikTok account or cookies?\n\nNo. The actor reads the search results TikTok shows to signed-out visitors. There is no cookie,\ntoken or proxy field to fill in. TikTok sometimes asks anonymous cloud IPs to log in; the actor\nautomatically retries with a different proxy session and never asks you for credentials.\n\n### How many results can I get per query?\n\nTikTok's own search pool usually ends around 150–220 posts per query, even when a larger limit is\nrequested. The actor follows TikTok's cursor until the pool ends, then optionally runs casing and\nspacing query passes. To collect more, add more queries or turn on discovery expansion.\n\n### Why is my result count lower than `maxResultsPerQuery`?\n\nTwo reasons: TikTok may exhaust its result pool before your limit, and the date, duration, ads,\nlikes, views and creator filters run after collection. The final dataset is always the\npost-filter set.\n\n### Are the sort and filters applied by TikTok or by the actor?\n\nBy the actor. The actor collects posts in TikTok's default relevance order and then applies your\nsort and filters locally. For a narrow date window it scans up to 5× the requested count (capped\nat 500) before applying the window; because that scan is bounded, a week or day window can\nlegitimately yield fewer posts than requested.\n\n### What is the difference between the video and photo search types?\n\nBoth return posts for a keyword. Video search uses TikTok's main search ranking; photo search\nuses its photo/slideshow vertical. Photo rows always include `images[]`; video playback fields\nare omitted because slideshows do not carry a direct video stream.\n\n### Why are some fields missing on some posts?\n\nTikTok includes fields such as subtitles, location, mentions, AR effects or quality badges only\nwhen they apply. Empty fields are omitted rather than filled with placeholders.\n\n### Do the media URLs work forever?\n\nTikTok's media URLs are signed and expire; `mediaUrlExpiresAt` shows when the actor can read the\nexpiry. Use `postUrl` as the stable reference. Cover images, avatars and sound preview URLs are\ngenerally directly accessible, but TikTok's video CDN may reject direct downloads even while the\nvideo plays on TikTok itself.\n\n### Can I search a specific country or language?\n\nQueries can be in any language and return results in that language. TikTok's web search does not\nexpose a working country filter: its `region` parameter is cosmetic and results still follow the\nrequest's network location, so no region input is offered.\n\n### Can I search for creators directly?\n\nThis actor focuses on posts and hashtags. To find creators, use `uniqueAuthors` on a keyword\nsearch (one post per creator), or turn on expansion to reach more creators through related\nsearches, hashtags and sounds. A dedicated user-search mode is not included because TikTok\nserves it inconsistently to signed-out sessions.\n\n### Is this affiliated with TikTok?\n\nNo. It is an independent tool that reads TikTok's public search results and is not run or\nendorsed by TikTok.\n"
    },
    "buildNumber": "1.0.7",
    "imageDigest": "08e296f4086e7acbedeefc4da9cc6358e5a80d36703070dee355bcc987049ae1",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "1.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.04566111111111111
    }
  }
}