Apify + Google Sheets: TikTok ads log stays clean
Checking the TikTok Ads Library “real quick” turns into a daily rabbit hole. Then you still have to copy links, names, and screenshots into a spreadsheet, and you’re never fully sure you didn’t log the same ad twice.
This TikTok ads log automation hits performance marketers first, but agency owners and growth-focused operators feel it too. The outcome is simple: a clean, always-updated Google Sheet that only adds truly new creatives, plus a short Slack or Telegram ping when something changes.
Below you’ll see exactly how this n8n workflow watches the library via Apify, de-dupes by adId, updates your log, and keeps notifications quiet unless there’s something worth looking at.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Apify + Google Sheets: TikTok ads log stays clean
flowchart LR
subgraph sg0["Schedule Flow"]
direction LR
n0@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set Parameters", pos: "b", h: 48 }
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Convert Dates to Unix"]
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Build Apify Body"]
n3["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Prepare Data for Sheets"]
n4@{ icon: "mdi:database", form: "rounded", label: "Read existing IDs", pos: "b", h: 48 }
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Collect ID list"]
n6["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Attach existing ids"]
n7["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Filter new creatives"]
n8["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Count new ads"]
n9@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Any new ads?", pos: "b", h: 48 }
n10@{ icon: "mdi:database", form: "rounded", label: "Append or update row in sheet", pos: "b", h: 48 }
n11["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/slack.svg' width='40' height='40' /></div><br/>Send a message"]
n12["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Send a text message"]
n13@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Get TT Ads through Apify", pos: "b", h: 48 }
n14@{ icon: "mdi:play-circle", form: "rounded", label: "Schedule Trigger", pos: "b", h: 48 }
n9 --> n12
n9 --> n11
n8 --> n9
n0 --> n1
n5 --> n6
n2 --> n13
n14 --> n0
n4 --> n5
n6 --> n7
n7 --> n10
n7 --> n8
n1 --> n2
n3 --> n4
n3 --> n6
n13 --> n3
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n14 trigger
class n9,n13 decision
class n4,n10 database
class n1,n2,n3,n5,n7,n8 code
classDef customIcon fill:none,stroke:none
class n1,n2,n3,n5,n6,n7,n8,n11,n12 customIcon
The Problem: Competitor ad tracking turns into messy busywork
Competitor monitoring sounds straightforward until you actually do it for a week. You search the TikTok Ads Library, open a bunch of creatives, copy details into a sheet, and promise yourself you’ll “clean it up later.” Later rarely comes. The log becomes inconsistent (different naming, missing fields, broken links), and duplicates sneak in because you’re working from memory. Worst part: you end up spending your best thinking time collecting data instead of learning from it.
The friction compounds. Here’s where it breaks down.
- You re-check ads you already saw because there’s no reliable “already logged” system.
- Manual copy-paste introduces little errors that ruin analysis later (wrong advertiser, missing IDs, mismatched dates).
- Your sheet grows, but it doesn’t stay usable, so nobody trusts it when it’s time to make decisions.
- Notifications become noise when you share updates, so the team stops paying attention.
The Solution: Scheduled scraping + de-duplication + clean logging
This workflow runs on a schedule and searches the TikTok Ads Library the same way you would, but without the manual clicking. n8n builds a request (country, date range, advertiser IDs, or keyword searches), then Apify scrapes the matching creatives and returns structured data. From there, the workflow formats each result for your spreadsheet, reads the existing adId values already logged, and filters out anything you’ve seen before. Only fresh creatives get written to Google Sheets, using adId as the “match” key so re-runs stay safe. Finally, if new ads exist, you get a short Slack or Telegram message with the count and a link to the sheet. If nothing changed, it stays silent.
The workflow starts with a Scheduled Automation Trigger and a simple “input options” node where you define what to track. Apify fetches and returns the ads, then n8n compares their IDs against your sheet before upserting rows and sending a lightweight notification.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you track 8 competitors and do a quick check each morning. If you spend about 10 minutes per competitor opening creatives and logging details, that’s roughly 80 minutes a day, plus the inevitable “did I already log this one?” backtracking. With this workflow, the daily routine becomes: set it once, let the scheduled run scrape and de-dupe, then glance at a Slack/Telegram message that says “6 new ads” and open the sheet when it’s worth it. The human time drops to maybe 5 minutes a day.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Apify to scrape TikTok Ads Library results
- Google Sheets to store your clean competitor log
- Slack or Telegram for “new ads found” notifications
- Apify API token (get it from Apify Console settings)
Skill level: Intermediate. You’ll connect accounts, paste an API token, and confirm your Sheet columns match the workflow mapping.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A scheduled run kicks things off. You choose a cadence (every morning is common), and the workflow pulls “yesterday to today” by default so you’re always scanning the newest window.
Your search parameters get cleaned up. n8n stores your inputs (country, keyword, advertiser business IDs, optional result limit), then converts dates into Unix timestamps so the request behaves the same way every time.
Apify retrieves the ad results, then n8n filters them. The workflow extracts key fields like adId, video URLs, cover image, advertiser details, and username. Next it reads the adId column from Google Sheets, merges that “existing ID list” into the current run, and keeps only ads that are truly new. It even prevents duplicates inside the same scrape batch.
Google Sheets gets an upsert, not a messy append. New creatives are appended or updated using adId as the matching column, and cover images can be displayed via an =IMAGE() formula so your log becomes browsable, not just “data storage.”
You can easily modify the search inputs (country, advertiser IDs, or keyword logic) to match how you monitor competitors. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Scheduled Automation Trigger
Set the schedule that starts the automation and feeds default inputs into the workflow.
- Open Scheduled Automation Trigger and configure the schedule rule that matches your monitoring cadence.
- Verify Scheduled Automation Trigger connects to Define Input Options as shown in the workflow connections.
Step 2: Define Input Parameters and Date Conversion
Provide the ad search filters and convert human-readable dates into Unix timestamps for the API request.
- In Define Input Options, set Ad target country to
all. - Set Ad published date From (DD/MM/YYYY) to
{{ $now.minus({ days: 1 }).toFormat('dd/MM/yyyy') }}and Ad published To (DD/MM/YYYY) to{{ $now.toFormat('dd/MM/yyyy') }}. - Update adv_biz_ids to your advertiser ID in the format
[YOUR_ID], and optionally fill Advertiser name or keyword or Ad limit. - Confirm Transform Dates to Unix follows Define Input Options to generate
start_time_unixandend_time_unix.
DD/MM/YYYY, Transform Dates to Unix will throw an error and stop the run.Step 3: Build and Run the Apify Request
Create the custom payload for the TikTok Ads actor and execute the Apify run.
- Open Assemble Apify Payload and keep the logic that builds the URL and JSON body for the actor request.
- In Retrieve TikTok Ads, set Operation to
Run actor and get datasetand map Custom Body to{{ $json.customBody }}. - Credential Required: Connect your apifyApi credentials in Retrieve TikTok Ads.
resultsLimit into the JSON body.Step 4: Prepare, De-duplicate, and Identify New Ads
Normalize the response, load existing IDs from Google Sheets, and filter only new creatives.
- Review Format Rows for Sheets to ensure
videoUrl,coverImageUrl, andtiktokUsernameare safely extracted for each ad. - Format Rows for Sheets outputs to both Load Existing IDs and Merge Prior IDs in parallel.
- In Load Existing IDs, set the Document ID to
[YOUR_ID]and Range toK:Kfor the existing adId column. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Load Existing IDs.
- Confirm Gather ID Catalog feeds into Merge Prior IDs, and then Filter Fresh Creatives removes any ads already found in Sheets.
Step 5: Write New Ads and Send Notifications
Insert or update new ads in Google Sheets and notify your channels if any were found.
- Filter Fresh Creatives outputs to both Upsert Sheet Rows and Tally New Ads in parallel.
- In Upsert Sheet Rows, confirm Operation is
appendOrUpdateand the column mappings use expressions like{{ $json.adId }}and{{ $json.coverImageUrl ? `=IMAGE("${$json.coverImageUrl}"; 1)` : '' }}. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Upsert Sheet Rows.
- Tally New Ads feeds into Check New Ads with a numeric condition
{{ $json.newCount }} > 0. - Check New Ads outputs to both Send Telegram Update and Post Slack Update in parallel.
- Credential Required: Connect your telegramApi credentials in Send Telegram Update and set Chat ID to
[YOUR_ID]. - Credential Required: Connect your Slack credentials in Post Slack Update and select the target Channel.
- Keep the message content in both notification nodes as
Hello! {{$json.newCount}} TikTok ads were found today. Review the list in your spreadsheet..
Step 6: Test and Activate Your Workflow
Run a manual test to validate the flow, then enable the schedule for production.
- Click Execute Workflow to run the full flow from Scheduled Automation Trigger onward.
- Confirm new rows appear in Google Sheets through Upsert Sheet Rows, and that Tally New Ads outputs a
newCountvalue. - If
newCountis greater than zero, verify both Send Telegram Update and Post Slack Update deliver messages in parallel. - Once verified, toggle the workflow to Active to allow Scheduled Automation Trigger to run on its schedule.
Common Gotchas
- Apify credentials can expire or the actor can require the right access. If things break, check your Apify token and actor permissions in the Apify Console first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Google Sheets upsert depends on your matching column. If adId isn’t in the expected column/range (or the sheet header changed), duplicates will slip in even though the workflow “ran successfully.”
Frequently Asked Questions
About 30–60 minutes if your Apify, Google Sheets, and Slack/Telegram accounts are ready.
No. You will mostly connect accounts and paste an Apify token. The only “technical” part is making sure your Google Sheet has the expected columns.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in Apify usage costs for the TikTok Ads Scraper actor.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and it’s a common upgrade. You can turn the advertiser business IDs (adv_biz_ids) in the “Define Input Options” node into a list, then loop over it so each run checks multiple competitors. Another option is switching from advertiser IDs to keyword-based searches by changing the same input node, then letting the “Assemble Apify Payload” logic build the right URL. Most people also tweak the Slack/Telegram message to include the date range or advertiser label.
Usually it’s an expired or incorrect Apify API token in n8n. Regenerate the token in Apify, update the credential used by “Retrieve TikTok Ads,” and try a manual run. If it still fails, check that your Apify plan/actor access includes the TikTok Ads Scraper actor, and watch for rate limits if you’re scraping large result sets.
A lot, as long as your Apify run and your n8n plan can keep up.
Often, yes, because this is not a simple “if new row then send message” flow. You need safe reruns, de-duplication, and an upsert strategy based on adId, plus some light data shaping before writing to Sheets. n8n handles branching and code steps without turning every extra filter into another paid task. Zapier or Make can still work if you already live there, but you’ll likely spend more time fighting edge cases like duplicate handling. If you want help deciding, Talk to an automation expert and bring your exact volume and reporting needs.
You get a competitor log that stays trustworthy, even when you stop thinking about it. Set the schedule, keep the sheet link handy, and use the time you saved to actually make better creative decisions.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.