TikTok Video Scraper & TikTok Hashtag Scraper: Stats by URL avatar

TikTok Video Scraper & TikTok Hashtag Scraper: Stats by URL

Pricing

from $1.50 / 1,000 videos

Go to Apify Store
TikTok Video Scraper & TikTok Hashtag Scraper: Stats by URL

TikTok Video Scraper & TikTok Hashtag Scraper: Stats by URL

TikTok video scraper, no login: video URLs, share links or hashtags in, one row per video out. Plays, likes, comments, shares, saves as TikTok shows them (rounded above 10K); caption, hashtags, mentions, date, duration, sound, author, subtitles, cover and video files. Misses free.

Pricing

from $1.50 / 1,000 videos

Rating

0.0

(0)

Developer

Hyperbach

Hyperbach

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 hours ago

Last modified

Features

Limited permissions

Share

TikTok videos, logged out: video URLs, share links or hashtags in — one row per video out. Each row has the video's id and link, the caption, hashtags and mentions, the date posted, the play, like, comment, share, save and repost counts as TikTok's page shows them, the duration and the video's format, the cover and video links, the sound (title, author, original flag, length), the author's public profile with follower, following, like and video counts, the subtitle tracks, the ad and AI-generated labels, the location the video was posted from — and the country and TikTok data centre each row was read from. Every video URL gets its row in your order; a video TikTok does not have is a free row that says so. Date, count, duration and ad filters checked on every row; the cover and the MP4 stored on request. No login, no cookies, proxies handled for you.

From $3.00 per 1,000 rows (video) on the Free plan, $2.55 on Starter; every row and add-on is priced under Pricing below. A run start is $0.001. The default input returns about 3 rows for about $0.01. A value that names nothing is a free row that says why.

A TikTok video page in a desktop browser: a skatepark clip with likes, comments, saves and shares beside it. Next to it, the row this Actor returns, with comments, read_country and data_centre highlighted so each count names the view it came from.

Why this TikTok video scraper

  • The counts TikTok's page shows, with the view they came from. Plays, likes, comments, shares and reposts, and the author's followers, following, likes and videos, are the figures TikTok's logged-out web serves: to the unit up to 9,999 and rounded above 10,000 the way TikTok's own page shows them (369.6K, so 369,600, for 369,589 plays; 33.3M followers, so 33,300,000), on a video page and in the hashtag list alike. Saves come to the unit. The figure to the unit above 10,000 is the mobile app's, which a logged-out web read does not get. TikTok keeps the comment and save counts per data centre: one video read 249 and 236 comments from two US data centres, 235 from Canada and 230 from Europe in two minutes, and 10,280, 10,270 and 10,271 saves from the US, Germany and Japan. Every row names read_country and data_centre, and readCountry picks the view (12 countries).
  • Every URL gets its row, in your order. A video link, a photo-post link, a share link (vm.tiktok.com, vt.tiktok.com, /t/), an m.tiktok.com or embed link or a bare id is read; a link TikTok does not know gets a free not_found row only when a second connection agrees, a share link that opens a profile gets a free not_a_video row. The rows come out in the order you gave the links.
  • Filters you can trust. The Actor checks the date window, the counts, the duration and the ad flag on every hashtag video before it is delivered, on the video's own date and figures. A video your filters leave out is never charged, and the hashtag's row counts it.
  • Hashtags with a verdict. Each hashtag gets a free row: COMPLETE (TikTok's list ended), MAX_REACHED (your limit), PARTIAL (stopped, with the reason), TRUNCATED (TikTok's list ended far below the count TikTok gives, so the rest is not served logged out: a big hashtag's list ended at 118 to 175 videos in our eight reads), with the videos read, delivered and filtered out.
  • Photo posts too. A slideshow is a row like a video, with its images; its link works on its /photo/ or its /video/ form.
  • Fast. Video links and hashtag lists are read over plain HTTP, several pages at once: in our tests on Apify 127 video links were read in 9.5 s, and a hashtag's list to its end (122 and 167 videos) was out 11.3 and 21.0 s after the run started (warm runs of 2026-10-30). A stealth browser reads a hashtag only when TikTok refuses the plain list. A run on a fresh server first spends about 30 s loading the Actor's image (it carries that browser).

Who it's for

  • Marketers and social media teams — the play, like, comment and share counts of your videos and your competitors' videos from their links, refreshed by a schedule; the recent videos of a hashtag in a date window, over a likes floor.
  • Researchers and analysts — a hashtag's videos with the caption, hashtags, date, counts and author on each row, the subtitle tracks, the ad and AI labels, and a verdict per hashtag to report against.
  • Influencer and creator scouts — the creators behind a topic's videos with their follower counts and bios, filtered by likes or plays to find the rising ones.
  • Developers and data teams — typed rows keyed by video_id, one row per input link in your order, a free row per hashtag with its status, a run summary to check a pipeline against, every input constrained in the schema.

Quick start

Three videos by link

{
"videoUrls": [
"https://www.tiktok.com/@olympics/video/7210447318028455173",
"https://www.tiktok.com/@olympics/video/7208589533632269574",
"https://www.tiktok.com/t/ZTyMpW4m5/"
]
}

A hashtag's videos of this month with at least 1,000 likes

{
"hashtags": [
"lasagna"
],
"postedWithin": "month",
"minLikes": 1000,
"maxItemsPerQuery": 50
}

A hashtag's videos with their subtitles and posting location

{
"hashtags": [
"olympics"
],
"maxItemsPerQuery": 100,
"searchDetails": true
}

Videos with their cover and MP4 stored

{
"videoUrls": [
"https://www.tiktok.com/@olympics/video/7210447318028455173"
],
"downloadCovers": true,
"downloadVideos": true
}

Output

One row per video (charged), one free row per video URL that gave no video, and one free row per hashtag:

fieldmeaning
record_typevideo on a video row (charged when status is ok); query on a hashtag's free row.
statusok, or why an input gave no video: not_found (TikTok has no such video or hashtag; two connections agree), not_a_video (a share link that opens a profile or another page), not_available (TikTok does not show the video in the country read: try another readCountry), duplicate (the same video as an earlier input), invalid_input, failed (TikTok refused every connection), not_read (a limit or the time limit stopped the run first).
input_typeWhich input gave the row: url (videoUrls) or hashtag (hashtags).
inputThe value you gave that this row answers.
positionThe video's place among the distinct videos of the hashtag's list, 1 for the first (TikTok's order; a video TikTok's pages repeat keeps its first place).
read_countryThe country TikTok served this row to (the page's own reading of the connection; US for every hashtag list).
data_centreThe TikTok data centre that answered (useast5, useast8, useast2b …). The comment and save counts can differ between them.
detail_sourceWhich TikTok answer the row's fields come from: page (the video's own page) or hashtag_list (the hashtag's list).
media_filesThe stored files (downloadCovers, downloadSlideshowImages, downloadVideos): kind, key, url, bytes, content_type, source_url, reused. A photo post with downloadSlideshowImages carries every image (<id>-image-<n>.jpg).
cover_file_urlThe stored cover image's link in the run's key-value store (does not expire).
video_file_urlThe stored MP4's link in the run's key-value store (does not expire).
verdictOn a hashtag's row: COMPLETE (TikTok's list ended), MAX_REACHED (maxItemsPerQuery), PARTIAL (stopped: note says why), TRUNCATED (TikTok's list ended far below the count TikTok gives: the source's limit, note names both figures), NO_RESULTS.
rows_deliveredOn a hashtag's row: the videos it delivered.
rows_readOn a hashtag's row: the distinct videos read from TikTok's list (a video its pages repeat counts once).
rows_droppedOn a hashtag's row: the videos your filters left out (free).
pagesOn a hashtag's row: the list pages read.
source_filter_honouredNull on every row since 2026-10-30 (it read whether TikTok's own date filter held on a search's first page; TikTok's search now asks for a login).
sort_honouredNull on every row since 2026-10-30 (it read whether TikTok sorted a search's first page by likes; TikTok's search now asks for a login).
noteWhy a row has the status or the verdict it has.
scraped_atWhen this row was read (UTC).
video_idTikTok's video id (a string).
video_urlThe video's page (/photo/ for a photo post).
descriptionThe caption as the creator wrote it, with its line breaks.
text_languageThe caption's language as TikTok detects it (ISO 639-1).
created_atWhen the video was posted (UTC).
created_at_timestampWhen the video was posted, as a unix time in seconds.
playsPlays as TikTok's logged-out page shows them: to the unit up to 9,999, rounded above 10,000 (369.6K = 369,600).
likesLikes, as TikTok's page shows them (rounded above 10,000, like plays).
commentsComments, as TikTok's page shows them (rounded above 10,000, like plays), as the data centre in data_centre counts them.
sharesShares, as TikTok's page shows them (rounded above 10,000, like plays).
savesSaves (favourites), to the unit, as the data centre in data_centre counts them.
repostsReposts, as TikTok's page shows them (rounded above 10,000, like plays).
hashtagsThe caption's hashtags: id, name and the hashtag's own description (title) where TikTok gives one.
mentionsThe handles the caption mentions.
detailed_mentionsThe caption's mentions with the account id, handle and sec_uid.
duration_sThe video's length in seconds (null on a photo post).
widthThe video's width in pixels.
heightThe video's height in pixels.
ratioTikTok's quality label of the stream (540p, 720p).
definitionThe stream's definition (540p, 720p, 1080p).
video_formatThe file format (mp4).
bitrateThe main stream's bitrate in bits a second.
codecThe main stream's codec (h264, h265).
cover_urlThe cover image (a signed TikTok link that expires; the image itself opens without cookies).
origin_cover_urlThe cover's original-size image.
play_urlTikTok's video stream link. It works only with the reading session's cookies and expires at media_expires_at: use downloadVideos for a file you can keep.
download_urlTikTok's download link, where the page gives one (same rules as play_url).
media_expires_atWhen the signed cover and video links stop working (UTC).
subtitlesTikTok's own subtitle tracks: language (e.g. eng-US), source (ASR speech recognition, MT machine translation, LC the creator's), format and the file's url (WebVTT, opens without cookies). On a hashtag row: the tracks TikTok's list answer carries, null when the answer leaves them out; every video's own tracks with searchDetails.
is_photo_posttrue for a photo post (slideshow).
image_countA photo post's number of images.
image_urlsA photo post's images, in order.
music_idThe sound's id (a string).
music_titleThe sound's title.
music_authorThe sound's author.
music_albumThe sound's album, where TikTok gives one.
music_originaltrue for an original sound (made on TikTok, by this or another creator).
music_duration_sThe sound's length in seconds.
music_urlThe sound's audio file (opens without cookies).
music_cover_urlThe sound's cover image.
author_idThe author's TikTok user id (a string).
author_sec_uidThe author's secUid, TikTok's stable account key.
author_usernameThe author's handle (without @).
author_nicknameThe author's display name.
author_verifiedtrue when the account carries TikTok's verified badge, read from this video's record.
author_bioThe author's bio.
author_bio_linkThe link in the author's bio, where there is one.
author_avatar_urlThe author's profile picture.
author_privatetrue for a private account.
author_tt_sellertrue for a TikTok Shop seller account.
author_created_atWhen the author's account was created (UTC; on hashtag rows with searchDetails).
author_followersThe author's followers, as TikTok's page shows them (rounded above 10,000: 15.2M = 15,200,000).
author_followingThe accounts the author follows, as TikTok's page shows them (rounded above 10,000).
author_likesThe likes the author's videos received in all, as TikTok's page shows them (rounded above 10,000).
author_videosThe author's public videos.
author_diggsThe videos the author liked, as TikTok counts them.
author_friendsAlways null: TikTok's logged-out page gives 0 friends (mutual follows) for every author, so the figure is not served logged out.
author_room_idThe author's live room id while the author is live.
author_has_storytrue when the author has an active story.
is_adtrue when TikTok marks the video as an ad.
ad_authorizationtrue when the creator authorised the video for ads.
is_pinnedAlways null: no logged-out TikTok answer for a video names the creator's pin (never a guessed false).
is_ai_generatedtrue when TikTok labels the video as AI-generated (IsAigc); null on a hashtag row without searchDetails.
ai_generated_labelTikTok's AI-generated label text, where there is one.
location_createdThe country the video was posted from (ISO code); on hashtag rows with searchDetails.
duet_enabledtrue when duets are allowed (null when TikTok does not say).
stitch_enabledtrue when stitches are allowed (null when TikTok does not say).
comments_enabledtrue when comments are open.
effect_stickersThe effects used: id and name.

Example record:

{
"record_type": "video",
"status": "ok",
"input_type": "url",
"input": "https://www.tiktok.com/@olympics/video/7210447318028455173",
"position": null,
"read_country": "US",
"data_centre": "useast8",
"detail_source": "page",
"media_files": null,
"cover_file_url": null,
"video_file_url": null,
"verdict": null,
"rows_delivered": null,
"rows_read": null,
"rows_dropped": null,
"pages": null,
"source_filter_honoured": null,
"sort_honoured": null,
"note": null,
"scraped_at": "2026-10-29T18:39:31Z",
"video_id": "7210447318028455173",
"video_url": "https://www.tiktok.com/@olympics/video/7210447318028455173",
"description": "POV: you are a horse at the Olympics ⚡️\nRio 2016 #Olympics #Athletes #Sports #SportsTok #Equestrian #Horse #HorseTok ",
"text_language": "en",
"created_at": "2023-03-14T16:58:13Z",
"created_at_timestamp": 1678813093,
"plays": 1000000,
"likes": 142800,
"comments": 249,
"shares": 1928,
"saves": 10281,
"reposts": 0,
"hashtags": [
{
"id": "569333",
"name": "olympics",
"title": "The Winter 2026 Olympic Games are for everyone! Show off your passion for the Games using #Olympics"
},
{
"id": "30888",
"name": "athletes",
"title": null
},
{
"id": "7887",
"name": "sports",
"title": null
},
{
"id": "1617221133106342",
"name": "sportstok",
"title": null
},
{
"id": "8097",
"name": "equestrian",
"title": "Equestrians of TikTok, let's ride 🐎"
},
{
"id": "7883",
"name": "horse",
"title": null
},
{
"id": "1627697747948550",
"name": "horsetok",
"title": null
}
],
"mentions": [],
"detailed_mentions": [],
"duration_s": 6,
"width": 576,
"height": 1024,
"ratio": "540p",
"definition": "540p",
"video_format": "mp4",
"bitrate": 2197323,
"codec": "h264",
"cover_url": "https://p16-common-sign.tiktokcdn-us.com/tos-maliva-p-0068/bf215101a9bd40d797e24cc605351eb6_1678813095~tplv-tiktokx-origin.image?…",
"origin_cover_url": "https://p19-common-sign.tiktokcdn-us.com/tos-maliva-p-0068/0db1aa9f2e8e4db08ff6b1bafc662052_1678813095~tplv-tiktokx-origin.image?…",
"play_url": "https://v16-webapp-prime.us.tiktok.com/video/tos/useast2a/tos-useast2a-ve-0068c001/oEqIM2UC9gfjPIGRAPfHA6CSnCI4h0fDId8Bzx/?…",
"download_url": null,
"media_expires_at": "2026-10-31T17:49:49Z",
"subtitles": [
{
"language": "eng-US",
"source": "ASR",
"format": "webvtt",
"url": "https://v16m-webapp.tiktokcdn-us.com/4035eb6c40c64f354b3867b859db48af/6ae62a3d/video/tos/useast2a/tos-useast2a-v-0068/b27803a0dc8142bb9fbb96df353f0812/?…"
}
],
"is_photo_post": false,
"image_count": null,
"image_urls": null,
"music_id": "7149262464009030442",
"music_title": "original sound",
"music_author": "Breanne",
"music_album": null,
"music_original": true,
"music_duration_s": 7,
"music_url": "https://v16m.tiktokcdn-us.com/c7ceb190967d4bff2699d9e3bec89bc3/6ae3db9e/video/tos/useast5/tos-useast5-v-27dcd7-tx/ceb8de41b6204d1d958ef65b27b1baf3/?…",
"music_cover_url": "https://p19-common-sign.tiktokcdn-us.com/tos-useast5-avt-0068-tx/c79fa45299dae46902426ecdedd4d28f~tplv-tiktokx-cropcenter:1080:1080.jpeg?…",
"author_id": "6754011909617894406",
"author_sec_uid": "MS4wLjABAAAA488JA-imwOQzZbBA62XbV0eezMZ_Esx1CLYGKP2Y-5AWXd-xc-Y6FTZzzlL3lzLv",
"author_username": "olympics",
"author_nickname": "Olympics™",
"author_verified": true,
"author_bio": "Excellence, respect and friendship 🕊️\n\nWatch the Youth Olympics here!\nDakar 2026 🦁👇",
"author_bio_link": null,
"author_avatar_url": "https://p16-common-sign.tiktokcdn-us.com/tos-alisg-avt-0068/829ea90040553aaec7450d66caaadc10~tplv-tiktokx-cropcenter:1080:1080.jpeg?…",
"author_private": false,
"author_tt_seller": false,
"author_created_at": "2019-10-31T17:05:56Z",
"author_followers": 15200000,
"author_following": 364,
"author_likes": 376400000,
"author_videos": 5862,
"author_diggs": 994,
"author_friends": null,
"author_room_id": null,
"author_has_story": false,
"is_ad": true,
"ad_authorization": true,
"is_pinned": null,
"is_ai_generated": false,
"ai_generated_label": null,
"location_created": "ES",
"duet_enabled": true,
"stitch_enabled": true,
"comments_enabled": true,
"effect_stickers": []
}

Pricing

Pay only for the videos a run delivers, with no platform usage billed to you. The video's price falls with your Apify plan.

per 1,000FreeStarterScaleBusiness
Video (video)$3.00$2.55$2.10$1.50
Stored video file (MP4) (media_file)+$6.10+$6.10+$6.10+$6.10
Stored photo-post image (image_file)+$0.24+$0.24+$0.24+$0.24
per unitFreeStarterScaleBusiness
Hashtag list (hashtag_list)+$0.0001+$0.0001+$0.0001+$0.0001
Run start (start)+$0.001+$0.001+$0.001+$0.001

A video is $3.00 per 1,000 on the Free plan ($0.003 a video) and $1.50 on Business, from a link or a hashtag alike. The run start is $0.001, once per run, with the run's first charged video: a run that delivers no video pays nothing. A hashtag is $0.0001 once, with its first delivered video; a hashtag that delivers no video is not charged. TikTok's logged-out list of a big hashtag ends long before the count TikTok shows: at 118 to 175 videos in our eight reads to its end (two hashtags, 2026-10-29 and 10-30). A stored MP4 (downloadVideos) is $0.0061 per file written to the run's store this run: the file TikTok's page plays, which the leading TikTok scraper stores too; ordinary videos' files are large (1.5–56 MB, 25 MB on average over 10 ordinary videos), and the price follows that. A photo post's image (downloadSlideshowImages) is $0.00024 an image. A stored cover (downloadCovers) is free. A file the store already holds is linked, not charged. So three video links cost $0.01 on Free and a hashtag's 30 videos cost $0.0911. A link that gives no video (removed, private, a profile, a dead share link, a value that names no video), a repeat, a video your filters leave out, every hashtag row, a rejected input and the inputs a limit or the time limit left unread are labelled rows and free. maxItems counts videos and stops the run at that count, never past it; before the first request the log says the most the run can cost at your plan's prices and names the fees of the options you switched on. Enterprise plans have their own rates: the Actor's Pricing tab shows the price for your plan.

Usage patterns

  • Video links — videoUrls takes https://www.tiktok.com/@user/video/<id> and /photo/<id> links, share links (vm.tiktok.com/…, vt.tiktok.com/…, tiktok.com/t/…, followed once), m.tiktok.com/v/<id>.html and embed links, a bare 19-digit id and a TikTok link wrapped in another site's redirect. A profile link, a hashtag link or a search link gets a free invalid_input row that says where it belongs (a profile's videos are tiktok-profile-scraper's job). The same video twice gets one charged row and a free duplicate row.
  • Hashtags — hashtags reads the hashtag's own list, the one its page (tiktok.com/tag/<name>) shows, 30 videos a page, in the page's order, over plain HTTP: TikTok signs every page of that list and the Actor signs it as the page does. When TikTok refuses the plain list on several fresh connections, the Actor loads the hashtag's page in a stealth browser and reads the list there, so a run with hashtags takes 4 GB of memory. TikTok's logged-out list of a big hashtag ends after about 4 to 7 pages (118 to 175 videos in our eight reads to its end, of the 2,003,086 videos TikTok counted under #olympics and 1,779,841 under #sourdough): the hashtag's row then says TRUNCATED with both figures, never COMPLETE; a list that stops giving more says PARTIAL with the reason. A hashtag TikTok does not know is a free not_found row. Each video carries its position in the list. TikTok's own search box asks a logged-out visitor to log in since 2026-10-30, so this Actor reads hashtags and links, not search words.
  • Filters — postedWithin (or postedAfter / postedBefore), minPlays, minLikes, maxLikes, minComments, minShares, minDuration, maxDuration and excludeAds apply to the hashtag videos, checked on each video before it is delivered; your video links are always read. A filtered video is free and counted on the hashtag's row (rows_dropped). strictHashtag keeps only the videos whose caption carries the hashtag itself.
  • Details and files — searchDetails reads each delivered hashtag video's own page for what the lists leave out (subtitle tracks, the posting location, the AI-generated label, the author's account date), at no extra charge. downloadCovers stores the cover image (free with its row), downloadVideos the MP4 the page plays (the file the leading scraper stores; ordinary videos 1.5-56 MB) and downloadSlideshowImages a photo post's images, in the run's key-value store with links that do not expire (cover_file_url, video_file_url, media_files); TikTok's own play_url works only with the reading session's cookies and expires in hours (media_expires_at).

Input configuration

fieldtypedefaultwhat it does
videoUrlsarray[]TikTok videos to read, one per line: a video or photo link (https://www.tiktok.com/@user/video/7210447318028455173), a share link (vm.tiktok.com/…, vt.tiktok.com/…, tiktok.com/t/…), an m.tiktok.com/v/<id>.html or embed link, or a bare video id. Each value gets its own row, in your order: the video, or a free row that says why not (not found, a profile link, a dead share link).
hashtagsarray[]Hashtags, one per line, with or without # (olympics, #fyp, a tiktok.com/tag/… link): the videos of the hashtag's own list, up to maxItemsPerQuery each, read over plain HTTP; a stealth browser reads a hashtag only when TikTok refuses the plain list, so a run with hashtags takes 4 GB of memory.
maxItemsPerQueryinteger50The most videos each hashtag delivers. TikTok's logged-out list of a big hashtag ends after about 120 to 175 videos; the hashtag's row says when the list ended before your number.
maxItemsinteger0The most charged videos of the whole run; 0 = no cap beyond your charge limit. Every input still gets its row.
postedWithinany / day / week / month / 3months / 6months"any"Keep only hashtag videos posted in this window, checked on each video's own date. A video outside it is not delivered and not charged. Video URLs are always read.
postedAfterstringKeep only hashtag videos posted on or after this date (UTC, YYYY-MM-DD). Checked on each video's own date.
postedBeforestringKeep only hashtag videos posted before this date (UTC). Checked on each video's own date.
minPlaysintegerKeep only hashtag videos with at least this many plays (the figure TikTok's page shows: rounded above 10,000).
minLikesintegerKeep only hashtag videos with at least this many likes.
maxLikesintegerKeep only hashtag videos with at most this many likes (to find smaller creators).
minCommentsintegerKeep only hashtag videos with at least this many comments.
minSharesintegerKeep only hashtag videos with at least this many shares.
minDurationintegerKeep only hashtag videos at least this long (a photo post has no duration and is left out when a duration is set).
maxDurationintegerKeep only hashtag videos at most this long.
excludeAdsbooleanfalseLeave out hashtag videos TikTok marks as ads (is_ad).
strictHashtagbooleanfalseKeep only the hashtag videos whose caption carries the hashtag itself. TikTok's tag page also lists videos without it (74 of 162 under #olympics in our test); those are left out, free, and counted in the hashtag's rows_dropped.
readCountryUS / GB / DE / FR / ES / NL / PL / CA / BR / MX / JP / AU"US"The country video URLs are read from. TikTok's comment count differs by data centre (one video read 249, 236, 235 and 230 comments in two minutes from the US, Canada and Europe); every row names the country and the data centre it was read from. Hashtag lists are always read from the US. TikTok often walls readers in Canada, Brazil, Japan, Mexico and Australia (measured in November 2026): a run from there can end PARTIAL, and a video TikTok refuses is a free failed row. The US, the UK, Germany and France read reliably.
searchDetailsbooleanfalseRead each delivered hashtag video's own page too, for what TikTok's lists leave out: the subtitle tracks, the location the video was posted from, the AI-generated label, the author's account date. About half a second a video more; no extra charge.
downloadCoversbooleanfalseStore each video's cover image in the run's key-value store, with a link that does not expire on the row (cover_file_url). Free with the row.
downloadSlideshowImagesbooleanfalseStore every image of a photo post (slideshow) in the run's key-value store, each linked in media_files. Charged per image stored.
downloadVideosbooleanfalseStore each video's MP4 file in the run's key-value store, with a link that does not expire on the row (video_file_url): the file TikTok's page plays, the same file the leading TikTok scraper stores. Ordinary videos are large (1.5-56 MB, 25 MB on average over 10 ordinary videos of 11-465 s). TikTok's own video link works only with the reading session's cookies. Charged per MP4 stored.
proxyUrlstringYour own proxy (scheme://user:pass@host:port) for every call instead of ours. Leave empty: the Actor brings its own connections at no cost to you.
feedbackstringA note to the people who maintain this Actor: what you needed and did not get. For example a missing field, a wrong or empty result, or the Actor you switch from or to, and why. The run does not read it: the rows and the charges stay the same. A person reads every note.

Errors

A run does not fail because of your input. When an input cannot be used — a date that is not a date, an id in the wrong form, two settings that contradict each other — the run ends Succeeded, charges nothing, and says what to change:

  • the status message starts with INPUT REJECTED;
  • the dataset holds one row, {"error": true, "code": "…", "message": "…"}, and no results;
  • the key-value store record ERROR holds the same object.

From code, check error on the first row before reading results.

A video TikTok does not have (checked on a second connection), a share link that opens a profile or TikTok's home page, a hashtag TikTok does not know or a value that names nothing is not an error: it gets one free row with its status and the reason, and the run goes on with the others. A run that ends Failed is a fault on our side, never your input; it charges nothing, and we are alerted.

FAQ

Why does the comment count differ from what I see in the app?

TikTok keeps a comment count per data centre and they differ by a few percent: one video read 249 and 236 from two US data centres, 235 from Canada and 230 from Europe within two minutes. Each row names the country (read_country) and the data centre (data_centre) it was read from; set readCountry to read the view your audience sees. TikTok often walls readers in Canada, Brazil, Japan, Mexico and Australia (measured in November 2026): a run from there can end PARTIAL, and a video TikTok refuses is a free failed row. The US, the UK, Germany and France read reliably.

Why is a count like 369,600 rounded?

Because TikTok's logged-out web serves its display figure: a count above 10,000 is rounded the way TikTok's own page shows it (369.6K for 369,589 plays), on the video page and in the hashtag list alike, while saves and every count up to 9,999 come to the unit. A count to the unit above 10,000 comes from TikTok's mobile app, which a logged-out web read does not get. The min… filters test the figure the row carries.

Do I need a TikTok account, cookies or an API key?

No. Everything is read logged out: the video pages and the hashtag lists. There is no login input.

Why is is_pinned empty?

No logged-out TikTok answer for a video names the creator's pin: the field is null rather than a guessed false.

Why does play_url not open in my browser?

TikTok's video link works only with the cookies of the session that read the page, and it expires in hours. Turn on downloadVideos to get the MP4 stored with a link that does not expire.

Can I get the transcript or the comments?

The row carries the links to TikTok's own subtitle tracks (subtitles). The full transcript, with AI speech-to-text where a video has no subtitles, is tiktok-transcript-scraper's job; the comments are a different Actor's.

Integration

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('hyperbach/tiktok-video-scraper').call({"videoUrls": ["https://www.tiktok.com/@olympics/video/7210447318028455173", "https://www.tiktok.com/@olympics/video/7208589533632269574", "https://www.tiktok.com/t/ZTyMpW4m5/"]});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Python

from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('hyperbach/tiktok-video-scraper').call(run_input={'videoUrls': ['https://www.tiktok.com/@olympics/video/7210447318028455173', 'https://www.tiktok.com/@olympics/video/7208589533632269574', 'https://www.tiktok.com/t/ZTyMpW4m5/']})
items = client.dataset(run['defaultDatasetId']).list_items().items

CLI

$apify call hyperbach/tiktok-video-scraper --input '{"videoUrls": ["https://www.tiktok.com/@olympics/video/7210447318028455173", "https://www.tiktok.com/@olympics/video/7208589533632269574", "https://www.tiktok.com/t/ZTyMpW4m5/"]}'

REST

curl -X POST "https://api.apify.com/v2/acts/hyperbach~tiktok-video-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' -d '{"videoUrls": ["https://www.tiktok.com/@olympics/video/7210447318028455173", "https://www.tiktok.com/@olympics/video/7208589533632269574", "https://www.tiktok.com/t/ZTyMpW4m5/"]}'

AI agents and MCP

Apify's MCP server offers this Actor as a tool to Claude, Cursor, VS Code and any other MCP client. Connect https://mcp.apify.com?tools=hyperbach/tiktok-video-scraper and ask, for example: "Get the stats of the TikTok videos 7210447318028455173 and 7208589533632269574 by olympics". The agent fills the input from the table above and reads the rows from the run's dataset. The input names are the ones in the table above. An agent or a person can add feedback to any run and say what was needed and not delivered: a missing field, a wrong or empty result, the Actor switched from or to, and why. The run returns the same rows at the same price, and a person reads every note.

n8n, Make and Zapier

The Apify node in n8n, the Apify app in Make and the Apify integration in Zapier run this Actor on a schedule or from a trigger and read its dataset. A webhook on the run's end (Integrations on the Actor page) sends the rows on to your own endpoint. Nothing to install on our side.

Support

Disagree with a charge? Write to apify@hyperbach.com with the run ID. We will ask Apify to compensate you, and the charge comes back to your Apify account as platform credit.

Did it do the job? A short review on the Store, at any rating, helps the next buyer choose.

See also

  • TikTok Followers Scraper — the followers and following lists of any TikTok account, with the exact follower count of every account listed.
  • TikTok Creative Center Scraper — TikTok's top ads by country and period with CTR and retention curves, plus trending hashtags and videos.
  • TikTok User Search Scraper — the TikTok creators a keyword finds, in TikTok's own order, with exact counts and the e-mails and links in their bios.
  • TikTok Profile Scraper — TikTok profiles with the exact follower, like and video counts, the created date and the business category.
  • TikTok Ads Library Scraper — every ad an advertiser runs in TikTok's Ad Library, with targeting, reach per country, payer and landing page.
  • TikTok Transcript Scraper — the spoken words of TikTok videos, by video link or creator: TikTok's own captions first, speech-to-text where there are none.

This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.