Back to Blog
General

World Cup Ad Spy: What Brands Are Running on TikTok During the Tournament

June 25, 2026
11 min read
S
By SociaVault Team
world cupsocial media datatiktok adsad spycompetitor research

World Cup Ad Spy: What Brands Are Running on TikTok During the Tournament

TL;DR: During the World Cup, brands flood TikTok with match-timed creatives, and the good ones get refreshed every few days. The TikTok Ad Library API lets you pull what your competitors and the official sponsors are actually running, ranked by performance, without paying for a heavyweight ad-spy subscription. This guide shows you how to set up daily monitoring with working code in JavaScript and Python.

It is the 78th minute. A favorite just went down a goal, the internet is melting, and within about twenty minutes three different brands have a fresh TikTok ad live that references the moment without ever naming the tournament. By the next morning, two of those creatives are gone and a new variation is running. That churn is the whole game during a World Cup, and if you are only checking the For You page on your phone, you are seeing maybe one percent of what is actually live.

A global tournament compresses a year of advertising into about a month. Media budgets spike, creative teams ship daily, and the cost of guessing wrong gets expensive fast. The brands that win the attention war are not necessarily the ones spending the most. They are the ones who can see what is working right now and react before the moment passes.

This post is about building that visibility for yourself. We will use the TikTok Ad Library to monitor competitor and sponsor activity, rank ads by real performance signals, and set up a daily routine that surfaces new creatives as they go live.

Why the World Cup Breaks Normal Ad Monitoring

Outside of a tournament, a quarterly competitor review is usually fine. Ad creatives turn over slowly, budgets are steady, and you can spot a new campaign with a weekly glance.

The World Cup throws that rhythm out completely. Here is what changes:

  • Creative velocity explodes. Brands ship new variations around individual matches, results, and viral moments. A creative that was live this morning may be retired by tonight.
  • Spend concentrates into windows. The hours around kickoff and the full-time whistle see the heaviest pushes. Miss the window and you miss the data.
  • Non-sponsors crash the party. Brands with zero official rights run "football-adjacent" creatives to ride the attention. (We cover that ambush-marketing angle in depth in our ambush marketing tracking guide.)
  • Regional splits matter more. The same brand often runs completely different creatives in Brazil, the UK, Mexico, and Japan. A single-region view is misleading.

Manual browsing cannot keep up with any of that. You need a way to pull the data on a schedule and diff it against yesterday.

Why the TikTok Ad Library Beats a Generic Spy Tool Here

Plenty of ad-spy platforms exist, and they have their place. But for a fast-moving event, the TikTok Ad Library has three advantages that matter:

  1. Performance ranking is built in. You can order results by impressions, CTR, conversion rate, or likes, so you are not just seeing that an ad exists, you are seeing how it ranks.
  2. It is closer to the source. Less lag means you catch creatives while they are still live rather than weeks after they peaked.
  3. The detail view is rich. Individual ad pages include the creative, the destination, and engagement signals you can use to reverse-engineer what is working.

The catch with the native Creative Center is that it is a manual browsing surface. You cannot schedule it, diff it, or pull it into a spreadsheet. That is exactly the gap the API fills.

You can read the full parameter reference in the TikTok Ad Library docs. The endpoints we lean on are /v1/scrape/tiktok-ad-library/search and /v1/scrape/tiktok-ad-library/ad. Most requests cost one credit.

Step 1: Pull the Top Creatives in Your Category

Let's say you work for a beverage brand and you want to see the highest-impression ads in your space over the last week across the US. Order by impressions to surface the heaviest hitters.

// Node 18+ (built-in fetch) — top beverage ads by impressions, last 7 days
const params = new URLSearchParams({
  industry: "food_beverage",
  region: "US",
  period: "7",
  order_by: "impression",
  limit: "50",
});

const res = await fetch(
  `https://api.sociavault.com/v1/scrape/tiktok-ad-library/search?${params}`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } },
);

const { data } = await res.json();
console.log(`Pulled ${data.ads.length} top food and beverage ads`);
data.ads.slice(0, 10).forEach((ad, i) => {
  console.log(`${i + 1}. ${ad.ad_title}${ad.brand_name}`);
});

Here is the same call in Python:

import requests

params = {
    "industry": "food_beverage",
    "region": "US",
    "period": "7",
    "order_by": "impression",
    "limit": "50",
}

res = requests.get(
    "https://api.sociavault.com/v1/scrape/tiktok-ad-library/search",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params=params,
)

data = res.json()["data"]
print(f"Pulled {len(data['ads'])} top food and beverage ads")
for i, ad in enumerate(data["ads"][:10], start=1):
    print(f"{i}. {ad['ad_title']}{ad['brand_name']}")

Each ad in the response typically includes the creative text, a thumbnail, video download URLs, the brand name, the ranking metric you sorted on, and an objective classification. That alone tells you who is spending into your category right now.

Step 2: Track Specific Competitors and Sponsors

Category-level pulls are great for the landscape view, but during the tournament you usually have a watchlist: the official sponsors, plus your two or three closest rivals. Use the query parameter to search by brand name or by football-adjacent terms, and loop your watchlist.

const watchlist = ["nike", "adidas", "coca cola", "visa", "budweiser"];

async function pullBrandAds(query) {
  const params = new URLSearchParams({
    query,
    region: "US",
    period: "7",
    order_by: "impression",
    limit: "30",
  });
  const res = await fetch(
    `https://api.sociavault.com/v1/scrape/tiktok-ad-library/search?${params}`,
    { headers: { "X-API-Key": "YOUR_API_KEY" } },
  );
  const { data } = await res.json();
  return data.ads;
}

const results = {};
for (const brand of watchlist) {
  results[brand] = await pullBrandAds(brand);
  console.log(`${brand}: ${results[brand].length} live ads`);
}
import requests

watchlist = ["nike", "adidas", "coca cola", "visa", "budweiser"]

def pull_brand_ads(query):
    params = {
        "query": query,
        "region": "US",
        "period": "7",
        "order_by": "impression",
        "limit": "30",
    }
    res = requests.get(
        "https://api.sociavault.com/v1/scrape/tiktok-ad-library/search",
        headers={"X-API-Key": "YOUR_API_KEY"},
        params=params,
    )
    return res.json()["data"]["ads"]

results = {}
for brand in watchlist:
    results[brand] = pull_brand_ads(brand)
    print(f"{brand}: {len(results[brand])} live ads")

Run this every morning and you have a daily census of what each brand on your list is putting weight behind.

Step 3: Catch Regional Splits

The same sponsor almost never runs the same creative everywhere. Loop over a set of regions for a single brand to see how the message changes by market. This is where you learn that the Brazil creative leans on joy and the UK creative leans on dry humor.

const regions = ["US", "BR", "GB", "MX", "JP"];
const brand = "adidas";

for (const region of regions) {
  const params = new URLSearchParams({
    query: brand,
    region,
    period: "7",
    order_by: "ctr",
    limit: "20",
  });
  const res = await fetch(
    `https://api.sociavault.com/v1/scrape/tiktok-ad-library/search?${params}`,
    { headers: { "X-API-Key": "YOUR_API_KEY" } },
  );
  const { data } = await res.json();
  const topHook = data.ads[0]?.ad_title ?? "no ads found";
  console.log(`${region}: top hook by CTR — "${topHook}"`);
}
import requests

regions = ["US", "BR", "GB", "MX", "JP"]
brand = "adidas"

for region in regions:
    params = {
        "query": brand,
        "region": region,
        "period": "7",
        "order_by": "ctr",
        "limit": "20",
    }
    res = requests.get(
        "https://api.sociavault.com/v1/scrape/tiktok-ad-library/search",
        headers={"X-API-Key": "YOUR_API_KEY"},
        params=params,
    )
    ads = res.json()["data"]["ads"]
    top_hook = ads[0]["ad_title"] if ads else "no ads found"
    print(f'{region}: top hook by CTR — "{top_hook}"')

Step 4: Reverse-Engineer the Winners

When you spot an ad punching above its weight, pull the full detail record to study it properly. Use the /v1/scrape/tiktok-ad-library/ad endpoint with the ad's URL or ID.

const res = await fetch(
  "https://api.sociavault.com/v1/scrape/tiktok-ad-library/ad?" +
    new URLSearchParams({
      url: "https://library.tiktok.com/ads/detail/?ad_id=7700000000000000000",
    }),
  { headers: { "X-API-Key": "YOUR_API_KEY" } },
);

const { data } = await res.json();
console.log("Destination:", data.landing_page_url);
console.log("Objective:", data.objective);
console.log("Video URL:", data.video_url);
import requests

res = requests.get(
    "https://api.sociavault.com/v1/scrape/tiktok-ad-library/ad",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"url": "https://library.tiktok.com/ads/detail/?ad_id=7700000000000000000"},
)

data = res.json()["data"]
print("Destination:", data["landing_page_url"])
print("Objective:", data["objective"])
print("Video URL:", data["video_url"])

From the detail record you can see where the ad sends traffic, what objective it is optimized for, and download the creative to study the hook. During a tournament, the first three seconds carry everything. Pull ten winners, watch their opening frames back to back, and the pattern usually jumps out: a goal reaction, a crowd shot, a split-second product flash before the action resumes.

Step 5: Diff Against Yesterday to Catch What's New

The real payoff is detecting change. Store today's ad IDs per brand, then compare against the previous run so you only get alerted on genuinely new creatives.

import fs from "node:fs/promises";

async function detectNewAds(brand, todaysAds) {
  const file = `./snapshots/${brand}.json`;
  let previousIds = [];
  try {
    previousIds = JSON.parse(await fs.readFile(file, "utf8"));
  } catch {
    // first run, no snapshot yet
  }

  const todaysIds = todaysAds.map((ad) => ad.ad_id);
  const freshAds = todaysAds.filter((ad) => !previousIds.includes(ad.ad_id));

  await fs.writeFile(file, JSON.stringify(todaysIds));
  return freshAds;
}

const fresh = await detectNewAds("nike", results["nike"]);
console.log(`${fresh.length} brand-new Nike creatives since yesterday`);
import json
import os

def detect_new_ads(brand, todays_ads):
    path = f"./snapshots/{brand}.json"
    previous_ids = []
    if os.path.exists(path):
        with open(path) as f:
            previous_ids = json.load(f)

    todays_ids = [ad["ad_id"] for ad in todays_ads]
    fresh = [ad for ad in todays_ads if ad["ad_id"] not in previous_ids]

    os.makedirs("./snapshots", exist_ok=True)
    with open(path, "w") as f:
        json.dump(todays_ids, f)
    return fresh

fresh = detect_new_ads("nike", results["nike"])
print(f"{len(fresh)} brand-new Nike creatives since yesterday")

Wire that into a morning cron job and a Slack webhook and you have a competitor radar that pings you the moment a rival ships something new. We walk through the alerting side of this in our Slack competitor ad alerts guide.

Being Honest About the Limits

A few things worth saying plainly so you set expectations correctly:

  • The library is not exhaustive. Ad transparency surfaces a large slice of paid activity, but it does not guarantee every single creative for every advertiser. Treat it as a strong sample, not a complete census.
  • Ranking metrics are relative, not exact spend. Ordering by impressions tells you what is heavy, but it is not a dollar figure. Do not present it as confirmed budget.
  • Creatives disappear. Because brands rotate fast during the tournament, an ad you saw yesterday may already be gone. Snapshot and download anything you want to keep.
  • Regional coverage varies. Some markets have deeper data than others. Cross-check thin regions against organic signals before drawing conclusions.

None of this undercuts the value. It just means you treat the data as a sharp directional signal rather than gospel.

A Practical Daily Routine

Here is a workflow that takes about ten minutes a morning once it is scripted:

  1. Pull the top 50 ads in your category by impressions, US plus your two priority regions.
  2. Loop your brand watchlist and diff against yesterday's snapshot.
  3. Open the detail view on any new creative that ranks well and download it.
  4. Watch the first three seconds of the day's winners back to back.
  5. Drop the standouts and your read on them into a shared channel before the team's morning standup.

Do that for the length of the tournament and you will end up with a creative swipe file that is more current than anything a monthly subscription would hand you, plus a real feel for how the attention is moving day to day.

Where to Go Next

Once you can see what is running, the natural next questions are who is winning attention without paying for it, and how fans actually feel about all these campaigns. Those are exactly the threads we pick up in the sibling posts:

Ready to build your own ad radar? Start free with SociaVault and you get 50 credits to run your first competitor sweep today. The full endpoint reference lives in the docs, and the TikTok Ad Library specifics are in the search reference.

The tournament only happens once every four years. The brands that treat the next month like a daily intelligence operation are the ones whose creatives people will still be talking about when it is over.

Found this helpful?

Share it with others who might benefit

Ready to Try SociaVault?

Start extracting social media data with our powerful API. No credit card required.