Ads
The ads endpoints let you discover trending creatives, search every ad we track, and pull a single brand's ad activity across Meta (Facebook/Instagram Ads), TikTok, and Instagram. Each platform has its own field shape and sort options. On this page, we will look at the discover, list, search, and aggregate endpoints.
Media URLs are auto-attached. Every ad response automatically includes stable Brandsearch-hosted URLs for images, videos, and thumbnails. You don't need to request these fields — they're always present when available. They can also be selected explicitly via fields= if you're projecting a narrow subset.
Image URLs are time-limited. Every image URL we return — thumbnails, covers, transformed images — is signed and expires 3 days after the response is issued. After that, the URL returns 404 Expired, and editing the URL won't extend it. Don't cache or hotlink these long-term: re-fetch the parent ad/post when you need fresh URLs. Video URLs (.mp4) and transcript URLs are not subject to this expiry.
Meta ads
Default fields
id, brand_id, status, start_date, end_date, is_video, is_image, platforms, creative, thumbnail_url, eu_total_spend, eu_total_reach, funnel_type, created_at
Auto-attached media URLs
These fields are automatically added to Meta ad responses, and can also be selected explicitly via fields=:
- Name
image_url- Type
- string
- Description
Standard-resolution image URL (image ads only).
- Name
image_original_url- Type
- string
- Description
Original-resolution image URL (when available).
- Name
video_sd_url- Type
- string
- Description
SD video URL (video ads only).
- Name
video_hd_url- Type
- string
- Description
HD video URL (when available).
- Name
thumbnail_url- Type
- string
- Description
Thumbnail preview URL.
All available fields
- Name
id- Type
- string
- Description
Unique ad identifier.
- Name
ad_id- Type
- string
- Description
Meta Ad Library ID.
- Name
brand_id- Type
- string
- Description
The brand this ad belongs to.
- Name
status- Type
- string
- Description
"Active"or"Inactive".
- Name
start_date- Type
- timestamp
- Description
When the ad started running.
- Name
end_date- Type
- timestamp
- Description
When the ad stopped running.
- Name
total_active_time- Type
- integer
- Description
Total active runtime in seconds.
- Name
created_at- Type
- timestamp
- Description
When the ad was first added.
- Name
creative- Type
- object
- Description
Flattened ad copy:
{ "title": string, "description": string, "cta": { "text": string, "type": string } }. When the underlying ad uses Dynamic Creative Optimisation (i.e. the raw text is a placeholder like'{{product.name}}'), the API automatically falls back to the first localised carousel card so you always get real text. Only the keys with non-empty values are returned.
- Name
cards_count- Type
- integer
- Description
Number of carousel cards backing the ad.
0for single-creative ads.
- Name
page_info- Type
- object
- Description
Nested object with the Facebook page that ran the ad:
id,name,current_name,categories,like_count,entity_type,creation_time, etc.
- Name
is_video- Type
- boolean
- Description
Whether the ad contains video.
- Name
is_image- Type
- boolean
- Description
Whether the ad contains an image.
- Name
is_duplicate- Type
- boolean
- Description
Whether the ad is a duplicate variant.
- Name
duplicate_count- Type
- integer
- Description
Number of duplicate variants.
- Name
duration- Type
- integer
- Description
Video duration in seconds.
- Name
platforms- Type
- array
- Description
Platforms the ad runs on (e.g.,
["facebook", "instagram"]).
- Name
categories- Type
- array
- Description
Ad category classifications.
- Name
target_gender- Type
- string
- Description
Target gender demographic.
- Name
target_ages- Type
- string
- Description
Target age range.
- Name
target_locations- Type
- array
- Description
Target location objects.
- Name
eu_total_spend- Type
- number
- Description
Total EU spend in euros.
- Name
eu_daily_spend- Type
- number
- Description
Daily EU spend in euros.
- Name
eu_total_reach- Type
- number
- Description
Total EU reach (impressions).
- Name
per_country_spend- Type
- object
- Description
Spend breakdown by country.
- Name
funnel_type- Type
- string
- Description
Funnel classification (e.g.,
"TOF","MOF","BOF").
- Name
language- Type
- string
- Description
Ad copy language.
- Name
copy_word_count- Type
- integer
- Description
Number of words in ad copy.
- Name
reach_rank- Type
- integer
- Description
Reach ranking among brand ads.
- Name
has_transcript- Type
- boolean
- Description
Whether a transcript is available for the ad's video.
- Name
transcript_url- Type
- string
- Description
URL to a JSON transcript of the ad's audio. Only present when
has_transcriptistrue.
- Name
dashboard_url- Type
- string
- Description
Direct link to this ad's page in the Brandsearch dashboard (e.g.,
https://app.brandsearch.co/ads/meta/123456789). Always present on Meta ads. TikTok and Instagram responses do not carry this field.
Sort fields
created_at, start_date, eu_total_spend, eu_total_reach, reach_rank, total_active_time, duration, scaler
The scaler mode is special — it returns a shuffled mix of high-spending or high-reach ads (couples a reach_rank ∈ [1,10] OR eu_total_spend > 500 filter with a seeded random shuffle). Pass seed= (≤64 chars) on /v1/meta-ads/search or in the body of POST /v1/meta-ads/query to reproduce a specific shuffle; without a seed, every call returns a fresh ordering.
TikTok posts
Default fields
id, brand_id, desc, create_time, play_count, digg_count, comment_count, share_count, engagement_rate, is_video, cover_url, thumbnail_url
Auto-attached media URLs
These fields are automatically added to every TikTok post response, and can also be selected explicitly via fields=:
- Name
cover_url- Type
- string
- Description
Cover image URL (JPEG).
- Name
cover_webp_url- Type
- string
- Description
Cover image URL (WebP).
- Name
cover_converted_url- Type
- string
- Description
Alternate cover URL optimized for broad browser compatibility.
- Name
dynamic_cover_url- Type
- string
- Description
Animated WebP dynamic cover.
- Name
thumbnail_url- Type
- string
- Description
Resized thumbnail URL.
- Name
video_url- Type
- string
- Description
MP4 video URL.
All available fields
- Name
id- Type
- string
- Description
Unique post identifier.
- Name
brand_id- Type
- string
- Description
The brand this post belongs to.
- Name
desc- Type
- string
- Description
Post description/caption.
- Name
create_time- Type
- timestamp
- Description
When the post was created.
- Name
duration- Type
- integer
- Description
Video duration in seconds.
- Name
play_count- Type
- integer
- Description
Number of plays/views.
- Name
digg_count- Type
- integer
- Description
Number of likes (diggs).
- Name
comment_count- Type
- integer
- Description
Number of comments.
- Name
share_count- Type
- integer
- Description
Number of shares.
- Name
collect_count- Type
- integer
- Description
Number of saves/collections.
- Name
engagement_rate- Type
- number
- Description
Engagement rate as a percentage.
- Name
popularity- Type
- number
- Description
Popularity score.
- Name
is_video- Type
- boolean
- Description
Whether the post is a video.
- Name
is_image- Type
- boolean
- Description
Whether the post is an image.
- Name
is_carousel- Type
- boolean
- Description
Whether the post is a carousel.
- Name
has_video- Type
- boolean
- Description
Whether a video is available.
- Name
has_cover- Type
- boolean
- Description
Whether a cover image is available.
- Name
language- Type
- string
- Description
Caption language. Note: the upstream feed sometimes populates this with an ISO country code (e.g.
"GB") instead of a language code ("en") — known data-quality issue, not normalised by the API.
- Name
added- Type
- timestamp
- Description
When the post was added to Brandsearch.
- Name
last_updated- Type
- timestamp
- Description
When the post was last updated.
Sort fields
create_time, play_count, digg_count, comment_count, share_count, engagement_rate, popularity, viral
The viral mode boosts content with high engagement-per-age — play_count ≥ 20k (0–14d), 50k (14–30d), 100k (30–60d), 500k (60–90d). Deterministic, so seed has no effect.
Instagram posts
Default fields
id, brand_id, code, caption, taken_at, post_type, is_video, is_reel, like_count, comment_count, view_count, engagement_rate, thumbnail_url
Auto-attached media URLs
The thumbnail_url field is always a Brandsearch-hosted URL. For videos and reels, a video_url is also attached. These can also be selected explicitly via fields=.
- Name
thumbnail_url- Type
- string
- Description
Thumbnail URL (always present).
- Name
image_transformed_url- Type
- string
- Description
Resized/optimized image URL.
- Name
video_url- Type
- string
- Description
MP4 video URL (only for videos and reels).
All available fields
- Name
id- Type
- string
- Description
Unique post identifier.
- Name
brand_id- Type
- string
- Description
The brand this post belongs to.
- Name
code- Type
- string
- Description
Instagram shortcode (used in the post URL).
- Name
caption- Type
- string
- Description
Post caption text.
- Name
taken_at- Type
- timestamp
- Description
When the post was published.
- Name
post_type- Type
- string
- Description
Post type (e.g.,
"post","reel","story").
- Name
media_type- Type
- string
- Description
Media type classification.
- Name
is_video- Type
- boolean
- Description
Whether the post is a video.
- Name
is_image- Type
- boolean
- Description
Whether the post is an image.
- Name
is_carousel- Type
- boolean
- Description
Whether the post is a carousel.
- Name
is_reel- Type
- boolean
- Description
Whether the post is a Reel.
- Name
like_count- Type
- integer
- Description
Number of likes.
- Name
comment_count- Type
- integer
- Description
Number of comments.
- Name
view_count- Type
- integer
- Description
Number of views.
- Name
play_count- Type
- integer
- Description
Number of plays (for video/reels).
- Name
share_count- Type
- integer
- Description
Number of shares.
- Name
engagement_rate- Type
- number
- Description
Engagement rate as a percentage.
- Name
popularity- Type
- number
- Description
Popularity score.
- Name
thumbnail_url- Type
- string
- Description
Thumbnail image URL.
- Name
video_duration- Type
- number
- Description
Video duration in seconds.
- Name
carousel_media_count- Type
- integer
- Description
Number of items in a carousel.
- Name
hashtags- Type
- array
- Description
Array of hashtags (without the
#).
- Name
mentions- Type
- array
- Description
Array of mentioned usernames.
- Name
language- Type
- string
- Description
Caption language.
- Name
added- Type
- timestamp
- Description
When the post was added to Brandsearch.
- Name
last_updated- Type
- timestamp
- Description
When the post was last updated.
Sort fields
taken_at, like_count, comment_count, view_count, play_count, engagement_rate, popularity, viral
The viral mode boosts content with high engagement-per-age — like_count ≥ 200/1k/2k/10k OR play_count ≥ 20k/50k/100k/500k across 0–14d / 14–30d / 30–60d / 60–90d windows. Deterministic.
Discover trending ads & posts
Three endpoints serve a fresh mix of high-performing ads and posts — the kind of feed you'd build a "Discover" tab around. Random sample from the trending slice, with quality gates already applied so you only see ads that scaled and posts that went viral.
| Endpoint | What it returns |
|---|---|
GET /v1/meta-ads/discover | Top Meta ads from active, scaling brands |
GET /v1/tiktok-ads/discover | Viral TikTok posts |
GET /v1/instagram-posts/discover | Viral Instagram posts |
Quality bar
Every returned row has already passed two layers of filtering — one on the brand, one on the ad/post.
Brand-side (same on all 3 platforms):
- Top markets (
US, CA, GB, AU, DE, FR, IE, NL, IT, ES, NZ, CH, BE, LU) - Top currencies (
USD, CAD, GBP, AUD, EUR, CHF, NZD) monthly_visits >= 100OR added in the last 90 days- TikTok requires at least one TikTok video on file; Instagram requires at least one Instagram post on file
Ad-side (per platform):
- Meta: high reach rank (top 10) OR EU spend over €500. Defaults to English when no
languagesis supplied. - TikTok: viral play count, scaled by recency — 20k+ in the first two weeks, climbing to 500k+ within 90 days
- Instagram: viral like count (200+ / 1k+ / 2k+ / 10k+) OR play count (20k+ / 50k+ / 100k+ / 500k+), scaled by recency
For TikTok and Instagram, when no niche filter is supplied, the discover slice defaults to a curated set of evergreen winners: Beauty & Skincare, Health & Supplements, Pet Supplies, Baby & Kids, Kitchen, Jewelry, Toys & Games, Books & Education. Pass an explicit niche to override.
TikTok and Instagram discover also drop rows whose video or still image is missing — every returned row has playable media. Meta discover always has media.
Common parameters
- Name
seed- Type
- string
- Description
Reproducibility seed (≤64 chars). Same seed + same filters = same sample.
- Name
limit- Type
- integer
- Description
Sample size (1-100). Default
30.
- Name
max_ads_per_brand- Type
- integer
- Description
Cap how many rows from any single brand can appear in the result (1-20).
Each endpoint also accepts the same ad-side filters as its /search sibling, plus the full brand-side filter set (brand_ids, monthly_visits_min/max, meta_ads_active, meta_active_min/max, meta_total_min/max, product_count_min/max, niche, niche_exclude, apps, apps_exclude, techs, techs_exclude, country_code, country_code_exclude, markets, markets_exclude, currency_code, currency_code_exclude, min_revenue_min/max, max_revenue_min/max).
Response
Response shape
{
"data": [...],
"seed": "daily-2026-05-01",
"count": 30
}
Charges 1 credit per returned row.
Example — Meta ads discover
cURL
curl -G https://api.brandsearch.co/v1/meta-ads/discover \
-H "X-API-Key: bsk_your_api_key" \
-d niche="Beauty & Skincare" \
-d languages=en \
-d limit=30 \
-d max_ads_per_brand=2 \
-d seed=daily-2026-05-01
Example — TikTok discover
cURL
curl -G https://api.brandsearch.co/v1/tiktok-ads/discover \
-H "X-API-Key: bsk_your_api_key" \
-d limit=30 \
-d max_ads_per_brand=2
Example — Instagram discover
cURL
curl -G https://api.brandsearch.co/v1/instagram-posts/discover \
-H "X-API-Key: bsk_your_api_key" \
-d limit=30 \
-d max_ads_per_brand=2
List ads for a brand
This endpoint allows you to retrieve a paginated list of ads or posts for a specific brand. The platform parameter is required and determines which ad type and which filters apply.
Required attributes
- Name
platform- Type
- string
- Description
The platform to query. One of:
meta,tiktok,instagram.
Pagination & output
- Name
page- Type
- integer
- Description
Page number (1-1000). Default
1.
- Name
page_size- Type
- integer
- Description
Results per page (1-100). Default
20.
- Name
sort_by- Type
- string
- Description
Sort field (platform-specific, see above).
- Name
sort_order- Type
- string
- Description
ascordesc(defaultdesc).
- Name
fields- Type
- string
- Description
Comma-separated list of fields to include.
Meta filters
These filters only apply when platform=meta.
- Name
status- Type
- string
- Description
activeorinactive.
- Name
is_video- Type
- boolean
- Description
Filter by video ads.
- Name
is_image- Type
- boolean
- Description
Filter by image ads.
- Name
min_spend- Type
- number
- Description
Minimum EU total spend (EUR).
- Name
max_spend- Type
- number
- Description
Maximum EU total spend (EUR).
- Name
min_reach- Type
- number
- Description
Minimum EU total reach.
- Name
q- Type
- string
- Description
Phrase search across the ad's copy and any localised carousel variants. For single-keyword queries, the brand's Meta page name is also matched. Use a double space (
" ") to combine up to 5 keywords (all must match).
- Name
meta_page_created_from- Type
- string
- Description
Filter ads whose Meta page was created on or after this date. Accepts
YYYY-MM-DD, ISO 8601, or unix seconds.
- Name
meta_page_created_to- Type
- string
- Description
Filter ads whose Meta page was created on or before this date. Accepts
YYYY-MM-DD, ISO 8601, or unix seconds.
TikTok & Instagram filters
These filters apply when platform=tiktok or platform=instagram.
- Name
q- Type
- string
- Description
Keyword search. For TikTok, matches the post description and on-screen sticker text. For Instagram, matches the caption and hashtags. Fuzzy matching is enabled, so small typos still match. Max 200 characters.
- Name
is_video- Type
- boolean
- Description
Filter by video posts.
- Name
is_image- Type
- boolean
- Description
Filter by image posts.
- Name
min_play_count- Type
- integer
- Description
Minimum play/view count.
- Name
min_like_count- Type
- integer
- Description
Minimum like count (or digg count on TikTok).
- Name
min_engagement_rate- Type
- number
- Description
Minimum engagement rate (0-100).
Request
curl -G https://api.brandsearch.co/v1/brands/nike.com/ads \
-H "X-API-Key: bsk_your_api_key" \
-d platform=meta \
-d status=active \
-d sort_by=eu_total_spend \
-d page_size=2
Response — Meta ads
{
"data": [
{
"id": "abc123",
"brand_id": "nike.com",
"status": "Active",
"start_date": "2025-01-10T00:00:00Z",
"is_video": true,
"is_image": false,
"platforms": ["facebook", "instagram"],
"creative": {
"title": "Just Do It.",
"description": "Shop the latest collection.",
"cta": { "text": "Shop now", "type": "SHOP_NOW" }
},
"eu_total_spend": 45000.00,
"eu_total_reach": 2500000,
"funnel_type": "TOF",
"created_at": "2025-01-10T12:00:00Z",
"video_sd_url": "https://cdn.brandsearch.co/meta/abc123.mp4",
"video_hd_url": "https://cdn.brandsearch.co/meta/abc123_hd.mp4",
"thumbnail_url": "https://cdn.brandsearch.co/thumbnails/meta/abc123.jpg"
}
],
"pagination": {
"page": 1,
"page_size": 2,
"total": 245,
"total_pages": 123
}
}
cURL — TikTok posts
curl -G https://api.brandsearch.co/v1/brands/nike.com/ads \
-H "X-API-Key: bsk_your_api_key" \
-d platform=tiktok \
-d sort_by=play_count \
-d min_engagement_rate=5
Response — TikTok posts
{
"data": [
{
"id": "7321456789",
"brand_id": "nike.com",
"desc": "New Air Max drop. Link in bio.",
"create_time": "2025-03-15T14:30:00Z",
"play_count": 12500000,
"digg_count": 890000,
"comment_count": 15200,
"share_count": 45000,
"engagement_rate": 7.6,
"is_video": true,
"cover_url": "https://cdn.brandsearch.co/tiktok/cover_7321456789.jpg",
"cover_webp_url": "https://cdn.brandsearch.co/tiktok/cover_7321456789.webp",
"dynamic_cover_url": "https://cdn.brandsearch.co/tiktok/dynamic_cover_7321456789.webp",
"thumbnail_url": "https://cdn.brandsearch.co/thumbnails/tiktok/7321456789.jpg",
"video_url": "https://cdn.brandsearch.co/tiktok/video_7321456789.mp4"
}
],
"pagination": {
"page": 1,
"page_size": 20,
"total": 342,
"total_pages": 18
}
}
cURL — Instagram posts
curl -G https://api.brandsearch.co/v1/brands/nike.com/ads \
-H "X-API-Key: bsk_your_api_key" \
-d platform=instagram \
-d sort_by=like_count \
-d min_like_count=10000
Response — Instagram posts
{
"data": [
{
"id": "3021456789",
"brand_id": "nike.com",
"code": "C1abc234XYZ",
"caption": "Dream crazier.",
"taken_at": "2025-03-20T10:00:00Z",
"post_type": "reel",
"is_video": true,
"is_reel": true,
"like_count": 450000,
"comment_count": 8900,
"view_count": 5200000,
"engagement_rate": 9.2,
"thumbnail_url": "https://cdn.brandsearch.co/instagram/thumbnail_3021456789.jpg",
"image_transformed_url": "https://cdn.brandsearch.co/thumbnails/instagram/thumbnail_3021456789.jpg",
"video_url": "https://cdn.brandsearch.co/instagram/video_3021456789.mp4"
}
],
"pagination": {
"page": 1,
"page_size": 20,
"total": 512,
"total_pages": 26
}
}
Brand-side filters (any ad endpoint)
Every ad search, query, discover, and aggregate endpoint accepts the same brand-side filter set as /v1/brands — pre-filter the brand pool, then layer ad-side filters on top. Useful for "show me viral TikToks from beauty brands with 1M+ monthly visits" or "Meta ads from brands using Klaviyo, in the US or Canada".
Applies to: GET|POST /v1/meta-ads/search, POST /v1/meta-ads/query, GET /v1/meta-ads/discover, POST /v1/meta-ads/aggregates and their TikTok / Instagram counterparts.
- Name
brand_ids- Type
- string
- Description
Comma-separated list of brand IDs (cleaned domains, e.g.
nike.com,adidas.com). POST form accepts a JSON array. Cap 200 IDs per request. Constrains results to ads from the listed brands.
- Name
monthly_visits_min- Type
- integer
- Description
Minimum monthly visits on the parent brand.
- Name
monthly_visits_max- Type
- integer
- Description
Maximum monthly visits.
- Name
meta_ads_active- Type
- boolean
- Description
Only ads from brands with active Meta ads (
true) or without (false).
- Name
meta_active_min- Type
- integer
- Description
Minimum active Meta ads on the parent brand.
- Name
meta_active_max- Type
- integer
- Description
Maximum active Meta ads on the parent brand.
- Name
meta_total_min- Type
- integer
- Description
Minimum total Meta ads on the parent brand.
- Name
meta_total_max- Type
- integer
- Description
Maximum total Meta ads on the parent brand.
- Name
product_count_min- Type
- integer
- Description
Minimum product count on the parent brand.
- Name
product_count_max- Type
- integer
- Description
Maximum product count on the parent brand.
- Name
niche- Type
- string
- Description
Comma-separated list of niches — keep only ads from brands in these niches.
- Name
niche_exclude- Type
- string
- Description
Comma-separated list of niches to exclude.
- Name
apps- Type
- string
- Description
Comma-separated app names — keep only ads from brands using at least one of these apps.
- Name
apps_exclude- Type
- string
- Description
Comma-separated app names — drop ads from brands using any of these apps.
- Name
techs- Type
- string
- Description
Comma-separated technology names — keep only ads from brands using at least one of these techs.
- Name
techs_exclude- Type
- string
- Description
Comma-separated technology names — drop ads from brands using any of these techs.
- Name
country_code- Type
- string
- Description
Comma-separated ISO country codes (e.g.,
US,CA,GB). Keep only ads from brands headquartered in these countries. Case-insensitive.
- Name
country_code_exclude- Type
- string
- Description
Comma-separated ISO country codes — drop ads from brands HQ'd in any of these countries. Case-insensitive.
- Name
markets- Type
- string
- Description
Comma-separated full country names (e.g.,
United States,Canada) — matches the parent brand'sships_to_countries. Distinct fromcountry_code(HQ origin). Case-sensitive. Use canonical names fromGET /v1/facets/country-names.
- Name
markets_exclude- Type
- string
- Description
Comma-separated full country names — drop ads from brands shipping to any of these markets.
- Name
currency_code- Type
- string
- Description
Comma-separated ISO-4217 currency codes (e.g.,
USD,EUR). Keep only ads from brands in these currencies. Case-insensitive. Vocabulary atGET /v1/facets/currencies.
- Name
currency_code_exclude- Type
- string
- Description
Comma-separated currency codes — drop ads from brands in any of these currencies.
- Name
min_revenue_min- Type
- number
- Description
Minimum value of the parent brand's
min_revenue(conservative revenue estimate).
- Name
min_revenue_max- Type
- number
- Description
Maximum value of the parent brand's
min_revenue.
- Name
max_revenue_min- Type
- number
- Description
Minimum value of the parent brand's
max_revenue(optimistic revenue estimate).
- Name
max_revenue_max- Type
- number
- Description
Maximum value of the parent brand's
max_revenue.
Search Meta ads
Search every Meta ad we track. Unlike /v1/brands/{brand_id}/ads, this is not scoped to a single brand — find ads by copy, spend, reach, targeting, and timing across all brands at once.
Returns the same Meta ad fields as the per-brand endpoint, with the same auto-attached media URLs.
Search
- Name
q- Type
- string
- Description
Phrase search across the ad's copy and any localised carousel variants. For single-keyword queries, the brand's Meta page name is also matched. Use a double space (
" ") to combine up to 5 keywords (all must match). Max 200 characters.
Status & media filters
- Name
status- Type
- string
- Description
activeorinactive.
- Name
is_video- Type
- boolean
- Description
Filter by video ads.
- Name
is_image- Type
- boolean
- Description
Filter by image ads.
Spend & reach filters
- Name
spend_min- Type
- number
- Description
Minimum total EU spend in euros.
- Name
spend_max- Type
- number
- Description
Maximum total EU spend in euros.
- Name
daily_spend_min- Type
- number
- Description
Minimum daily EU spend in euros.
- Name
daily_spend_max- Type
- number
- Description
Maximum daily EU spend in euros.
- Name
reach_min- Type
- number
- Description
Minimum EU reach.
- Name
reach_max- Type
- number
- Description
Maximum EU reach.
- Name
reach_rank_min- Type
- integer
- Description
Minimum reach rank.
- Name
reach_rank_max- Type
- integer
- Description
Maximum reach rank.
Creative filters
- Name
duration_min- Type
- integer
- Description
Minimum video duration (seconds).
- Name
duration_max- Type
- integer
- Description
Maximum video duration (seconds).
- Name
copy_word_count_min- Type
- integer
- Description
Minimum word count in ad copy.
- Name
copy_word_count_max- Type
- integer
- Description
Maximum word count in ad copy.
- Name
duplicate_count_min- Type
- integer
- Description
Minimum duplicate variant count.
- Name
duplicate_count_max- Type
- integer
- Description
Maximum duplicate variant count.
- Name
funnel_types- Type
- string
- Description
Comma-separated list of funnel types (e.g.,
TOF,MOF,BOF).
- Name
languages- Type
- string
- Description
Comma-separated list of language codes (e.g.,
en,fr,es).
- Name
cta_types- Type
- string
- Description
Comma-separated list of CTA types (e.g.,
SHOP_NOW,LEARN_MORE).
Targeting filters
- Name
platforms- Type
- string
- Description
Comma-separated list of distribution platforms. Allowed values:
facebook,instagram,messenger,audience_network,threads(case-insensitive).
- Name
target_gender- Type
- string
- Description
One of:
male,female,all,unknown.
- Name
eu_countries- Type
- string
- Description
Comma-separated list of ISO country codes (e.g.,
FR,DE,IT).
Date filters
All date filters accept YYYY-MM-DD, ISO 8601, or unix seconds.
- Name
ad_started_from- Type
- string
- Description
Filter ads with
start_dateon or after this date.
- Name
ad_started_to- Type
- string
- Description
Filter ads with
start_dateon or before this date.
- Name
meta_page_created_from- Type
- string
- Description
Filter ads whose Meta page was created on or after this date.
- Name
meta_page_created_to- Type
- string
- Description
Filter ads whose Meta page was created on or before this date.
Brand-side filters
All brand-side filters compose on top of the ad-side filters above — brand_ids, monthly_visits_min/max, niche, apps, techs, country_code, markets, currency_code, min_revenue_*, max_revenue_*, etc.
Pagination & output
- Name
page- Type
- integer
- Description
Page number (1-1000). Default
1.
- Name
page_size- Type
- integer
- Description
Results per page (1-100). Default
20.
- Name
sort_by- Type
- string
- Description
Sort field. One of:
created_at,start_date,eu_total_spend,eu_total_reach,reach_rank,total_active_time,duration,scaler. Thescalermode is a shuffled mix of high-spend / high-reach ads (see Sort fields above).
- Name
sort_order- Type
- string
- Description
ascordesc(defaultdesc).
- Name
seed- Type
- string
- Description
Reproducibility seed (≤64 chars). Pins the random shuffle when
sort_by=scaler. Withoutseed, a fresh server-generated seed is used per request.
- Name
max_ads_per_brand- Type
- integer
- Description
Cap how many rows from any single brand can appear in the result (1-20). Useful with
sort_by=scalerto surface a diverse mix. The cap is applied after the search runs, sopagination.totalstill reflects the total ads matching your filters (pre-cap).
- Name
fields- Type
- string
- Description
Comma-separated list of Meta ad fields to include.
Request
curl -G https://api.brandsearch.co/v1/meta-ads/search \
-H "X-API-Key: bsk_your_api_key" \
-d q="summer sale" \
-d status=active \
-d spend_min=1000 \
-d platforms="facebook,instagram" \
-d languages=en \
-d ad_started_from=2025-01-01 \
-d sort_by=eu_total_spend \
-d page_size=2
Response
{
"data": [
{
"id": "xyz789",
"brand_id": "nike.com",
"status": "Active",
"start_date": "2025-06-01T00:00:00Z",
"is_video": true,
"is_image": false,
"platforms": ["facebook", "instagram"],
"creative": {
"title": "Summer sale",
"description": "30% off running shoes.",
"cta": { "text": "Shop sale", "type": "SHOP_NOW" }
},
"eu_total_spend": 12500.00,
"eu_total_reach": 850000,
"funnel_type": "BOF",
"language": "en",
"created_at": "2025-06-01T08:00:00Z",
"video_sd_url": "https://cdn.brandsearch.co/meta/xyz789.mp4",
"thumbnail_url": "https://cdn.brandsearch.co/thumbnails/meta/xyz789.jpg"
}
],
"pagination": {
"page": 1,
"page_size": 2,
"total": 4218,
"total_pages": 2109
}
}
Search TikTok posts
Search every TikTok post we track across all brands. Find posts by description, hashtag-style sticker text, engagement, duration, and timing.
Search
- Name
q- Type
- string
- Description
Keyword search across the post description and on-screen sticker text. Fuzzy matching is enabled, so small typos still match. Max 200 characters.
Engagement filters
- Name
play_count_min- Type
- integer
- Description
Minimum play (view) count.
- Name
play_count_max- Type
- integer
- Description
Maximum play count.
- Name
digg_count_min- Type
- integer
- Description
Minimum like count (TikTok calls likes "diggs").
- Name
digg_count_max- Type
- integer
- Description
Maximum like count.
- Name
comment_count_min- Type
- integer
- Description
Minimum comment count.
- Name
comment_count_max- Type
- integer
- Description
Maximum comment count.
- Name
share_count_min- Type
- integer
- Description
Minimum share count.
- Name
share_count_max- Type
- integer
- Description
Maximum share count.
- Name
collect_count_min- Type
- integer
- Description
Minimum save count.
- Name
collect_count_max- Type
- integer
- Description
Maximum save count.
- Name
engagement_rate_min- Type
- number
- Description
Minimum engagement rate (0-100).
- Name
engagement_rate_max- Type
- number
- Description
Maximum engagement rate (0-100).
Media filters
- Name
is_video- Type
- boolean
- Description
Filter for video posts.
- Name
is_image- Type
- boolean
- Description
Filter for image posts.
- Name
is_carousel- Type
- boolean
- Description
Filter for carousel posts.
- Name
duration_min- Type
- integer
- Description
Minimum video duration in seconds.
- Name
duration_max- Type
- integer
- Description
Maximum video duration in seconds.
Other filters
- Name
languages- Type
- string
- Description
Comma-separated list of ISO language codes (e.g.,
en,fr,es). Case-insensitive —frandFRbehave identically.
- Name
created_from- Type
- string
- Description
Filter posts created on or after this date. Accepts
YYYY-MM-DD, ISO 8601, or unix seconds.
- Name
created_to- Type
- string
- Description
Filter posts created on or before this date.
Brand-side filters
All brand-side filters compose on top of the ad-side filters above — brand_ids, monthly_visits_min/max, niche, apps, techs, country_code, markets, currency_code, min_revenue_*, max_revenue_*, etc.
Pagination & output
- Name
page- Type
- integer
- Description
Page number (1-1000). Default
1.
- Name
page_size- Type
- integer
- Description
Results per page (1-100). Default
20.
- Name
sort_by- Type
- string
- Description
Sort field. One of:
create_time,play_count,digg_count(alias:likes),comment_count,share_count,engagement_rate,popularity,viral. Theviralmode boosts content with high engagement-per-age (deterministic).
- Name
sort_order- Type
- string
- Description
ascordesc(defaultdesc).
- Name
max_ads_per_brand- Type
- integer
- Description
Cap how many rows from any single brand can appear in the result (1-20). Useful with
sort_by=viralto surface a diverse mix. The cap is applied after the search runs, sopagination.totalstill reflects the total posts matching your filters (pre-cap).
- Name
fields- Type
- string
- Description
Comma-separated list of TikTok post fields to include.
Request
curl -G https://api.brandsearch.co/v1/tiktok-ads/search \
-H "X-API-Key: bsk_your_api_key" \
-d q="skincare routine" \
-d play_count_min=100000 \
-d engagement_rate_min=5 \
-d languages=en \
-d sort_by=play_count \
-d page_size=2
Response
{
"data": [
{
"id": "7411223344",
"brand_id": "glowrecipe.com",
"desc": "My 5-step skincare routine for glass skin.",
"create_time": "2025-08-14T10:00:00Z",
"play_count": 4200000,
"digg_count": 320000,
"comment_count": 5400,
"share_count": 18000,
"engagement_rate": 8.1,
"is_video": true,
"cover_url": "https://cdn.brandsearch.co/tiktok/cover_7411223344.jpg",
"thumbnail_url": "https://cdn.brandsearch.co/thumbnails/tiktok/7411223344.jpg",
"video_url": "https://cdn.brandsearch.co/tiktok/video_7411223344.mp4"
}
],
"pagination": {
"page": 1,
"page_size": 2,
"total": 8742,
"total_pages": 4371
}
}
Search Instagram posts
Search every Instagram post we track across all brands. Find posts by caption, hashtag, engagement, post type, and timing.
Search
- Name
q- Type
- string
- Description
Keyword search across the caption and hashtags. Fuzzy matching is enabled, so small typos still match. Max 200 characters.
Engagement filters
- Name
like_count_min- Type
- integer
- Description
Minimum like count.
- Name
like_count_max- Type
- integer
- Description
Maximum like count.
- Name
comment_count_min- Type
- integer
- Description
Minimum comment count.
- Name
comment_count_max- Type
- integer
- Description
Maximum comment count.
- Name
view_count_min- Type
- integer
- Description
Minimum view count.
- Name
view_count_max- Type
- integer
- Description
Maximum view count.
- Name
play_count_min- Type
- integer
- Description
Minimum play count (videos and Reels).
- Name
play_count_max- Type
- integer
- Description
Maximum play count.
- Name
share_count_min- Type
- integer
- Description
Minimum share count.
- Name
share_count_max- Type
- integer
- Description
Maximum share count.
- Name
engagement_rate_min- Type
- number
- Description
Minimum engagement rate (0-100).
- Name
engagement_rate_max- Type
- number
- Description
Maximum engagement rate (0-100).
Media filters
- Name
post_type- Type
- string
- Description
Filter by post type (e.g.,
post,reel,story).
- Name
is_video- Type
- boolean
- Description
Filter for video posts.
- Name
is_image- Type
- boolean
- Description
Filter for image posts.
- Name
is_carousel- Type
- boolean
- Description
Filter for carousel posts.
- Name
is_reel- Type
- boolean
- Description
Filter for Reels.
Other filters
- Name
languages- Type
- string
- Description
Comma-separated list of ISO language codes (e.g.,
en,fr,es). Case-insensitive —frandFRbehave identically.
- Name
taken_at_from- Type
- string
- Description
Filter posts published on or after this date. Accepts
YYYY-MM-DD, ISO 8601, or unix seconds.
- Name
taken_at_to- Type
- string
- Description
Filter posts published on or before this date.
Brand-side filters
All brand-side filters compose on top of the ad-side filters above — brand_ids, monthly_visits_min/max, niche, apps, techs, country_code, markets, currency_code, min_revenue_*, max_revenue_*, etc.
Pagination & output
- Name
page- Type
- integer
- Description
Page number (1-1000). Default
1.
- Name
page_size- Type
- integer
- Description
Results per page (1-100). Default
20.
- Name
sort_by- Type
- string
- Description
Sort field. One of:
taken_at,like_count(alias:likes),comment_count,view_count,play_count,engagement_rate,popularity,viral. Theviralmode boosts content with high engagement-per-age (deterministic).
- Name
sort_order- Type
- string
- Description
ascordesc(defaultdesc).
- Name
max_ads_per_brand- Type
- integer
- Description
Cap how many rows from any single brand can appear in the result (1-20). Useful with
sort_by=viralto surface a diverse mix. The cap is applied after the search runs, sopagination.totalstill reflects the total posts matching your filters (pre-cap).
- Name
fields- Type
- string
- Description
Comma-separated list of Instagram post fields to include.
Request
curl -G https://api.brandsearch.co/v1/instagram-posts/search \
-H "X-API-Key: bsk_your_api_key" \
-d q="black friday" \
-d is_reel=true \
-d like_count_min=10000 \
-d taken_at_from=2025-11-01 \
-d sort_by=like_count \
-d page_size=2
Response
{
"data": [
{
"id": "3055667788",
"brand_id": "fashionnova.com",
"code": "C9xyz123ABC",
"caption": "Black Friday — up to 70% off. Link in bio.",
"taken_at": "2025-11-28T14:00:00Z",
"post_type": "reel",
"is_video": true,
"is_reel": true,
"like_count": 215000,
"comment_count": 3400,
"view_count": 4800000,
"engagement_rate": 6.4,
"thumbnail_url": "https://cdn.brandsearch.co/instagram/thumbnail_3055667788.jpg",
"video_url": "https://cdn.brandsearch.co/instagram/video_3055667788.mp4"
}
],
"pagination": {
"page": 1,
"page_size": 2,
"total": 15320,
"total_pages": 7660
}
}
Detail endpoints
Fetch a single ad or post by ID. Returns the same row shape as the corresponding list endpoint and supports fields= for projection. Each detail call costs 1 credit. Returns 404 ad_not_found if the ID does not exist.
| Endpoint | Path | Notes |
|---|---|---|
| Get a Meta ad | GET /v1/meta-ads/{ad_id} | Accepts either the bare ad_id (Meta Ad Library ID) or the composite {brand_id}_{ad_id} form returned in list responses. |
| Get a TikTok post | GET /v1/tiktok-ads/{ad_id} | Use the id from a list response. |
| Get an Instagram post | GET /v1/instagram-posts/{post_id} | Use the id from a list response. |
cURL — Meta ad
curl https://api.brandsearch.co/v1/meta-ads/123456789 \
-H "X-API-Key: bsk_your_api_key" \
-G -d fields=id,creative,eu_total_spend,video_sd_url
JSON body counterparts (POST /query)
Each search endpoint has a POST counterpart that takes filters in the JSON body. Same filter shape as the GET version (including the full brand-side filter set and brand_ids), plus page and page_size in the body. List-shaped fields (brand_ids, niche, niche_exclude, apps, apps_exclude, techs, techs_exclude, country_code, country_code_exclude, markets, markets_exclude, currency_code, currency_code_exclude, funnel_types, languages, platforms, eu_countries, cta_types) accept either a CSV string or a JSON array.
| GET endpoint | POST counterpart |
|---|---|
GET /v1/brands | POST /v1/brands/query |
GET /v1/meta-ads/search | POST /v1/meta-ads/query |
GET /v1/tiktok-ads/search | POST /v1/tiktok-ads/query |
GET /v1/instagram-posts/search | POST /v1/instagram-posts/query |
Use these when your filter set is too long for a query string, or when you'd rather send native JSON arrays and nested values than CSV.
Unknown fields are rejected. As of the latest release, all search and query endpoints return 400 validation_error if you pass a field they don't recognise. Common typos: niches → niche, country → country_code, language → languages, brand_id → brand_ids. The error response names the offending field at error.details.parameter.
cURL — POST /v1/meta-ads/query
curl -X POST https://api.brandsearch.co/v1/meta-ads/query \
-H "X-API-Key: bsk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"q": "summer sale",
"status": "active",
"platforms": ["facebook", "instagram"],
"languages": ["en", "fr"],
"spend_min": 1000,
"ad_started_from": "2025-01-01",
"sort_by": "eu_total_spend",
"page": 1,
"page_size": 20
}'
Aggregate dashboard
Two aggregation endpoints return a six-dimension summary over a slice of Meta ads in a single round trip — perfect for building dashboards without fetching every ad. Each call charges 1 credit flat, regardless of how many underlying ads were aggregated.
Six dimensions returned
- Name
media_mix- Type
- object
- Description
Counts of
videovsimageads.
- Name
funnel_mix- Type
- object
- Description
Ad count by funnel type (
TOF,MOF,BOF,unknown).
- Name
language_mix- Type
- object
- Description
Ad count by language code.
- Name
cta_breakdown- Type
- object
- Description
Ad count by call-to-action — combines the primary creative's CTA and any per-card CTAs on carousel ads.
- Name
demography- Type
- object
- Description
Nested
{gender, age, country}— each is an object mapping the value to ad count.
- Name
spend_summary- Type
- object
- Description
ad_count,eu_total_spend(sum),avg_eu_total_spend,max_eu_total_spend,eu_total_reach,avg_eu_total_reach,max_eu_total_reach.
Aggregates for one brand
Aggregate Meta ads for a single brand. Useful when you already know the brand and want a pre-computed summary.
Optional attributes
- Name
status- Type
- string
- Description
activeorinactive. Default: include both.
- Name
from- Type
- string
- Description
Lower bound on
start_date. AcceptsYYYY-MM-DD, ISO 8601, or unix seconds.
- Name
to- Type
- string
- Description
Upper bound on
start_date.
Request
curl -G https://api.brandsearch.co/v1/brands/nike.com/ads/aggregates \
-H "X-API-Key: bsk_your_api_key" \
-d status=active \
-d from=2025-01-01
Response
{
"brand_id": "nike.com",
"platform": "meta",
"window": { "from": "2025-01-01", "to": null, "ad_count": 245 },
"media_mix": { "video": 187, "image": 58 },
"funnel_mix": { "TOF": 142, "MOF": 78, "BOF": 25 },
"language_mix": { "en": 200, "fr": 28, "es": 17 },
"cta_breakdown": { "SHOP_NOW": 158, "LEARN_MORE": 64, "SIGN_UP": 23 },
"demography": {
"gender": { "all": 198, "female": 31, "male": 16 },
"age": { "18-65": 142, "25-54": 68, "...": "..." },
"country": { "US": 120, "GB": 42, "DE": 31, "...": "..." }
},
"spend_summary": {
"ad_count": 245,
"eu_total_spend": 1245000.0,
"avg_eu_total_spend": 5081.6,
"max_eu_total_spend": 92000.0,
"eu_total_reach": 48200000,
"avg_eu_total_reach": 196734.7,
"max_eu_total_reach": 3400000
}
}
Aggregates across all brands
Same six-dimension aggregation, but over an arbitrary slice of every Meta ad we track. Body shape matches POST /v1/meta-ads/query minus pagination — including the full brand-side filter set, so you can aggregate over "every Meta ad from US Beauty brands with 1M+ monthly visits" in a single call.
Useful for industry-wide views: "what CTAs are top-performing in Beauty right now?", "spend distribution across languages last quarter", and so on.
Request
curl -X POST https://api.brandsearch.co/v1/meta-ads/aggregates \
-H "X-API-Key: bsk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"status": "active",
"spend_min": 1000,
"languages": ["en"],
"ad_started_from": "2025-01-01"
}'
Response
{
"platform": "meta",
"window": { "ad_count": 124800 },
"media_mix": { "video": 98400, "image": 26400 },
"funnel_mix": { "TOF": 72100, "MOF": 38200, "BOF": 14500 },
"language_mix": { "en": 124800 },
"cta_breakdown": { "SHOP_NOW": 81200, "LEARN_MORE": 32800, "SIGN_UP": 10800 },
"demography": { "gender": { "...": "..." }, "age": { "...": "..." }, "country": { "...": "..." } },
"spend_summary": {
"ad_count": 124800,
"eu_total_spend": 482300000.0,
"avg_eu_total_spend": 3865.5,
"max_eu_total_spend": 920000.0,
"eu_total_reach": 24200000000,
"avg_eu_total_reach": 193910.3,
"max_eu_total_reach": 12400000
}
}
Aggregate TikTok posts
Multi-dimension dashboard over an arbitrary slice of TikTok posts. Body shape matches POST /v1/tiktok-ads/query minus pagination — including the full brand-side filter set, so you can aggregate over "every TikTok post from beauty brands in the US" in a single call.
Charges 1 credit flat regardless of how many posts are aggregated.
Returned dimensions
- Name
media_mix- Type
- object
- Description
Counts for
video,image,carousel.
- Name
language_mix- Type
- object
- Description
Post count by language code.
- Name
engagement_summary- Type
- object
- Description
ad_countplus{sum, avg, max}blocks forplay_count,digg_count,comment_count,share_count,collect_count,engagement_rate.
Request
curl -X POST https://api.brandsearch.co/v1/tiktok-ads/aggregates \
-H "X-API-Key: bsk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"q": "skincare routine",
"play_count_min": 100000,
"languages": ["en"],
"created_from": "2025-01-01"
}'
Response
{
"media_mix": { "video": 24800, "image": 1240, "carousel": 320 },
"language_mix": { "en": 24800, "fr": 1240, "es": 320 },
"engagement_summary": {
"ad_count": 26360,
"play_count": { "sum": 8412000000, "avg": 319193.5, "max": 42000000 },
"digg_count": { "...": "..." },
"comment_count": { "...": "..." },
"share_count": { "...": "..." },
"collect_count": { "...": "..." },
"engagement_rate": { "...": "..." }
}
}
Aggregate Instagram posts
Multi-dimension dashboard over an arbitrary slice of Instagram posts. Body shape matches POST /v1/instagram-posts/query minus pagination — including the full brand-side filter set.
Charges 1 credit flat.
Returned dimensions
- Name
media_mix- Type
- object
- Description
Counts for
video,image,carousel,reel.
- Name
post_type_mix- Type
- object
- Description
Post count by
post_typevalue.
- Name
language_mix- Type
- object
- Description
Post count by language code.
- Name
engagement_summary- Type
- object
- Description
post_countplus{sum, avg, max}blocks forlike_count,comment_count,view_count,play_count,share_count,engagement_rate.
Request
curl -X POST https://api.brandsearch.co/v1/instagram-posts/aggregates \
-H "X-API-Key: bsk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"is_reel": true,
"like_count_min": 10000,
"languages": ["en"],
"taken_at_from": "2025-11-01"
}'
Response
{
"media_mix": { "video": 18400, "image": 6200, "carousel": 1240, "reel": 16800 },
"post_type_mix": { "reel": 16800, "post": 7600, "story": 1440 },
"language_mix": { "en": 24800, "es": 1240 },
"engagement_summary": {
"post_count": 25840,
"like_count": { "sum": 412000000, "avg": 15945.4, "max": 4800000 },
"comment_count": { "...": "..." },
"view_count": { "...": "..." },
"play_count": { "...": "..." },
"share_count": { "...": "..." },
"engagement_rate": { "...": "..." }
}
}