Apify Ads Intelligence
Published by hologrow in hologrow-ai-skills
What this skill does
Research, spy on, and analyze ads across Meta (Facebook & Instagram), Google (Ads Transparency Center + paid search results), TikTok (Ads Library + Creative Center), LinkedIn Ad Library, and X (Twitter — promoted tweets, best-effort) using Apify Actors. Use when user asks about competitor ads, ad library research, winning creatives, ad copy analysis, landing page audits from ads, cross-platform ad audits, brand transparency checks, or any task involving paid ad creatives, advertiser data, or ad
Add Apify Ads Intelligence to your agent
Review the source and files first. When you are ready, copy the prompt instruction or use the CLI command supported by your environment.
Install with a prompt
Paste this into a compatible coding agent:
add this skill "apify-ads-intelligence" from https://github.com/hologrow/hologrow-ai-skillsInstall with the CLI
Run this command in a controlled environment after reviewing the repository:
npx skills add https://github.com/hologrow/hologrow-ai-skills --skill apify-ads-intelligenceSkill instructions
Hologrow data context: When this workflow needs private commerce, advertising, or analytics data, use
hologrow-data-middlewarefirst. Work only from authorized connected sources, verify coverage and freshness, and state any data limitation before making a recommendation.
Ads Intelligence Cluster
Answer natural language questions about ads, ad libraries, and competitor advertising activity by routing to the right Apify Actor and delivering a synthesized answer.
Unshelling note: This skill was adapted from an Apify-CLI-based runtime. All local
apify ...CLI calls,APIFY_TOKENhandling,apify login, and local file exports have been removed. Actor calls now go through the platform-hosted MCP tools; authentication and billing are handled platform-side. Output is delivered as a Markdown answer plus a structured data block (no local CSV/JSON files written).
Note on platform coverage
- Meta, Google, TikTok, LinkedIn: real public ad libraries with rich data (creatives, targeting, dates, reach where disclosed).
- X (Twitter): no public ad library exists. Coverage is a best-effort workaround that scrapes a brand's tweets and flags items with non-empty
cardfield orsourcecontaining "Ads" as likely promoted. Always include the caveat in synthesis output.
Note on overlap with apify-ecommerce
That skill has an ads-intelligence intent that routes to apify/facebook-ads-scraper for shallow Meta-ad lookups. This skill is the deep dive across all five platforms. If you only need Meta ads as a side detail of an ecommerce question, stay in apify-ecommerce. If ads are the main task, use this skill.
Prerequisites
(No need to check it upfront)
- The Apify Actor tools are mounted on the platform. Authentication, token refresh, and billing are handled platform-side — this skill does not manage any credentials.
Workflow
Copy this checklist and track progress:
Task Progress:
- [ ] Step 1: Detect intent and select Actor(s)
- [ ] Step 2: Fetch Actor schema
- [ ] Step 3: Ask user preferences (output format, result count, country)
- [ ] Step 4: Run the Actor (or Actors in parallel for cross-platform-audit) and fetch results
- [ ] Step 5: Synthesize a direct answer (not a data dump)
Step 1: Detect Intent and Select Actor
Classify the user's message into an intent, then pick the right Actor.
Intent signals:
| Signals in user message | Intent |
|---|---|
| "what ads is X running", "competitor [brand] ads", "[brand] FB/Google/TikTok/LinkedIn/X/Twitter ads", "show ads from [page]", "promoted tweets from [brand]" | competitor-ads |
| "ads about [topic]", "find [keyword] ads", "ads for [vertical]", "fitness/fintech/saas ads" | keyword-ads |
| "trending ads", "winning ads", "top ads", "best performing", "long-running ads", "creative inspiration" | top-creatives |
| "where do these ads go", "landing pages from ads", "click destinations", "ad funnels" | landing-page-audit |
| "compare X's ads across platforms", "all ads from [brand]", "cross-platform ad audit" | cross-platform-audit |
If multiple intents detected, ask: "Do you want [intent A] or [intent B]?"
Actor routing — always try Primary first, switch to Fallback only if it fails or returns 0 results:
| Intent | Platform | Primary Actor | Fallback Actor |
|---|---|---|---|
competitor-ads | Meta (FB/IG) | apify/facebook-ads-scraper | brilliant_gum/facebook-ads-library-scraper |
competitor-ads | dz_omar/google-ads-scraper | solidcode/ads-transparency-scraper | |
competitor-ads | TikTok | brilliant_gum/tiktok-ads-library-scraper (source: library) | silva95gustavo/tiktok-ads-scraper |
competitor-ads | silva95gustavo/linkedin-ad-library-scraper | dz_omar/linkedin-ads-scraper | |
competitor-ads | X (workaround) | apidojo/twitter-scraper-lite (twitterHandles: [<brand>]) + heuristic filter | apidojo/tweet-scraper |
keyword-ads | Meta | brilliant_gum/facebook-ads-library-scraper | apify/facebook-ads-scraper |
keyword-ads | apify/google-search-scraper (focusOnPaidAds: true) | — | |
keyword-ads | TikTok | brilliant_gum/tiktok-ads-library-scraper | — |
keyword-ads | silva95gustavo/linkedin-ad-library-scraper | — | |
keyword-ads | X (workaround) | apidojo/twitter-scraper-lite (searchTerms: [<keyword>]) + heuristic filter | apidojo/tweet-scraper |
top-creatives | Meta | brilliant_gum/facebook-ads-library-scraper (rank by daysRunning) | — |
top-creatives | TikTok | burbn/tiktok-top-ads-spy (sort by CTR / impressions / likes) | brilliant_gum/tiktok-ads-library-scraper (source: creative_center) |
top-creatives | n/a — fall back to competitor-ads route, filter to active ads | — | |
top-creatives | n/a — fall back to competitor-ads route, rank by impressionsPerCountry reach | — | |
top-creatives | X | n/a in v1 — no reliable promoted-content signal across timelines | — |
landing-page-audit | Meta | brilliant_gum/facebook-ads-library-scraper (resolveSnapshotUrls: true) | — |
landing-page-audit | apify/google-search-scraper (focusOnPaidAds: true, directUrl) | dz_omar/google-ads-scraper (destinationUrl) | |
landing-page-audit | X | n/a in v1 — heuristics not reliable enough for landing-page extraction | — |
cross-platform-audit | All five | Run Meta + Google + TikTok + LinkedIn primaries in parallel; X workaround runs separately with caveat. Merge by advertiser. | — |
X (Twitter) heuristic filter — after scraping, flag a tweet as likely promoted if any of the following hold:
cardfield is non-empty (website cards / CTAs are commonly attached to promoted tweets)sourcefield contains "Ads" (e.g. "Twitter Ads")
Surface results with the explicit caveat: "X has no public ad library; results below are tweets from the brand's own timeline that match promoted-content heuristics. They will miss promoted-only ads that appear in other users' feeds."
Step 2: Fetch Actor Schema
Before running, fetch the Actor summary, input schema, and README via the platform Actor-info tool so you know the required and optional parameters. The input schema lives in .taggedBuilds.latest.build.inputSchema (an escaped JSON string). Pass the selected Actor ID (e.g., apify/facebook-ads-scraper) to the info tool.
What to read from the schema:
- Summary — title, description, pricing, stats.
- Input schema — required and optional parameters (especially the result-limit field name, which varies by Actor:
maxResults,resultsLimit,resultsPerQuery, etc.). - README — capabilities, examples, gotchas.
Step 3: Ask User Preferences
Before running, ask:
-
Output format:
- Quick answer (default) — synthesized answer in chat
- Full structured data — return the complete dataset as a structured data block in the answer
-
Result count — defaults by intent:
Intent Default count competitor-ads30 keyword-ads30 top-creatives20 landing-page-audit50 cross-platform-audit15 per platform -
Country — default
US. For TikTok library specifically, defaultDE(EU-only) and warn the user; for global TikTok usesource: creative_center. X routes are global by handle/keyword, no country parameter.
Cost awareness: Always set a sensible result limit in the Actor input (e.g., maxResults, resultsLimit, or the equivalent field per Actor schema). Do not batch-pull or auto-paginate. Run the same query only once by default. Warn the user before runs of 500+ ads and before continuing — apify/facebook-ads-scraper charges per ad and X primaries charge per tweet.
Step 4: Run the Actor and Fetch Results
Two steps: run the Actor (blocks until done), then fetch dataset items.
Run the Actor — call the platform Actor-run tool with the Actor ID and the JSON input you built. The run returns metadata; extract .id (run ID), .status (should be SUCCEEDED), and .defaultDatasetId for the next step.
Fetch results — call the platform dataset get-items tool with the defaultDatasetId:
- Quick answer: fetch dataset info (
itemCount,fields,consoleUrl) plus the top 5 items, and synthesize in chat. - Full structured data: fetch all items and return them as a structured data block in the answer.
Use the tool's limit / offset parameters server-side to keep cost and bandwidth down when paginating large datasets.
Discover real field names from one sample item before composing further analysis (Actor outputs vary): fetch a single item (limit: 1) and inspect its keys.
Cross-platform audit (parallel runs): For cross-platform-audit, kick off the Meta + Google + TikTok + LinkedIn primaries as separate Actor-run calls, then fetch each run's defaultDatasetId and its items per platform. The X workaround runs separately with its caveat. Merge results by advertiser.
X heuristic filter on fetched tweets: keep items where card is non-empty OR source contains "Ads":
keep item if (item.card != null and item.card != "") or (item.source != null and item.source contains "Ads")
Step 5: Analyze Results and Deliver Answer
Synthesize, don't dump. Patterns by intent:
| Intent | What the synthesis surfaces |
|---|---|
competitor-ads | Total ads found, active vs inactive split, top creative formats, top 5 ad copy snippets, list of unique landing-page domains. For X specifically: total tweets scraped, count flagged as likely-promoted, top 5 flagged tweets with the heuristic-detection caveat. |
keyword-ads | Top 5 advertisers running ads on this keyword, total ads, country split |
top-creatives | Top 5 by daysRunning (Meta) or CTR (TikTok), with creative summary, link to Ad Library entry |
landing-page-audit | List of unique landing URLs, grouped by domain, with ad counts pointing at each |
cross-platform-audit | Per-platform ad count and tone summary, then a "where they're spending most" inference |
Suggested follow-ups — keyed off the intent that just ran:
| If user just ran… | Suggest next |
|---|---|
competitor-ads (Meta) | Stack with apify-competitor-intelligence to add their FB Page posts, IG profile, and Google Maps reviews |
landing-page-audit (any) | Stack with apify-ecommerce (tech-stack intent) to detect the platform behind the landing pages, or with apify-lead-generation to enrich destination domains with contact info |
top-creatives (TikTok / Meta) | Stack with apify-influencer-discovery if any creatives are influencer collabs |
keyword-ads (Google / Meta) | Stack with apify-trend-analysis to see whether the keyword is rising or falling on Google Trends / Instagram / TikTok |
cross-platform-audit | Stack with apify-content-analytics for the brand's organic content side; combined paid + organic picture |
Quirks
- TikTok keyword search is loose. Searching "Nike" can return ads from unrelated advertisers (Interactive Brokers, Shopify in our test). Always post-filter by
advertiserNamematching the user's intended brand; warn the user if zero matches after filter. - TikTok Ads Library is EU/EEA/UK only. The
librarysource needs an EU country code (DE / FR / IT / ES / NL / PL / SE etc.). For US/global coverage, switch tocreative_centersource — different fields (CTR, impression ranges, no targeting data). dz_omar/google-ads-scraperrequiresresultsPerQuery >= 10. Smaller values fail validation. Always set 10+ even for small intents.apify/facebook-ads-scrapertakes URLs, not keywords. Forcompetitor-ads: buildhttps://www.facebook.com/<PageName>from the brand name. Forkeyword-ads: build a Meta Ad Library URL withq=<keyword>&country=<XX>.apify/google-search-scraperpaid-ads mode has a built-in retry (up to 3) when no paid results are found — sometimes a query genuinely has no paid results. Treat emptypaidResultsas a valid answer, not an error.- LinkedIn Ad Library URL construction: company URL
https://www.linkedin.com/company/<slug>/is allowed but slow and ignores filters. Forcompetitor-adsusehttps://www.linkedin.com/ad-library/search?accountOwner=<slug>&countries=<XX>. Forkeyword-adsuse?keyword=<term>&countries=<XX>. - X has no public ad library. Coverage is heuristic only. The route uses
apidojo/twitter-scraper-liteto scrape a brand's own tweets (or keyword search results), then flags items with non-emptycardfield orsourcecontaining "Ads" as likely promoted. This will miss promoted-only tweets that never appear in the brand's own timeline. - X session sensitivity. If the primary X Actor returns only
noResultssentinels, switch to the fallback before declaring zero results. - Pricing. Most primaries are FREE in our pricing tier;
apify/facebook-ads-scrapercharges per ad ($0.001 - $0.0058); X primaries charge per tweet (~$0.0004 / 1k). Default counts (30 / 20 / 50) keep cost negligible. Warn before runs of 500+ ads.
Error Handling
Actor not found→ check Actor ID against the routing table- Run status
FAILED→ open the console URL (.consoleUrlfrom run metadata) for logs - Timeout / very long run → reduce result count, or set a shorter timeout on the run
- 0 results → switch to the Fallback Actor; if still 0, try a different country code
- TikTok library: no EU country supplied → default to
DEand warn the user dz_omar/google-ads-scraper: validation error onresultsPerQuery→ bump to 10+- X scraper: only
noResultssentinels → switch to the fallback X Actor proxy is requirederror → add"proxy": {"useApifyProxy": true}to the input
Files included
- SKILL.md

