# Changelog of TikTok Video Downloader API - No Watermark, Bulk MP4 URLs ✅ (`unseenuser/tiktok-no-watermark-url-extractor`) Actor

- **URL**: https://apify.com/unseenuser/tiktok-no-watermark-url-extractor/changelog.md
- **Full Actor documentation**: https://apify.com/unseenuser/tiktok-no-watermark-url-extractor.md

## Changelog

All notable changes to this Actor are recorded here. Dates are the date the change
was published to the Apify Store.

This Actor follows one rule above all others: **existing output keys are never
renamed, removed, or repurposed.** New data always arrives as new keys, appended
after the existing ones. If you read the dataset as JSON by key name, no release
below can break you. If you read exported CSV by *column position*, pin the
columns you need with the API's `fields` parameter rather than relying on order.

### \[0.2.0] - 2026-08-10

Output grows from 17 fields to 75. Everything added here comes from data the
Actor was already fetching, so no release below costs an extra request or
changes what a run is billed.

#### Fixed

- **`clean_url` was corrupted on every row.** A redaction pass intended for error
  messages was also being applied to successful rows, and its patterns matched
  the signature segments inside TikTok CDN URLs. Long path segments and the `rc=`
  and `l=` query parameters were being replaced with `[REDACTED]`, producing URLs
  the CDN rejected. Successful payloads now pass through untouched; redaction
  still applies to error text, where the risk actually was. **Any URL returned
  before this release was unusable. Re-run affected inputs.**

#### Added

- **`clean_url_fallbacks` and `clean_url_alt`.** TikTok publishes the same file on
  several CDN hosts, and the first one sometimes answers `403 Access Denied` on a
  direct fetch. `clean_url_fallbacks` lists every URL for the file;
  `clean_url_alt` surfaces the `api16-normal-*.tiktokv.us` entry, which is usually
  more permissive. You can now retry without re-running the Actor.
- **`video_variants`** - every rendition TikTok published, sorted highest bitrate
  first, each with resolution, fps, bitrate, file size and URL. Note that
  `clean_url` is not always the highest-resolution option: in a 10-video sample
  the top variant was 1080x1920 on every row while `clean_url` was 576x1024.
  Variants are an array inside the one row, never extra dataset rows, so this
  does not change what a run costs.
- **`origin_width` / `origin_height`** - the dimensions the creator uploaded, so
  you can tell whether the delivered file was downscaled.
- **`status` and `download_url`** - a single field to branch on, and an alias of
  `clean_url` under the name most download APIs use.
- **`audio_url` and `audio_url_fallbacks`** - a direct MP3 URL for the video's
  audio track, served as `mime_type=audio_mpeg`. A URL like every other field
  here; the Actor still downloads and hosts nothing. Populated on 10/10 videos in
  verification, all of which used original sound - videos on licensed commercial
  music may return `null`.
- **`post_type` and `image_urls`** - photo and slideshow posts previously produced
  a charged row with `status: "success"`, no media URL, and nothing explaining
  why, while the slide images sat unread in `image_post_info`. `post_type`
  distinguishes `"video"` from `"photo"`, and `image_urls` returns the slides in
  order, using the clean rendition rather than the watermarked copies TikTok also
  publishes.
- **47 further flat fields** promoted out of the nested objects: author (12),
  engagement (8), video and file size (10, besides the two above), covers (4),
  music (8), plus `hashtags`, `mentions`, `subtitles`, `subtitle_languages` and
  `has_auto_caption`. Hashtag extraction is unicode-aware, so non-Latin tags are
  returned correctly.

#### Changed

- **`author_following_count`, `author_heart_count` and `author_video_count` report
  `null` rather than `0` when TikTok does not report them.** TikTok's video-detail
  response returns these as `0` rather than omitting them, even for accounts where
  that cannot be true, and a real `0` is indistinguishable from "not reported".
  `author_follower_count` and every engagement count are unaffected and still pass
  through exactly as reported, `0` included.
- **Proxy region is now a dropdown** of 52 regions instead of a free-text field.
  Existing values are unaffected; `US` is still the default.
- **`pickCleanUrl` filters the URL list before choosing.** If the first entry of
  `download_no_watermark_addr` is malformed, the Actor now falls through to the
  next genuine no-watermark URL in the same address instead of dropping to
  `play_addr`.
- Actor title, description, keywords and Store categories updated. The Actor had
  been declaring a category constant the platform does not recognise, so it was
  absent from category browsing.
- The transcript input is now labelled "Include transcript". Behaviour and price
  are unchanged - transcripts remain free.

#### Known issues

- `content_type` is declared in the output schema but TikTok's video-detail
  response does not return it, so it is absent from every row.
- `has_watermark` can read `true` on rows whose `clean_url` came from
  `download_no_watermark_addr`. The flag appears to describe the underlying asset
  rather than the file at `clean_url`, but this is not yet confirmed. Treat
  `clean_url_source` as the authoritative answer to "where did this URL come
  from".

### \[0.1.0]

Initial release. One row per input URL: `clean_url`, `clean_url_source`,
`has_watermark`, `url_expires_estimate`, caption, timestamps, share URL, and the
full `statistics`, `author`, `music` and `video` objects, plus an optional WEBVTT
transcript. Typed `error_type` on failure rows, so a dead input URL still
produces a row rather than a gap.
