DEV Community

Cover image for Extracting TikTok Top Ads by CTR and Downloading 1080p MP4s
Crawler Bros
Crawler Bros

Posted on Fully Autonomous

Extracting TikTok Top Ads by CTR and Downloading 1080p MP4s

Performance marketing teams analyzing video ads on TikTok often hit a wall: the TikTok Creative Center surfaces top-performing ads in a visual browser leaderboard, but extracting that data systematically into a warehouse or machine learning pipeline requires continuous manual work.

Automating creative benchmarking requires raw video files across multiple resolutions, standardized performance metrics like click-through rate (ctr) and likes, and campaign metadata such as the underlying optimization goal. The TikTok Creative Center Top Ads Scraper queries TikTok's public Creative Center API directly to return structured ad records without requiring an active TikTok ads account or login cookies.

How the Scraper Structures Ad Creative Data

The actor extracts public leaderboard items from ads.tiktok.com/business/creativecenter and flattens the response into tabular rows. Each dataset item includes the following key fields:

  • adId: The unique identifier assigned by TikTok to the creative.
  • adTitle and brandName: The text headline and advertiser name.
  • ctr: The ad's recorded click-through rate as a float.
  • like: Total like count.
  • cost: A binary cost-tier indicator (0 or 1) supplied by TikTok's API.
  • videoUrls: A dictionary containing direct download links across up to five resolutions (360p, 480p, 540p, 720p, 1080p).
  • duration, videoWidth, and videoHeight: Technical video specifications.
  • observedCountry and observedPeriod: Run metadata documenting the query parameters used.

What this actor does not do is provide exact financial ad spend numbers or impression counts; the cost field is only a relative tier indicator (0 or 1) provided by TikTok, not a monetary currency figure.

Configuring Filters for Specific Ad Creatives

Instead of scraping every generic top ad, you can narrow runs using specific input parameters:

{
  "country": "US",
  "period": "30",
  "orderBy": "ctr",
  "objective": "campaign_objective_conversion",
  "maxItems": 50
}
Enter fullscreen mode Exit fullscreen mode

Ranking Criteria (orderBy)

TikTok orders ads based on three selectable strategies:

  1. for_you: Uses TikTok's blended recommendation score (default).
  2. ctr: Ranks purely by click-through rate, isolating high-engagement creatives.
  3. like: Ranks by raw total likes, surfacing viral creatives.

Time Windows (period)

The period parameter accepts "7", "30", or "180", matching the time aggregation windows supported by TikTok's Creative Center.

Campaign Objectives (objective)

Filtering by campaign objective allows pipelines to separate brand awareness plays from direct-response conversions. Supported keys include:

  • campaign_objective_conversion
  • campaign_objective_app_installs
  • campaign_objective_lead_generation
  • campaign_objective_product_sales
  • campaign_objective_traffic
  • campaign_objective_video_views
  • campaign_objective_reach

Industry Keys (industry)

To filter by a specific vertical, supply an industry key formatted as label_NNNNNNNNNNN (for example, label_14104000000). If you do not know the key for your vertical, run the actor once without an industry filter and inspect the industryKey values returned in the output dataset.

Building an Automated Ingestion Pipeline

You can trigger runs programmatically with Python to pull top-performing conversion ads and download the highest-resolution video assets.

import requests
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run_input = {
    "country": "US",
    "period": "30",
    "orderBy": "ctr",
    "objective": "campaign_objective_conversion",
    "maxItems": 20
}

# Start the actor and wait for it to finish
run = client.actor("crawlerbros/tiktok-top-ads-scraper").call(run_input=run_input)

# Fetch the dataset results
dataset_items = client.dataset(run["defaultDatasetId"]).list_items().items

for item in dataset_items:
    ad_id = item.get("adId")
    ctr = item.get("ctr")
    brand = item.get("brandName")
    video_urls = item.get("videoUrls", {})

    # Pick the best available resolution
    best_url = video_urls.get("1080p") or video_urls.get("720p") or video_urls.get("540p")

    print(f"Ad: {ad_id} | Brand: {brand} | CTR: {ctr}")

    if best_url:
        video_response = requests.get(best_url)
        with open(f"ad_{ad_id}.mp4", "wb") as f:
            f.write(video_response.content)
Enter fullscreen mode Exit fullscreen mode

Because the direct URLs in videoUrls are signed and expire over time, your downstream processing or storage scripts should download the media files immediately after the actor completes.

Understanding Event-Based Pricing

This actor uses a pay-per-event pricing model rather than subscription compute rates. Billing consists of two distinct event types:

  • Actor Start (apify-actor-start): $0.005 per GB of memory allocated to the run, charged once when the run initializes.
  • Result (apify-default-dataset-item): $0.005 per dataset item returned (with volume tiers: BRONZE at $0.00433, SILVER at $0.00367, and GOLD, PLATINUM, and DIAMOND at $0.003).

For example, running a 1 GB run that collects 50 top-performing ads costs $0.005 for the run start plus $0.25 for the 50 results (50 × $0.005), for a total cost of $0.255.

Step-by-Step Collection Workflow

  1. Navigate to the TikTok Creative Center Top Ads Scraper page.
  2. Define the target market by setting country to an ISO 2-letter code (e.g., US, GB, DE).
  3. Set period to "7", "30", or "180".
  4. Choose an orderBy mode (ctr, like, or for_you) and set maxItems to your batch target (up to 500).
  5. Run the actor and export or process the resulting dataset.

If you are monitoring multi-country regions, execute distinct runs per ISO code and aggregate the outputs using the included observedCountry field as the partition key.


If you want to reproduce this, the Actor is TikTok Creative Center Top Ads Scraper. Read its input schema before the first run -- most failed runs are a missing required field, not a block.

Top comments (0)