# Changelog of TikTok Transcript Scraper — TikTok Subtitles to Text, No Login (`steadyfetch/tiktok-profile-transcripts`) Actor

- **URL**: https://apify.com/steadyfetch/tiktok-profile-transcripts/changelog.md
- **Full Actor documentation**: https://apify.com/steadyfetch/tiktok-profile-transcripts.md

## Changelog

### 1.0.36 — 2026-10-21

- **A request to the API endpoint that charges more than one event now always sends every video that was paid for, and never a transcript that was not.** Once a request's videos are charged, a later charge that cannot be completed never stops them being sent. If the transcripts cannot be charged, the videos come back and each transcript is held back and not charged: its row says so with `transcriptStatus: not_sent` — ask again to get it. The request's summary now counts only the transcripts it actually sent.
- Nothing changes about runs, prices or charges.

### 1.0.35 — 2026-10-20

- **The actor now also answers as an API endpoint (Standby).** Send one TikTok creator to `https://steadyfetch--tiktok-profile-transcripts.apify.actor/?profile=natgeo` (GET or a JSON POST, with `maxVideos`, `includeTranscripts` and `sortBy`) and get their videos back in the same response — the same rows a run writes, with transcripts when you ask for them, plus the run's own receipt — with no run to start and no dataset to read. A request is charged with the same events and the same per-event prices as a run with the same settings, only for what it returns; if the charge for a request's videos cannot be completed, its videos are not sent and nothing is charged. One request collects at most 200 videos, or 25 with transcripts (30 and 10 on the Apify free plan), and it does not skip videos your account already has — for that, or for many creators at once, run the actor as usual. Runs, their input fields, their output columns and their prices are unchanged.

### 1.0.34 — 2026-10-16

- **A private account is now named as private, and a profile this actor cannot read no longer asks you to re-run.** When a creator's account was private, the run could not tell, delivered nothing, and its row said the videos could not be read on this run, that this was temporary, and to re-run — a re-run returned the same thing. The row now says the account is private (status `profile_private`). When TikTok answers for a profile but not with a list of videos this actor can read, the row now carries the new status `unsupported_shape`: it says a re-run returns the same answer and asks you to open the profile in a browser to check it shows public videos, and the run page says where to tell us if it does. A read that genuinely did not go through still says it is temporary and to run again. These rows are uncharged, as before. Nothing changes about the price, which rows are charged, the input fields or the other output columns.

### 1.0.33 — 2026-10-11

- **Clearer wording when a run stops at its limit.** The rows a run could not finish when it reached its limit carried an internal word as their status, and the run page counted them under that same word. Those rows now carry the status "limit_reached" and say "This run reached its limit", with the remaining videos fetched in a new run, and the run page counts them as "past this run's limit". Rows held when a run had to pause part-way carried another internal word; they now carry the same status "limit_reached", say "This run reached its limit" and that the remaining items can be fetched in a new run shortly, and the run page counts them as "held for this run". Two other row sentences, about a creator's page limit and a finished video list, are worded more plainly. Nothing changes about the price, which rows are charged, the input fields or the other output columns.

### 1.0.32 — 2026-10-09

- **A busy speech service no longer costs you transcripts.** When the speech service behind this actor asked a run to slow down, a video was given up after two short retries and delivered without its transcript, even with plenty of run time left. The run now waits as long as the service asks, holds its next transcript until then, and asks again; while it waits, the run log says so. Only when the wait cannot fit in the time the run has left does a video arrive without its transcript, with the words uncharged, on a row that says the speech service was at capacity for this run and where to get the words, and the status line says the same. Videos transcribed from TikTok's own captions never touch the speech service and are unaffected. The videos themselves, and every transcript delivered, are charged exactly as before.

### 1.0.31 — 2026-10-06

- **A scheduled run no longer reads a big creator's feed all the way back when nothing is new.** This actor reads up to its own page limit of one creator's feed in a run. When a run reached that limit and every video there was one your account already had, the next run on that creator read back to the same limit again, only to find the same videos. Now later runs read only what was posted since: they deliver and charge the new videos as before, then stop at the newest video your account already had. Each creator stopped this way gets one uncharged row saying when it was checked and when a run next reads to the page limit (at most a week after the last full read). Turning on "Include videos you already have", pointing "Skip videos in this dataset" at a dataset, or the popular order reads to the page limit as before. Nothing changes about the price, which rows are charged, the input fields or the output columns.

### 1.0.30 — 2026-10-03

- **A short run timeout no longer skips the first video when transcripts are on.** When a run's own Timeout setting was short, for example 58 seconds through the API, the run held back time for its report as if it had the whole "Max run seconds", so a run whose start and first page took more than about 8 seconds returned its video as an uncharged time-limit row with most of a minute still left. The time the run holds back is now sized to the time the run really has, so one video and its transcript are read and delivered in a run of about a minute. Runs of 80 seconds or more, and every run with transcripts off, hold back exactly what they did before.
- **The note about "Max run seconds" names the real limit.** When "Max run seconds" was outside this actor's range of 30 to 3,600 seconds and the run's Timeout setting was shorter than the value the run used instead, the uncharged note row said the run continued at that value. It now says the run timeout is what limits the run, and what to set it to.
- Nothing changes about the price, which rows are charged, the input fields or the output columns.

### 1.0.29 — 2026-09-29

- **A run that delivered videos now says what the next run costs.** When a run ends cleanly with videos delivered, the run page now adds one sentence: run it again or on a schedule, and a later run on the same creators charges only for videos you do not already have. The same fact now sits near the top of this page. It is left out when the run's token could not open or write the run memory, since that run cannot remember what it delivered, and on a crowded run page it gives way before anything about what this run delivered or charged. Nothing changes about what is delivered, which rows are charged, the price, the input fields or the output columns.

### 1.0.28 — 2026-09-28

- **On the Apify free plan, this actor now has a daily allowance.** One account on the free plan reads a creator's feed at most 10 times in any 24 hours (one read is a page of about ten videos), which covers about 100 videos: a run of the default 30 videos from one creator three times over, or three creators at the default in one run. All free plan accounts together also share a daily allowance on this actor, which resets at midnight UTC. When a run reaches either, it stops cleanly: nothing past that point is read, transcribed or charged, and every creator it did not finish gets an uncharged row that says which allowance it reached, the time it resets in UTC, and that paid Apify plans carry no daily allowance. The run page says the same. Runs on a paid Apify plan are unchanged: no daily allowance, same rows, same charges. Nothing changes about the price, the input fields or the output columns.

### 1.0.27 — 2026-09-26

- **A paid run's check no longer holds a run on the Apify free plan in the same hour, and the transcript-limit row tells the truth.** On the Apify free plan a creator is read at most once an hour; that hour now starts only from a check made by a run on the Apify free plan. A video whose transcript was not attempted because this run reached its own budget for this run now says a later run will not transcribe it again (it is a video you already have) and suggests asking for fewer videos per run — it no longer suggests a re-run for the transcripts. The run also now notes its own start in its internal record, so a run cut off before it finishes (a hard abort, a crash or a timeout) is still accounted for on our side. Nothing changes about what is delivered, which rows are charged, the price, the input fields or the output columns.

All notable changes to this actor are documented here. Each entry matches one build on the Builds tab.

### 1.0.26 — 2026-09-26

- **A large run on a paid plan now reads through to the end of its ask, and a run that does stop on this actor's own data limit now says what is true.** A paid-plan run that asked for thousands of videos at once, for example 600 videos from each of five creators, could stop part-way on a fixed data limit of this actor's own, and its rows said the actor had reached a monthly limit that resets at the start of the month. That was wrong: the limit was for that one run, and a re-run collects the rest straight away. That limit now grows with the size of a paid ask, so such a run reads everything it was asked for. When a run does stop on it, its rows and status line now say to start it again for the rest, and that videos you already have are not charged again. Videos that were not delivered are still not charged. No price, charged event, input field or output column changed.

### 1.0.25 — 2026-09-25

- **A run that stops because the rest of your ask is too small to pay for reading another page of a creator's feed now says that this limit is the actor's own.** It used to say "your maximum cost per run was reached", even when your maximum cost per run was nowhere near spent. The row now says it is this actor's own limit and not your maximum cost per run, the run page and the summary row name it as this actor's own limit, and all three say that asking for more videos in one run lets it read further. The videos it did not reach are still uncharged. No price, charged event, input field or output column changed.

### 1.0.24 — 2026-09-24

- **A short run with transcripts on now uses its whole clock.** Until this build a run with "Include transcripts" on stopped taking new videos once 90 seconds were left, however quickly its videos were actually being transcribed — so a run with a 3-minute timeout stopped at about its halfway mark, and a run of 90 seconds or less transcribed nothing. The run now keeps back what its own videos have actually been taking (with a safe minimum, and more for a long video), so it keeps collecting while another video and its transcript still fit. When the time left truly cannot fit another video, the rows it could not reach and the run's status line now name the run time that would have fit the whole ask, for example "set the run timeout and "Max run seconds" to at least 3 minutes (180 seconds)". Videos that were not reached are still uncharged. A run with plenty of time behaves exactly as before, and no price, charged event, input field or output column changed.
- **A creator cut short on the last page of their feed now names the limit that cut them.** If the run's time limit or your maximum cost per run stopped the run part-way through a creator's final page, the row for the videos left said TikTok had no more videos to list. It now says the run stopped at that limit, and those videos are counted as skipped at it, uncharged as before.

### 1.0.23 — 2026-09-24

- **Settings sent wrapped in an extra "input" object are now read.** A run whose input arrives as `{"input": {…}}` — for example from `run_input={"input": {...}}` in the Python client — now reads those settings (creators, profile links and every option) as if sent directly and adds one uncharged note row naming them. Before, the run stopped with a guidance row and collected nothing. A setting you also filled at the top level keeps your top-level value. Nothing changes about the price, the input fields or the output columns.

### 1.0.22 — 2026-09-24

- **On the Apify free plan, a run that was cut short no longer counts as the creator's hourly check.** Until this build any run that read a creator's feed started that creator's hour — even one its time limit, your maximum cost per run or your result limit stopped part-way, or one TikTok stopped answering on. Its row asked you to re-run for the rest, and a re-run inside the hour then read nothing and said the creator had been checked with nothing new. Now only a run that read the feed to its own end counts as the check — the feed running out, videos your account already has, or this actor's own page bound — so the re-run a cut-short row asks for reads on and collects the rest. A run on a paid plan reads the feed every time, exactly as before. Nothing changes about which videos or transcripts are charged, the price, the input fields or the output columns.

### 1.0.21 — 2026-09-24

- **A run that Apify restarts after it has already delivered keeps its own record of that delivery.** If the restarted part of a run delivers nothing new, the run's internal record now keeps what the earlier part delivered and charged, with a note of the restart, instead of being rewritten as if nothing had been delivered; one line in the run log says so. Nothing changes about what is delivered, which rows are charged, the price, the input fields or the output columns.

### 1.0.20 — 2026-09-23

- **A run billed at the Apify free plan column no longer pages through a creator's whole back catalogue to learn that nothing is new.** When your account already holds at least as many of a creator's videos as you asked for, two feed pages running of videos you already have now end that creator's walk, and an uncharged row says so. An ask larger than what your account holds still walks on to the older videos you do not have, and a run on any paid plan keeps paging on to the next videos you do not have yet, exactly as before. No price, input field, output column or charged event changed.
- **A re-run over a creator this actor has already read to the end now stops at the newest video it saw last time.** Everything behind that video was read already, so a re-run with nothing new posted reads one page instead of the whole feed, and one with new videos delivers them and stops there; the uncharged row says when the creator was last checked. On the Apify free plan column, one creator's feed is now read at most once an hour for your account: a run inside that hour reads nothing for that creator, and its uncharged row says when it was checked and when a fresh check is due. The stop at the newest video is never used with "Include videos you already have", the popular order or a skip-dataset. No price, input field, output column or charged event changed.

### 1.0.19 — 2026-09-22

- **The run log no longer prints an internal usage summary at the end of a run, and a failed internal bookkeeping write no longer prints where it was being saved.** Nothing changes about what is delivered, which rows are charged, the price, the input fields or the output columns.

### 1.0.18 — 2026-09-22

- **The run log no longer prints internal cost lines, and the row a run writes when this actor's own monthly collection allowance runs out no longer quotes a dollar figure.** That row still says why the run stopped and that the allowance resets at the start of each month. No price, input field, output column or charged event changed. A transcript that fails no longer passes on the speech service's own error message and links either; the row says so in plain words.

### 1.0.17 — 2026-09-21

- **The run page now tells you which column of the price table billed you, and what the same run costs on a paid Apify plan.** The price table has always been on this page in full, but the run itself said nothing about it — so a run billed at the Apify free plan column looked exactly like one billed at a third of it. A run on that column now ends with a sentence naming what it cost you per 1,000 videos and per 1,000 transcripts, and what the identical run costs on Bronze, Silver and Gold. It is the plan you hold with Apify, not a setting of this actor: nothing about what is collected, delivered or charged changes, and a run on any paid plan reads word for word as it did before. On a crowded run page — one already carrying your next step, a cap that stopped the run, and the repeat-check warnings — this sentence shortens and then gives way first, because it is the only one whose whole text is already published here. The store page also now names the Bronze and Silver columns beside Gold, instead of saying "the cheapest paid tier" for a price only Gold and above pay. No price, input field, output column or charged event changed.

### 1.0.16 — 2026-09-20

- **The `videoUrl` and `coverUrl` links in your rows now come from TikTok's own delivery network, or they come empty.** Before transcribing anything, this run has always refused to download a video from any host but TikTok's own — but the two link columns in your row were copied straight out of the feed's answer with no such check, so an answer naming some other host would have handed you, labelled "MP4 URL", a link the run itself would not follow. Both columns now read the same rule the download does: the first link on TikTok's own network, and nothing at all where there is none. Measured against every video on the two real profiles this was built from, the link you get is the link you always got — the check costs your rows nothing. No price, input field, column or charged event changed.

### 1.0.15 — 2026-09-19

- **The whole "Maximum cost per run" you set is now spent on videos; before this build the run held back about a twelfth of it.** Your cap pays for videos and nothing else — the compute, the proxy and the data behind the run are ours, not yours — but the run was still reserving roughly 8% of your cap against those costs before it planned a single video. So a cap worth ten videos bought nine, and the tenth was money you had authorised and could not spend. That reserve is gone. A run at its cap still ends the same honest way it always did: it stops itself, tells you what it cut and why, and charges you for nothing it did not deliver. No price, input field, output column or charged event changed.

### 1.0.14 — 2026-09-19

- **A page that was billed but came back in a shape this actor cannot read is no longer bought a second time on your clock.** The run decides whether to wait and ask again by looking at what the answer cost it: one that cost nothing is weather that clears in seconds and is worth another try, while one that was already paid for comes back identical however many times it is bought. When such an answer carried no readable cost, the run treated it as one it had not paid for and spent up to fourteen seconds of your "Max run seconds" waiting before asking again for a page that could never be read. It now stops after the first one and gets on with the rest of your creators. What the row says and what it charges you are unchanged — that page was uncharged before and it is uncharged now.
- No price, input field, output column or charged event changed.

### 1.0.13 — 2026-09-18

- **"N videos you already had were skipped, not charged" now survives the run page's 500-character limit.** On this actor a repeat you are spared is the video, its transcript and its transcription minutes — the most expensive thing the status line can tell you — and it used to be dropped alongside the census on 348 of the 480 endings a run can have, one of them at 375 characters with 125 still spare, while the 90-character "open an issue" line stayed. That sentence now rides every rung beside the two repeat-check clauses, shortening to its count before it is ever dropped, and the support ask is what gives way first.

### 1.0.12 — 2026-09-16

- **The input form now says what turning transcripts on actually costs, and what it never costs.** The "Include transcripts" switch described what it adds to each row and left the price to the description at the top of the form — which is all an AI agent’s tool screen shows it, and that screen stops after the first 500 characters of a field. It now names the charge per transcript actually delivered, the per-minute surcharge past the first three minutes, and the cases that are never charged: a video with no speech, a photo post, and a video this account already has. The profile-links door gained a worked example and the same never-charged sentence. Nothing about what is collected or charged changes.

### 1.0.11 — 2026-09-15

- **"Max run seconds" now ends the run's reads, not just its decision to start one.** Every limit
  check happened *before* a read began; nothing stopped a read that was already running. So a page
  of videos, a caption file, a video download, the fallback page lookup or a speech call started
  just inside your limit could keep going well past it — the video feed alone was allowed three
  tries of twenty-five seconds each with waits in between, and a speech call three minutes, three
  times over. Now every one of them is given the smaller of its own timeout and the time your run
  actually has left, and is stopped at exactly that; a further try is never started when the wait
  before it no longer fits; and a read the clock cannot hold is not made at all. When your own limit
  is what ended the collecting, the row says so and points at "Max run seconds" — it no longer tells
  you to re-run for a limit you set. A run with time to spare behaves exactly as before.
- **A run that Apify moves to another machine mid-way no longer restarts your time limit.** The
  window is now measured from when the run began rather than from when the container came up, so a
  180-second limit is 180 seconds however many times the run is moved.
- No price, input field, output column or charged event changed.

### 1.0.10 — 2026-09-14

- **A media link that does not come from TikTok's own servers is now refused before it is fetched,
  instead of being downloaded, transcribed and charged.** Every link this actor opens for a
  transcript is written by the data feed it buys from, not by you: the video's playback renditions,
  TikTok's own caption file, the video page address handed to the fallback resolver, and the address
  that resolver prints back. Nothing checked where any of them pointed, so a wrong or tampered
  answer would have been downloaded from whatever host it named, sent to the speech service and
  billed to you as a transcript. All four are now checked against TikTok's own servers first, and a
  link that is not one is never opened: the video row is still delivered, the transcript is
  uncharged, and the row says the link was refused and names the host — it does not say the video
  has no audio, because those are two different things. The checks are independent, so a refused
  playback link on a real TikTok video page still gets the fallback resolver, and a refused caption
  file still falls through to speech: nothing that used to produce a transcript stops producing one.
  No price, input field, output column or charged event changed.

- **A run that collected nothing now tells you what to change, instead of only that it collected
  nothing.** A handle this actor could not read ended the run cleanly, so the run page said
  "Delivered 0 videos of 1 asked for across 0 profiles." and stopped there — 52 characters, no
  cause and no next step. Two things were wrong. The count of values it could not read was kept on
  the run's own record and never printed, so a run whose only fault was a mistyped handle named
  nothing at all. And nothing on the page said what to put there instead. The line now carries that
  count, in words rather than internal codes, and on a run that delivered nothing it adds one plain
  sentence for the biggest cause: the box to use and a working handle to copy, what a private or
  deactivated account means, what a creator TikTok lists no videos for means, and which of those a
  second run would change. An order the run could not use gets its own sentence naming the two that
  work, rather than advice about handles that were never the problem. A feed read that did not go
  through is still never reported as "this creator has no videos" — it does not know. A run that
  did deliver is unchanged. No price, input field, output column or charged event changed.

- **The page now opens with the name you clicked, the price, and a real video row.** The first line of the page called this actor something other than its store title, what a run costs was four screens down, and the page listed every column without ever showing one. The heading is now the store title, the opening paragraph carries the per-1,000 price on the cheapest paid tier and on the Apify free plan, and a real delivered row — the caption, hashtags, post date, duration, plays, likes, comments, shares, saves and the sound — sits above the column table, built by this actor's own parser from a harvested profile feed. No price, input field, output column or charged event changed.

### 1.0.9 — 2026-09-14

- **A run that cannot open the memory of what you already have now says so, instead of quietly
  charging for it again.** The promise on this page is that a video your account already has is
  never bought twice and never re-transcribed, and the memory that keeps it is a key-value store in
  your own Apify account. A run started with a scoped API token in restricted-access mode cannot
  open that store at all — so every video you already owned was collected, transcribed and charged a
  second time, and nothing on the run page, in the rows or on the receipt told you why. It now does:
  an uncharged note row at the top of the dataset, a clause on the run page and a line on the
  receipt all name the cause and the fix — give the token key-value store Read, Write and Create
  permission, or set Actor runs to Full access, under Settings → API & Integrations, or start the run
  from the console. Every other reason the memory can be unavailable keeps the words it had. Nothing
  else moved: no input field, output column, charged event or price changed.
- **And a token that can READ that memory but not WRITE it now says so too.** That one looked like a
  perfect run: every video you already had was still recognised and skipped, but nothing this run
  delivered could be written down — so your NEXT run bought, transcribed and charged all of it
  again, three charged events per video, with nothing anywhere to say why. The run now names it the
  moment the first write is refused, on the run page, on its own uncharged row, on the receipt and
  in the run log, and tells you the permission to add: key-value store Write (and Create) under
  Settings → API & Integrations, or Actor runs set to Full access. A run with a full token is
  unaffected, and nothing about what is charged changed.

### 1.0.8 — 2026-09-13

- **A field name this actor does not have is now named on the run page, and counted properly on the run's record.** A run carrying only a name this actor neither has on its form nor reads as an alternative spelling already got one uncharged row explaining it — but the run page said nothing about which name, and the videos that run had asked for were left counted by nothing, which made an input typo look on our own records like TikTok failing us. The run page now quotes the name you sent beside the field this actor reads, and the record names the whole thing correctly. A "TikTok handles" value this actor cannot read, and an "Order" it does not recognise, still report against those fields — those really are about them. Nothing about pricing, the form, the output columns or what gets charged changed.

### 1.0.7 — 2026-09-13

- **The field name you guessed now works.** Send a creator as `profile`, `username`, `usernames`,
  `handle`, `handles`, `creator`, `creators`, `profileUrl` or `profileUrls`, or a profile link as
  `url`, `urls` or `startUrl`, and the run reads them instead of collecting nothing: the values are
  used exactly as sent, a creator you name in both places is collected once, and one uncharged note
  names the field to use next time. Nothing about what is charged changes.

### 1.0.6 — 2026-09-13

- **Your result limit now holds even when Apify moves the run to another server part-way through.** This actor already picks up exactly where it left off after such a move, and it works out how much of your limit is left from the videos it has already delivered — but it was counting only the videos that carried a fee. A video your account already has comes back delivered and uncharged, and so does every video on a run that cannot be billed at all, so those were invisible to the count: the run believed more of your limit was unspent than really was, and could hand you more videos than you asked for. It now counts every video already delivered to you, whether or not it carried a fee. Nothing about what you are charged moves — a repeat is still delivered without a result fee, and only delivered videos and produced transcripts are charged.

### 1.0.5 — 2026-09-13

- **The input schema now speaks to an AI agent as well as to a person.** An agent that finds this actor through Apify's MCP server never opens this page — it reads the input schema. So the schema's own description now opens with the call that works, says what one video row and one transcript cost and what a 30-video run with transcripts comes to, lists what is never charged, and names the run option that caps the bill. The TikTok handles field leads with the value shape and an example, then what is never charged, with the console sample instruction last. No price, no charged event, no input field and no output column moved.

### 1.0.4 — 2026-09-12

- **An answer this actor already paid for is never bought twice, and a creator whose collection is cut short now says what it actually collected.** When the data feed replies in a shape this actor cannot read, waiting and asking again can never change it — the run did it anyway, spending part of its own upstream allowance and up to fourteen seconds of your run clock on the same dead reply. From this build only the refusals that cost nothing and clear in seconds are waited out: a rate limit, a server error, a dropped connection, exactly as before. And when a creator's collection really is cut short part-way, the row that reports it now tells you how many videos it collected, over how many pages, and how much of your ask is still missing — instead of saying the videos could not be read on a run that had already delivered and charged for most of them. Nothing about what you are charged moves: only delivered videos and produced transcripts are charged, the videos collected before a cut are still delivered, and everything that did not arrive carries no result fee.

### 1.0.3 — 2026-09-12

- **A brief "slow down" from the data feed no longer costs you the rest of the creator.** When the
  feed behind this actor answered with a rate limit, a server error or an unreadable reply part-way
  through a creator's videos, the run used to give up on that creator within a few seconds: you kept
  the videos collected up to that point and the rest of your result limit came back as something to
  re-run. From this build the run waits the refusal out, up to twice per creator, and asks for the
  same page again; a feed that clears carries on to your result limit, and only a feed that still
  refuses afterwards ends the walk. The waiting is bounded by your run clock — no wait is taken that
  the remaining time cannot fit — and it stops immediately at your maximum cost per run. A verdict
  about the account itself (not found, private, no videos) is never waited on, because waiting
  cannot change it.

- **A creator that really was cut short is unchanged:** the videos already collected are still
  delivered, and nothing that did not arrive carries a result fee.

- **A limit of ours is never published as a verdict about the creator.** A walk that ends at this actor's own per-creator page limit now says exactly that — how far it read, that the feed was still listing more, and that it is a limit on this run rather than an answer about the account. The platform-verdict wording is kept for the one ending that earns it: TikTok's own feed closing. And where the result limit went unfilled because the videos on those pages were ones your account already has, the row names the switch that would have filled it.

- **The run record names the same cause the row does.** A walk this actor's own per-creator page limit cut is recorded as its own clean stop rather than as "no videos" — the wording a buyer reads, the run page's count and the machine-readable outcome record now agree about which limit ended the walk, so a run you read through the API says the same thing as the row in front of you. Nothing about what is charged changes: those videos were never collected and are never billed.

- **Your rows carry the data and nothing about the fetch behind it.** An address fragment that could reach a row is now stripped in every shape.

### 1.0.2 — 2026-09-13

First release.

- **A TikTok creator's videos as rows.** Type a handle — or paste a profile link — and every video comes back with its caption, hashtags, the creator, when it was posted, its duration, play/like/comment/share/save counts, the sound it uses, the cover image and a playable MP4 link.
- **Transcripts bundled.** Switch on **Include transcripts** and every delivered video also carries `transcript`, `transcriptLanguage`, timestamped `transcriptSegments` and `transcriptSource` — which says whether the words came from TikTok's own captions or from speech-to-text.
- **The result limit is exact.** Set 30 and the run delivers 30, or the last row says why it could not.
- **An over-ask never refuses the run.** The input schema declares no `maximum` on any number and no `minimum` above 1, so a caller asking for 20,000 videos per creator — or a 5-second run clock — still starts a run: the actor's own ceiling binds (2,000 per creator, 20,000 rows, a 30-3,600 second clock) and one uncharged row says what was asked and what bound it. A schema ceiling is validated by the platform before a container boots, so it returns an error and no run at all — invisible to the buyer and to us.
- **Two feeds.** `sortBy: "latest"` walks the profile grid newest first; `sortBy: "popular"` walks TikTok's own most-played ordering for that creator, which is a different set of videos.
- Three charged events. `video`, from $1.00 per 1,000 videos, platform usage included; `transcript`, only on a video whose spoken words were actually produced; `long-video-surcharge`, one per started minute beyond the three minutes included in the transcript price. No start fee, and no second charge for "details".
- A video whose words could not be produced — no speech, no audio track, an expired media link, or a photo post with no video at all — is delivered as a normal row with an explicit null transcript and a reason, and the transcript event is not charged.
- **Your maximum cost per run is asked before each collection step, not after it.** The moment the cap can no longer cover another video, the run stops collecting — it never spends a step it cannot hand you a row for — and the videos it did not reach ship as one uncharged row naming the cap.
- Honest uncharged rows: an account that does not exist or is deactivated, a private account, an account TikTok lists no videos for, a feed read that did not go through, and each of the limits that can stop a run all say so in their own words, and none of them is billed.
- Repeat memory: videos already delivered to your account are skipped on a later run, not charged again, never re-transcribed, and their slot goes to the next new video — so a daily schedule on the same creators costs only what is new.
