Find the ads already running in a market — paid libraries and organic feeds — and tear down what makes them work.
SEARCH-ENGINE WEBMASTER SURFACES: Search Console · Bing Webm…
list_search_console_sites#
List the Search Console properties shared with this brand read-only
The Google Search Console properties SHARED WITH THIS BRAND, each with the exact property string every other Search Console tool takes and the connected account's permission level on it. CALL THIS FIRST. A property is EITHER "sc-domain:example.com" (a Domain property, covering every scheme and subdomain) OR the full URL-prefix form "https://example.com/" including scheme and trailing slash — Google treats those as different properties and one of them will 403, so resolve it here rather than guessing, and never pass a bare domain. THIS IS NOT EVERY PROPERTY THE GOOGLE ACCOUNT CAN SEE, deliberately: one login commonly holds a dozen clients' properties, so the user ticks which belong to THIS brand and any other one is refused by name. An empty list means nothing is ticked yet — say so and point the user at Settings ▸ Connectors ▸ Google Search Console ▸ Manage accounts (or call list_connector_accounts / set_connector_accounts with provider "google_search_console"); never name or guess a property. A row whose permissionLevel is siteUnverifiedUser will refuse every later call. Read-only, 0 credits. Needs Google Search Console connected.
No parameters.
search_console_performance#
What people searched for on Google, and what they clicked read-only
THE REAL SEARCH TERMS — Google Search Console's performance report, and the most useful research tool here for writing copy. `dimensions:["query"]` returns the literal words people typed to reach this brand, with impressions, clicks, CTR and average position; `dimensions:["page","query"]` answers "which landing page already wins this demand", i.e. where paid traffic should point. Every other dimension is available too: country, device, searchAppearance, date, hour. USE IT BEFORE mine_angles OR plan_ad — this is first-party MEASURED demand language, not a competitor's guess (an ad library) and not a model (a keyword planner), and it exists nowhere else: organic search terms left Google Analytics with "not provided" years ago. startDate and endDate are REQUIRED and are exact YYYY-MM-DD in Pacific time — Google Analytics' relative forms like "28daysAgo" are NOT accepted anywhere in Search Console. THREE THINGS TO REPEAT WHENEVER YOU REPORT THESE NUMBERS: (1) rows are the TOP ones, not all of them, by Google's own statement; (2) anonymised queries are WITHHELD, so clicks summed per query will not equal the property total and that gap is not an error; (3) the default dataState "final" lags roughly 2-3 days, and "all" returns fresh partial data that will still change. Search Console keeps 16 months of history. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact property string from list_search_console_sites — "sc-domain:example.com" or "https://example.com/", never a bare domain, and it must be one SHARED with this brand |
startDaterequired | string | YYYY-MM-DD, required, Pacific time, inclusive |
endDaterequired | string | YYYY-MM-DD, required, Pacific time, inclusive |
dimensions | string[] | group by any of query, page, country, device, searchAppearance, date, hour. Omit for one total row. An unknown name is refused by name rather than dropped. |
type | string | web (default), image, video, news, discover or googleNews |
dimensionFilterGroups | object[] | narrow the report, e.g. [{"filters":[{"dimension":"query","operator":"contains","expression":"buy"}]}]. dimension is one of query/page/country/device/searchAppearance — date and hour are NOT filterable, they are the date range. operator is equals/notEquals/contains/notContains/includingRegex/excludingRegex. An empty expression is refused: Google matches it literally, so it would silently return nothing. |
aggregationType | string | auto (default), byPage, byProperty or byNewsShowcasePanel |
dataState | string | final (default, lags 2-3 days), all (includes fresh partial data that WILL change), or hourlyAll |
rowLimit | number | 1-25000, default 1000 |
startRow | number | zero-based, for paging past rowLimit |
search_console_url_inspection#
Is this page actually in Google? read-only
THE LIVE INDEX STATUS OF ONE PAGE, straight from Google: the index verdict, coverage state, whether robots.txt allows it, which URL Google picked as canonical versus the one the page itself declares, when it was last crawled and as which crawler, plus rich-result and mobile-usability verdicts. This is the tool for "why is this page getting no traffic" — a page Google cannot crawl, or whose canonical Google has reassigned to a different URL, will never rank however good the copy is. THE URL MUST SIT INSIDE THE PROPERTY: a URL-prefix property covers only its own prefix, while an "sc-domain:" property covers every scheme and subdomain. 🚨 QUOTA — Google allows 2,000 inspections per DAY and 600 per minute PER SITE, and that is the CUSTOMER'S property quota, not ours: inspect the handful of URLs the question is actually about and NEVER loop this over a sitemap, a page list or a crawl. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact property string from list_search_console_sites, and it must be one SHARED with this brand |
inspectionUrlrequired | string | the full URL to inspect, e.g. "https://example.com/pricing" — it must be under the property |
languageCode | string | BCP-47 code for translated issue messages, e.g. "de-CH". Default en-US. |
list_search_console_sitemaps#
List a property’s sitemaps, with submitted-vs-indexed counts read-only
The sitemaps registered on a Search Console property: when each was last submitted and last downloaded by Google, whether Google has processed it yet, its error and warning counts, and per content type how many URLs it SUBMITTED against how many are INDEXED. That last pair is the fastest read on whether a site has an indexing problem rather than a ranking one. Pass `feedpath` for one sitemap instead of the list, or `sitemapIndex` to list the sitemaps inside an index file. An empty list is a real answer — the property has no sitemap registered — and is not a failure. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact property string from list_search_console_sites |
feedpath | string | the FULL url of one sitemap, e.g. "https://example.com/sitemap.xml" |
sitemapIndex | string | the FULL url of a sitemap INDEX, to list the sitemaps it contains |
submit_search_console_sitemap#
Submit a sitemap to Google
Tell Google about a sitemap. `feedpath` is the sitemap's COMPLETE URL ("https://example.com/sitemap.xml"), never a path — Google addresses a sitemap by its full url. Re-submitting one that is already registered is harmless and simply re-notifies Google. THE ANSWER IS READ BACK FROM GOOGLE, not echoed from the request: it reports whether the sitemap is now actually registered, whether Google has processed it yet, and what errors and warnings it already carries. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact property string from list_search_console_sites |
feedpathrequired | string | the FULL sitemap URL, e.g. "https://example.com/sitemap.xml" |
delete_search_console_sitemap#
Remove a sitemap from a Search Console property destructive
Remove a sitemap from a property. THIS DOES NOT REMOVE THOSE PAGES FROM GOOGLE'S INDEX — it stops Google using that file to discover new ones, and it can be submitted again at any time, so it is reversible. CONFIRM-GATED: called without confirm it removes nothing and reports what the sitemap actually IS, read back from Google (its error and warning counts and how many URLs it covers), so you can check you are aiming at the right one. Re-run with confirm:true to proceed. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact property string from list_search_console_sites |
feedpathrequired | string | the FULL sitemap URL to remove |
confirm | boolean | true to actually remove it. Without this nothing is removed and the sitemap is described back to you. |
add_search_console_site#
Add a property to Search Console
Add a property to the connected Google account. TWO THINGS THAT MUST REACH THE USER, and the answer states both: (1) ADDING IS NOT VERIFYING — the property arrives with the account as an unverified user and EVERY read on it is refused until ownership is proven with a DNS record, an HTML file or a tag, which no API can do and which the user completes in Search Console itself; (2) the new property is NOT yet shared with this brand, so someone has to tick it under Settings ▸ Connectors ▸ Google Search Console ▸ Manage accounts before any tool here can use it. The permission level is READ BACK from Google, so the answer says which of those two states it is actually in. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | "sc-domain:example.com" for a Domain property (covers every scheme and subdomain), or the full URL-prefix form "https://example.com/". These are different properties — pick deliberately. |
delete_search_console_site#
Remove a property from Search Console destructive
Remove a property from the connected Google account. THIS LOSES HISTORY: the account loses access to that property's stored Search Console performance data, and re-adding it later means verifying ownership from scratch — Google does NOT restore the 16-month window on re-add. Nothing about the site itself, its pages or its ranking changes. CONFIRM-GATED: the unconfirmed call removes nothing and describes what would be lost, including how many sitemaps this account can currently see on it. The property is also dropped from this brand's shared list, so it cannot linger as a tick pointing at something unreachable. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact property string from list_search_console_sites |
confirm | boolean | true to actually remove it |
BING WEBMASTER TOOLS
list_bing_webmaster_sites#
List the Bing Webmaster sites shared with this brand read-only
The Bing Webmaster Tools sites SHARED WITH THIS BRAND, each exactly as Bing holds it (e.g. "https://example.com"). CALL THIS FIRST — every other Bing tool takes that exact string. THIS IS NOT EVERY SITE THE CONNECTION CAN REACH: Microsoft issues one key per USER covering every site that Bing account verified, so the user ticks which belong to THIS brand and any other one is refused by name. An empty list means nothing is ticked yet — point the user at Settings ▸ Connectors ▸ Bing Webmaster Tools ▸ Manage accounts (or call set_connector_accounts with provider "bing_webmaster") and never name or guess a site. A site flagged not verified will refuse every later call. Read-only, 0 credits.
No parameters.
bing_webmaster_traffic#
Bing clicks and impressions read-only
Bing clicks and impressions over time — for the whole site (mode "site", the default), for one page (mode "page", needs `url`), or for every page under one directory (mode "directory", needs `url`). Bing is a smaller share of search than Google, but its index is what Copilot and ChatGPT web search read from, so this is the answer-engine visibility read rather than a second traffic report. An unknown mode is refused by name. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites, and it must be one SHARED with this brand |
mode | string | site (default) | page | directory |
url | string | required for page and directory modes — the full URL |
page | number | zero-based results page, directory mode |
bing_webmaster_query_stats#
What people searched on Bing, and which pages they landed on read-only
The Bing twin of search_console_performance, split by what you want pinned. Modes: "queries" (top search terms for the site, the default), "pages" (top pages), "pageQueries" (which queries brought traffic to one `page`), "queryPages" (which pages one `query` landed on), "queryPageDetail" (one query on one page, day by day). Worth reading BESIDE Search Console rather than instead of it — the two engines' demand language genuinely differs, and Bing is the one feeding Copilot and ChatGPT. MICROSOFT UPDATES THIS DATA WEEKLY by their own statement, so it lags Search Console and will not move day to day; do not report a flat week as a drop. An unknown mode is refused by name. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
mode | string | queries (default) | pages | pageQueries | queryPages | queryPageDetail |
query | string | required for queryPages and queryPageDetail |
page | string | the full page URL — required for pageQueries and queryPageDetail |
bing_webmaster_keywords#
Keyword research with real impression volumes, no ad spend read-only
REAL SEARCH DEMAND FOR ANY TERM, free. Modes: "keyword" (impressions for exactly this term over a date range), "related" (the same for terms Bing considers related — the one to use for expanding a seed into a list), "history" (the term's historical series). This is the closest thing in Hermoso to a free keyword planner: google_ads_keyword_ideas needs Google Ads Basic access, and this needs only the Bing connection anyone can set up in two minutes. NOT SITE-SCOPED — these are Microsoft's signatures and they take no site, so it works for ANY term including a competitor's brand, and no property tick list applies. `country` AND `language` are BOTH REQUIRED and are deliberately never defaulted: a search volume with no market is unactionable, and picking one for you would answer confidently about the wrong country. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
qrequired | string | the keyword to look up, e.g. "running shoes" |
mode | string | keyword (default) | related | history |
countryrequired | string | REQUIRED, e.g. "us" — there is no default and one will not be guessed |
languagerequired | string | REQUIRED, e.g. "en-US" |
startDate | string | YYYY-MM-DD — required for keyword and related modes |
endDate | string | YYYY-MM-DD — required for keyword and related modes |
bing_webmaster_crawl#
Can Bing crawl this site? read-only
Whether Bing can actually reach the site's pages: crawl statistics (mode "stats"), the URLs with problems (mode "issues", the default), one page's index detail (mode "page", needs `url`), a directory's (mode "directory"), or the crawl settings themselves (mode "settings"). Issue names are DECODED from Bing's bitmask into readable ones — Code301, Code302, Code4xx, Code5xx, BlockedByRobotsTxt, ContainsMalware, ImportantUrlBlockedByRobotsTxt, DnsErrors, TimeOutErrors — because the raw JSON hands back an integer that means nothing on its own, and a bit Microsoft has added since is reported as unknown rather than dropped. Microsoft notes it may take a few days for a FIXED issue to disappear from this list, so a listed issue is not proof it is still live. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
mode | string | issues (default) | stats | page | directory | settings |
url | string | required for page and directory modes |
page | number | zero-based results page, directory mode |
bing_webmaster_links#
Inbound links as Bing sees them read-only
Inbound links according to Bing: counts per page (mode "counts", the default), the inbound links pointing at one page (mode "page", needs `url`), or the pages the site owner has declared as connected (mode "connected"). Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
mode | string | counts (default) | page | connected |
url | string | required for page mode — the page whose inbound links you want |
page | number | zero-based results page |
bing_webmaster_submission_quota#
How many URLs can still be submitted to Bing today read-only
How many URLs this site may still submit to Bing today and this month, plus the separate content-submission budget. BING SETS THIS PER SITE AND IT VARIES — Microsoft's own documented example allows 5 a day and 24 a month — so it is always read live and never assumed. Check it before promising anyone a bulk submission, because Bing rejects an over-quota batch as a WHOLE rather than taking what fits. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
submit_bing_webmaster_urls#
Submit URLs to Bing for indexing
Submit URLs to Bing for indexing — the fastest way to get a new or changed page crawled by Bing, and therefore into Copilot and ChatGPT web search. THE SITE'S REMAINING DAILY QUOTA IS READ FIRST and a batch that would exceed it is refused with the real number rather than half-submitted, because Bing rejects an over-quota batch as a whole and a partial failure leaves you unable to say which URLs made it. Bing accepts at most 500 per batch (Microsoft's own limit) and the site's daily quota is usually far lower. THE CONFIRMATION IS BING'S QUOTA COUNTER MOVING: its submit methods return no body at all, so the answer reports the counter before and after rather than claiming success from a 200. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
urlsrequired | string[] | full URLs on THIS site — a URL on another host is refused before anything is submitted |
THE BING WRITE SURFACE
list_bing_webmaster_sitemaps#
The sitemaps Bing has for this site read-only
The sitemaps registered for this site — Bing calls them FEEDS — with the status, URL count, file size and last-crawled date Bing holds for each. This is the read to make BEFORE submitting or removing one, because both of those are addressed by the sitemap's full URL exactly as Bing stores it. Pass `feedUrl` to expand a sitemap INDEX into its child sitemaps (Microsoft's GetFeedDetails); an empty answer for a plain non-index sitemap is a real answer, not a failure. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
feedUrl | string | optional — the full URL of a sitemap INDEX, to list its children |
submit_bing_webmaster_sitemap#
Register a sitemap with Bing
Register a sitemap with Bing so it discovers new and changed pages by itself — the durable twin of submit_bing_webmaster_urls, which spends a small per-site daily quota every time. Takes the sitemap's FULL URL, not a path. Bing accepts Sitemap, RSS 2.0, Atom 0.3, Atom 1.0 and plain text files (Microsoft's own list). A sitemap hosted on ANOTHER host is not refused — Bing allows that when the other host is also verified — but it is called out, because it is the likeliest reason one silently never crawls. SubmitFeed returns no body whatsoever, so the answer is read back from Bing's own feed list and reports what Bing says rather than that the call returned. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
feedUrlrequired | string | the FULL sitemap URL, e.g. "https://example.com/sitemap.xml" |
remove_bing_webmaster_sitemap#
Remove a sitemap from Bing destructive
Remove a sitemap from Bing. GATED ON BLAST RADIUS, not just on intent: called WITHOUT `confirm` it removes nothing and reports what Bing says that sitemap actually carries — its URL count, status and type — and a sitemap carrying any URLs then ALSO needs `confirmUrlCount` set to that number. confirm:true proves you meant to remove something; the echoed count proves you aimed at the sitemap you inspected rather than one that merely shares a name. A sitemap Bing reports as empty stays a one-call removal. Removing it does NOT remove those pages from Bing's index — Bing simply stops using it to find new ones — and it can be submitted again at any time. If the read-back that confirms the removal cannot run, the answer says "could not tell", never "removed". 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
feedUrlrequired | string | the FULL sitemap URL to remove, exactly as list_bing_webmaster_sitemaps shows it |
confirm | boolean | must be true; without it nothing is removed and you get the radius instead |
confirmUrlCount | number | the URL count Bing reports for that sitemap — required when it carries any |
list_bing_webmaster_fetched_urls#
What Bingbot fetched on demand read-only
The URLs fetched on demand as Bingbot for this site, or one of them in detail (pass `url`) including what Bingbot actually received. This is how you see a page through the CRAWLER's eyes rather than a browser's — a robots block, a redirect chain or a JS-only page all look fine in a browser and wrong here. An empty list means nothing has been fetched on demand yet, which is a real answer and not a failure. Read-only, 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
url | string | optional — one full URL, for the stored detail of that fetch |
fetch_bing_webmaster_url#
Ask Bingbot to fetch a page now
Ask Bingbot to fetch one URL now, so you can then read back what the crawler actually received with list_bing_webmaster_fetched_urls. THE FETCH IS QUEUED, NOT PERFORMED WHILE YOU WAIT — so "it has not appeared in the fetched list yet" is the normal FIRST answer, and it is reported as "requested, not yet done" rather than as a failure or as success. A URL that is not on this site is refused before anything is requested. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
urlrequired | string | the full URL on THIS site for Bingbot to fetch |
submit_bing_webmaster_content#
Hand Bing a page's content directly
Give Bing a page's content DIRECTLY instead of waiting for it to crawl — for a page Bingbot renders badly or cannot reach. YOU PASS THE HTML AND NOTHING ELSE: Microsoft's httpMessage parameter is a base64 raw HTTP response whose status line and every header must end CRLF with exactly two CRLFs before the body, and an LF-only message is accepted with a 200 while indexing nothing useful — a silent wrong answer — so Hermoso builds that framing and computes Content-Length itself. Optional `structuredData` carries JSON-LD for non-HTML content such as images or PDFs; `dynamicServing` is left at "none" unless the site really does serve different content per device, because declaring otherwise is a claim about the customer's infrastructure. This spends the CONTENT submission budget, which is separate from the URL one and is read first — check both with bing_webmaster_submission_quota. Max 10MB per submission. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
urlrequired | string | the full URL on this site that this content belongs to |
htmlrequired | string | the page content Bing should index for that URL |
status | number | HTTP status for the message, default 200 |
contentType | string | default text/html |
headers | object | extra response headers. Content-Length is always computed and never taken from you. |
structuredData | string | optional JSON-LD, for non-HTML content types |
dynamicServing | string | none (default) | pc-laptop | mobile | amp | tablet | non-visual-browser |
add_bing_webmaster_site#
Add a site to the Bing Webmaster account
Add a site to the connected Bing Webmaster account. 🚨 ADDING IS NOT VERIFYING, and saying so is most of this tool's value: the site arrives UNVERIFIED and every read on it is refused until an ownership proof is placed on the site itself — an XML file at the root, a meta tag in the home page <head>, or a CNAME DNS record — which no API can do. Place one, then call verify_bing_webmaster_site. Microsoft documents that adding a site which is already there does NOT error, so a success here is not even evidence anything changed, which is why the answer is read back from Bing's site list. It is also NOT shared with this brand until the user ticks it under Settings ▸ Connectors ▸ Bing Webmaster Tools ▸ Manage accounts. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the site with its scheme, e.g. "https://example.com" |
verify_bing_webmaster_site#
Ask Bing to verify site ownership
Ask Bing to CHECK the ownership proof for a site already on the account. IT DOES NOT PLACE THE PROOF — nothing can over an API. The user puts an XML file at the site root, a meta tag in the home page <head>, or a CNAME DNS record, and Bing Webmaster Tools shows the exact filename and value for each. A negative answer therefore means "the proof is not in place yet", never that Hermoso or the connection failed, and the reply says which three options exist. Bing refuses to verify a site that was never added, which is knowable for free, so that is refused here with add_bing_webmaster_site named as the fix. The verdict is read back from the site LIST rather than taken from the call's own return value — the two can disagree. 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the site to verify, exactly as it was added |
remove_bing_webmaster_site#
Remove a site from the Bing Webmaster account destructive
Remove a site from the connected Bing Webmaster account — the heaviest thing in this connector. GATED ON BLAST RADIUS: called WITHOUT `confirm` it removes nothing and reports whether Bing holds the site as VERIFIED and how many sitemaps are registered on it; a site that is verified or has any sitemaps then ALSO needs `confirmSiteUrl` set to that exact site string, which is a fact you only have after inspecting it. A site that was never verified and has no sitemaps is the empty radius and stays a one-call removal — friction that does not scale with the loss just gets routed around. RE-ADDING A VERIFIED SITE LATER MEANS PROVING OWNERSHIP FROM SCRATCH; no API restores it. Nothing about the site itself or its Bing ranking changes. The site is also dropped from this brand's shared list, and if the read-back that confirms the removal cannot run the answer says "could not tell", never "removed". 0 credits.
| Parameter | Type | Description |
|---|
siteUrlrequired | string | the exact site string from list_bing_webmaster_sites |
confirm | boolean | must be true; without it nothing is removed and you get the radius instead |
confirmSiteUrl | string | the exact site string again — required unless the site is unverified with no sitemaps |
COMPETITOR WATCH
set_competitor_watch#
Set the competitor watch
Set (or STOP) this workspace's standing COMPETITOR WATCH — the weekly job that re-checks each named brand's ad libraries and reports what is NEW since last time. The same watch the web app's Ad Spy ▸ Watching tab manages, and the same one the weekly digest email is sent from (turn that email on/off with update_settings({watchEmail})). This REPLACES the whole watched list, it does not add to it — pass every brand you want watched, every time. Max 5 brands (the server trims past that). Pass an EMPTY list to stop the watch entirely, which also clears the findings. Give a `domain` wherever you know one: Google Ads Transparency is looked up BY DOMAIN and is skipped for a brand without one, and the domain is what resolves the right Meta page for a brand with an ambiguous name. The run itself spends ScrapeCreators credits against the ad libraries (roughly 3 per brand on Meta, 1 each on Google and LinkedIn) and is hard-capped per run server-side, so an oversized watch is trimmed rather than allowed to run away. Setting the list is free; only a run spends. runNow:true runs it once IMMEDIATELY (a background job — it spends now) and then keeps the weekly cadence; leave it off and the first check is a week out. The country and the platform mix are NOT settable here — a re-set inherits whatever the pending run already carried (US / Meta for a watch that has never been configured otherwise). Read the findings back with list_watch_findings.
| Parameter | Type | Description |
|---|
competitorsrequired | object[] | the brands to watch — the COMPLETE list, replacing whatever was set before. Empty array = stop watching. |
runNow | boolean | true to run one check immediately (spends credits now) instead of waiting a week for the first one |
list_watch_findings#
Read the competitor watch read-only
Read what the standing COMPETITOR WATCH has found — the new ads each watched brand has launched since the last check, plus the watch's own state (who is watched, when it last ran, when it runs next, and whether the last run actually succeeded). The same board the web app's Ad Spy ▸ Watching tab renders. Use it to answer "what are our competitors running that's new?", to feed a teardown, or to save something worth keeping with save_to_swipefile. Findings marked `seed:true` are NOT new launches — the first check of a brand has nothing to diff against, so it seeds the board with what that brand is running right now; only later runs surface genuine changes. Read-only and free — it returns the stored results of past runs and never triggers a check (set_competitor_watch({runNow:true}) is what runs one).
| Parameter | Type | Description |
|---|
competitor | string | only findings for this watched brand (exact name as returned in `watching`) — omit for all of them |
limit | number | max findings to return (default 25, max 75 — the server keeps at most 75, and at most 15 per brand) |
research_ads#
Research ads read-only
Natural-language ad research: a Claude tool-use loop over Meta/Google/LinkedIn ad libraries + organic TikTok. Returns a summary + the found ads (with their served URLs). Spends LLM tokens + ScrapeCreators credits.
| Parameter | Type | Description |
|---|
queryrequired | string | what to research, e.g. "the longest-running protein-pancake ads on Meta" |
brand | string | object | brand name or profile object to tailor the research to; omit to use the workspace’s saved brand |
structured ad-spy
search_meta_ads#
Search Meta ads read-only
Structured Meta (Facebook/Instagram) Ad Library pull — use when you know exactly WHAT to fetch: a keyword (query) OR one advertiser (companyName / pageId). Returns compact JSON {page_name, body, cta, link, dates, media} per ad. For open-ended research that needs judgment across platforms, use research_ads instead. Spends ScrapeCreators credits (~1–2).
| Parameter | Type | Description |
|---|
query | string | keyword search across ALL advertisers (use INSTEAD of companyName/pageId) |
companyName | string | one advertiser’s ads by brand name |
pageId | string | one advertiser’s ads by Facebook page id (most precise) |
country | string | 2-letter code or 'ALL' (default ALL) |
status | "ACTIVE" | "INACTIVE" | "ALL" | ACTIVE = currently running; default ALL (includes proven past winners) |
mediaType | "ALL" | "IMAGE" | "VIDEO" | "MEME" | "IMAGE_AND_MEME" | "NONE" | filter by creative type (default ALL) |
limit | integer | max ads returned (1–25, default 8) |
search_google_ads#
Search Google ads read-only
Structured Google Ads Transparency pull for ONE advertiser (by domain or advertiserId) — use when you know the brand; use research_ads for open-ended research. Deliberately fetches the cheap BASIC listing (get_ad_details=false, ~1 credit — the detailed variant with per-ad headlines costs 25 credits/call and is not exposed here). Returns compact JSON {advertiser, format, adUrl, image, firstShown, lastShown} per ad.
| Parameter | Type | Description |
|---|
domain | string | the advertiser's domain, e.g. nike.com |
advertiserId | string | Google advertiser id (AR…) when the domain is ambiguous |
region | string | 2-letter region, default US |
limit | integer | max ads returned (1–25, default 8) |
search_linkedin_ads#
Search LinkedIn ads read-only
Structured LinkedIn Ad Library search by company name, keyword, or companyId — use for a targeted B2B pull; use research_ads for open-ended research. Returns compact JSON {advertiser, headline, description, cta, link, media, dates, impressions} per ad — LinkedIn is the one library exposing real impression counts. Spends ScrapeCreators credits (~1).
| Parameter | Type | Description |
|---|
company | string | advertiser company name |
keyword | string | keyword across all advertisers |
companyId | string | LinkedIn company id (numeric) when the name is ambiguous |
countries | string | CSV of 2-letter codes like 'US,CA'; omit or 'ALL' = worldwide |
limit | integer | max ads returned (1–25, default 8) |
search_tiktok#
Search TikTok read-only
Organic TikTok keyword search (there is NO TikTok ad library) — top-performing videos to mine for hooks/trends/remixable creative. Returns compact JSON {desc, author, handle, plays, likes, link, cover} per video, ranked by plays. Use research_ads for open-ended research. Spends ScrapeCreators credits (~1).
| Parameter | Type | Description |
|---|
queryrequired | string | keyword or hashtag (no # needed) |
limit | integer | max videos returned (1–25, default 8) |
search_instagram#
Search Instagram read-only
Organic Instagram REELS keyword search (/v2/instagram/reels/search — ScrapeCreators' only IG keyword surface; profile/hashtag pulls go through scrapecreators_fetch with a handle). Returns compact JSON {desc, author, handle, plays, likes, link, cover} per reel, ranked by plays. Spends ScrapeCreators credits (~1).
| Parameter | Type | Description |
|---|
queryrequired | string | keyword to search reels for |
limit | integer | max reels returned (1–25, default 8) |
search_youtube#
Search YouTube read-only
Organic YouTube keyword search (/v1/youtube/search) — videos to mine for hooks/angles/long-form structure. Returns compact JSON {desc (title), author, handle, plays, link, cover} per video, ranked by views. Spends ScrapeCreators credits (~1).
| Parameter | Type | Description |
|---|
queryrequired | string | keyword to search videos for |
limit | integer | max videos returned (1–25, default 8) |
search_reddit#
Search Reddit read-only
Reddit keyword search (/v1/reddit/search, top-ranked) — a goldmine for the customer's OWN words (pain points, objections, language) to mine into ad hooks and copy. Returns compact JSON {desc (title+selftext), subreddit, upvotes, comments, link} per post. Spends ScrapeCreators credits (~1).
| Parameter | Type | Description |
|---|
queryrequired | string | what to search Reddit for |
limit | integer | max posts returned (1–25, default 8) |
search_threads#
Search Threads read-only
Organic Threads keyword search (/v1/threads/search) — short-form text/social posts for trend + voice research. Returns compact JSON {desc, author, handle, likes, link, cover} per post. Spends ScrapeCreators credits (~1).
| Parameter | Type | Description |
|---|
queryrequired | string | keyword to search Threads for |
limit | integer | max posts returned (1–25, default 8) |
scrapecreators_fetch#
Fetch ScrapeCreators endpoint read-only
Generic ScrapeCreators escape hatch for any ALLOWLISTED long-tail endpoint the dedicated search_* tools don't cover — e.g. {path:'/v1/instagram/profile', params:{handle:'nike'}}. Allowlisted platform families: TikTok (+ TikTok Shop), Instagram, YouTube, Facebook (organic profiles/posts/events/marketplace), LinkedIn (organic posts/companies), Twitter/X, Reddit, Threads, Snapchat, Pinterest, Twitch, Bluesky, Truth Social, Rumble, Spotify, SoundCloud, GitHub, Google search, link-in-bio pages (Linktree etc.). Param names vary per endpoint (profiles use `handle`, keyword searches use `query`, Reddit uses `subreddit`). WARNING: returns RAW provider JSON — large and messy; prefer the dedicated search_* tools. Spends ScrapeCreators credits.
| Parameter | Type | Description |
|---|
pathrequired | string | exact SC endpoint path, e.g. '/v1/tiktok/profile' — non-allowlisted paths are rejected |
params | object | endpoint query params, e.g. {handle:'nike'} |
research analysis & creative remix
competitor_teardown#
Competitor teardown read-only
Tear a competitor's ad strategy down into an actionable playbook: their opening-hook MIX, longest-running campaign THEMES, the WHITE SPACE nobody in their set runs, 2-3 render-ready COUNTER-PLAYS, and the territories they own that you should avoid. Pass `competitor` {name, domain?}. CONTRACT: supply `ads` (raw ad objects from a prior pull_competitor_ads / search_meta_ads call) to tear exactly those down, OR omit `ads` and this pulls the competitor's real Meta ads first (spends ~1-2 ScrapeCreators credits, longest-running = proven winners). Auto-tailors the white space + counter-plays to YOUR saved brand. Spends LLM tokens (0 SC credits when you pass ads).
| Parameter | Type | Description |
|---|
competitorrequired | object | the competitor to tear down |
ads | object[] | ad objects to tear down (from pull_competitor_ads / search_meta_ads). Omit to auto-pull their Meta ads first. |
language | string | output language (default English) |
check_ad_policy#
Check ad policy read-only
Pre-flight ad copy against Meta's REAL, live Advertising Standards before you run it — a flat 1-credit check. Pulls Meta's actual policy pages and returns a verdict (pass / fix / block) where every flagged issue QUOTES Meta's own policy text verbatim plus a compliant rewrite that keeps the sell. It's a check, not an edit — it never changes the creative. Especially worth running for regulated-adjacent categories (health/supplements, weight-loss or beauty results claims, finance/crypto/insurance, alcohol, dating, gambling) or ANY strong/absolute/guaranteed claim.
| Parameter | Type | Description |
|---|
copyrequired | string | the ad copy / script / on-screen text to check |
claims | string | the claims / proof points the ad makes |
category | string | the product category — helps pick the relevant policy pages |
imageDescription | string | a description of the creative / image when relevant |
remix_static#
Remix a static ad
One-click STATIC-AD REMIX: rebuild a competitor/reference STATIC (image) ad as an on-brand version — SAME layout, composition and energy, but YOUR product, brand colours, logo and voice, with every trace of the source brand removed. Pass `imageUrl` = the static ad image to remix. Uses your saved brand (pass brandId to target a specific brand — that switches this key's active brand like use_brand). IMAGES ONLY — for video ads use render_ad. Bills as one image generation.
| Parameter | Type | Description |
|---|
imageUrlrequired | string | the URL of the static ad image to remix |
brandId | string | a brand id/name from list_brands to remix for; omit to use the active brand |
mine_angles#
Mine customer angles read-only
Mine ad ANGLES from real customer language: gathers the customer's own words (Reddit, TikTok, the brand's review page + review-site results) and returns a RANKED angle bank — each angle tagged (pain / outcome / identity / fear / competitive-displacement / social-proof / contrast), 2-5 VERBATIM proof quotes, a 0-100 score with breakdown, and a ready-to-run hook in the customer's own voice. Reads YOUR saved brand (pass brandId to target a specific brand — that switches this key's active brand like use_brand). To tear down a COMPETITOR use competitor_teardown instead. Spends a few ScrapeCreators credits + LLM tokens.
| Parameter | Type | Description |
|---|
brandId | string | a brand id/name from list_brands to mine for; omit to use the active brand |