Skip to main content
Glama

Get trends

get_trends
Read-only

Get aggregated trend rankings for a dimension: geo, geo_timeline, advertisers, webmasters, apps, timeline or scaling. Common filters: date_from/date_to, date_basis (timeline/geo: fb_start or parsed), country (single ISO code or comma-separated codes for geo_timeline), platform, ai_category/ai_subcategory, media_type, status, format, min_days_active, sort_by/sort_order. Each dimension has its own row semantics — units, what a zero means, which counters are comparable with which. They are NOT repeated here: call the tool and the chosen dimension's full field semantics arrive with the data, in meta.dimension_semantics. One line each so you can pick: geo = point-in-time per-country stock; geo_timeline = batched per-country daily NEW-AD flow; timeline = one segment's daily flow; advertisers = fanpage ranking; webmasters = anonymous affiliate networks (ranking signals only); apps = store-app ranking; domains = landing-domain (brand) ranking, requires a category; scaling = winning/new creatives by launch acceleration, with preset signals or your own thresholds. Returns ranked rows with totals. On dimensions whose total is the real market size (advertisers, apps) the response carries has_more + offset so you know whether another page exists; on webmasters/domains total is returned_rows_only, so has_more is intentionally absent (use search_webmasters.pagination.total for the segment universe). Use for rankings/aggregates, NOT to list individual ads (use search_ads). Rows never carry media URLs on any plan — a trend row is metadata; fetch the asset with get_media (50 tokens per multilang ad, 1 per ordinary ad, 10 per creative), the same split every other listing already uses. dimension=scaling pages 50 rows at a time, matching the website panel; other dimensions keep the 200 ceiling. On the FREE plan dimensions scaling / advertisers / apps return a 6-row preview and do NOT paginate — the same slice the site shows before its paywall; passing offset is refused rather than silently answered with page 1. Narrow the filters to preview a different slice, or upgrade for the full ranking. FREE PLAN COUNTS: when the plan window narrows the request, pagination.total_status is "restricted" — the count describes the archive window actually searched, not the one asked for, so a zero means "nothing in the archive window", never "nothing exists". FREE PLAN COUNTS: when the plan's archive window narrows a request, pagination.total_status is "restricted" and meta.plan_window_cutoff names the boundary — the count then describes the window actually searched, NOT the one requested, so a zero means "nothing in the archive window" and never "nothing exists". QUOTA: 1 token per DELIVERED result from your plan balance (free starter: 500 tokens lifetime; paid plans: 40,000/month; short pages auto-refund — you pay only for results you receive). Default page is 20 results = 20 tokens; pass limit (1–200) to size it. get_usage is free. Autonomous agents must be linked to a spytrend account to access data — an unlinked agent gets an actionable connect-your-account refusal (create agent credentials at spytrend.com/settings?tab=ai, or a human claims it by client_id), NOT a server error. Calls are rate-limited per authenticated user (deployment defaults: 60/minute and 1000/hour); a rate-limit refusal is an MCP tool error with structured error.code=rate_limit_exceeded, scope, window and retry_after_seconds. CONCURRENCY: heavy analytical calls (get_trends, search_ads, search_creatives) are admitted ONE AT A TIME per account — fanning out 5-10 of them in parallel does not go faster, it returns admission refusals for all but one. Issue heavy calls sequentially; light lookups (get_ad, get_advertiser, get_usage) are not gated.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
hubsNoadvertisers: filter by hub/destination
modeNoscaling signal (dimension=scaling only): exploding, early_signal, revival, new or all. Omitted = all signals (the recommended base for custom threshold rules — run min_growth/min_new_ads/… across every signal); the SITE's default tab is exploding, so pass mode='exploding' to mirror it.
limitNomax rows to return (default 20; each delivered row costs 1 token). Ignored for geo_timeline: that dimension has no pagination and returns every populated date×country point in the accepted window while charging only the requested page size.
formatNocreative format filter
offsetNoscaling: pagination offset — skip the first N rows (use with limit to page through results).
statusNostatus filter: active or inactive. NOTE: 'vanished' is honored for ads/webmasters but NOT for dimension=advertisers (no advertiser-level vanished concept — use life_status for advertiser liveness).
born_toNoadvertisers: page founded on or before this date (YYYY-MM-DD)
countryNosingle ISO country code filter (legacy form). Prefer countries[] for UI parity and multi-market requests; geo_timeline also accepts up to 200 comma-separated uppercase ISO-2 codes here, and omission means all geos
date_toNoend date YYYY-MM-DD; for geo_timeline supply together with date_from (both omitted = latest 30 days), max 31 inclusive days for all geos or 90 for a country subset
signalsNoscaling tag classifier version: v2 = honest acceleration (base ≥3 ads over prior 3 days, growth vs 3-day average) and early_signal = fresh multi-account rollout ≤72h; default v1 (the current site behavior)
sort_byNocolumn to order the ranking by (dimension-specific, e.g. total_ads). NOTE on ranking: for dimension=advertisers, when a country/ai_category/hub filter is active the RELEVANT pages (smoothed concentration share >= 0.3 in the filtered vertical/geo) come first as a bucket, ordered INSIDE by the honest sort_by column desc — so the printed numbers descend within the relevant bucket and a metric top-N IS collectable; below the bucket sit low-share pages in the same column order. sort_by=active_ads orders by the geo-scoped active value the row displays; sort_by=coverage ranks purely by concentration. For dimension=scaling, sort_by accepts: growth (default), score (composite Spike-Score: a percentile blend of new-ad volume, base-honest growth multiplier, advertiser spread and freshness — each scaling row then also carries a spike_score 0-100), new_ads (most new ads yesterday — the today_ads metric), spread (widest advertiser spread — new fanpages), or freshness (newest creatives first by first_seen); sort_order is ignored (scaling always ranks DESC).
baselineNoscaling growth baseline: avg (default, window mean) or median (robust to a single outlier day). Affects the 3d/7d comparison window only; 1d is a no-op (single day). Default avg.
platformNoplatform name filter (e.g. facebook, instagram)
snapshotNoscaling: snapshot source — v2 (default, 8-day detection window, the LIVE site behavior), v4 (37-day spike window, first_parsed_date axis; a PREVIEW contour) or long (Tier-2 Long Trend, 126-day WEEKLY window). ONLY snapshot=v4 unlocks spike_window, comparison=14d/30d, baseline=weekday, advertiser_ids, landing_changed, min_window_advertisers, min_active_now and the active_series/active_now/window_* fields; on v4 the active-history series is YOUNG (read days_of_active_history first). snapshot=long is a DIFFERENT tier — long-term Trend Growth (recent 30d new-ad rate vs the prior 90d baseline, per WEEK), NOT a spike: it accepts ONLY min_trend_growth / min_recent_new / min_advertisers / ai_category / ai_subcategory / media_types / sort=trend_growth|velocity, returns weekly_series[18] + trend_growth + recent_new_28d + prior_new_91d + prior_weekly_avg + window_advertisers with tag='trend_growth', and REFUSES (422) any spike-only param. On long the spike counters (today_ads, growth_multiplier, daily_history, currently_active, active_series, delta_*) are NOT populated — hydrate active/geo numbers per creative via get_creative (creative_id is the representative ad id).
born_fromNoadvertisers: page founded on or after this date (YYYY-MM-DD)
countriesNoISO country codes to INCLUDE. Mirrors the /trends geo include picker, which is multi-select: pass several markets in one call instead of one call per country.
date_fromNostart date YYYY-MM-DD; for geo_timeline supply together with date_to (both omitted = latest 30 days), max 31 inclusive days for all geos or 90 for a country subset
dimensionYesone of: geo, geo_timeline, advertisers, webmasters, apps, timeline, scaling, domains. geo_timeline is the batched per-country daily NEW-AD flow; use geo for current per-country stock. For creative trends use scaling (exploding/winning creatives). For BRANDS use domains — it ranks landing domains, the closest thing to a brand the data holds (advertisers are fanpages, webmasters are networks).
same_textNoscaling (snapshot=v4 ONLY): keep ONLY creatives whose title/hook is the SAME EXACT text — pass a title_norm_hash (a UInt64 as a decimal STRING, from a row's text cluster). This is same EXACT text, NOT 'same angle' (no embeddings). Template/boilerplate text (liquid {{…}}, bare URLs, confirmed CTA like 'Chat with us') is excluded. Ignored on snapshot=v2.
verbosityNoresponse size control: omit for the full payload, or compact to drop heavy per-row nested structures (geo: lifetime/geo_distribution; geo_timeline: is_complete, which meta already states for the whole window; timeline: lifetime; scaling: geo_distribution/active_series/daily_history/weekly_series). meta.omitted_row_fields lists exactly what was dropped. Use it when you only need the shape of a market and the full payload would not fit your context.
comparisonNoscaling growth-comparison window: 1d, 3d or 7d. The numerator is always yesterday (d-1); the baseline is the average of that many prior COMPLETE days ending at d-2 — 1d = d-2, 3d = d-2..d-4, 7d = d-2..d-8 (a full seven days). Only these three presets exist on the default snapshot; 14d/30d require snapshot=v4.
date_basisNotimeline/geo date axis: fb_start (Facebook launch date — the honest axis for 'what the market launched', and the default here) or parsed (when Spytrend discovered the ad). ⚠️ The spytrend.com /trends page sends parsed by default, so to REPRODUCE a number a user sees on the site pass date_basis=parsed explicitly; the two axes differ because Spytrend also indexes older ads late.
media_typeNomedia type filter: image or video
min_growthNoscaling: minimum growth multiplier (today_ads ÷ prior-window average) — a FREE-FORM number, e.g. 2, 4.5 or 10 (not limited to x2/x5 presets). Omitted or 0 = NO growth threshold; the SITE's default is ×2, so pass min_growth=2 to mirror it.
sort_orderNosort direction: asc or desc
store_typeNoapps ONLY: store type (e.g. android, ios). Has NO effect on dimension=advertisers.
ai_categoryNoAI category slug filter (e.g. gambling_and_betting)
life_statusNoadvertisers only: page life status — alive, deleted or banned
max_new_adsNoscaling: at most N new ads yesterday — combine with min_new_ads for a band, e.g. 10..50. 0 / omitted = no upper bound.
min_new_adsNoscaling: minimum NEW ads yesterday — the today_ads metric on each scaling row — free-form integer (e.g. 8). 0 / omitted = no threshold.
creative_ageNoscaling: creative age bucket by first_seen — new (≤3 days), fresh (3-14 days), proven (14-60 days) or old (60+ days). A preset alternative to max_first_seen_hours; combine with it and both narrow. Omitted = no age filter.
spike_windowNoscaling (snapshot=v4 ONLY): spike window in days — 1, 2, 3 or 7. The growth numerator becomes the per-day average of NEW launches over the last W complete days (1 = yesterday, the v2 form). Does NOT change the tag chips (they stay on the fixed yesterday-vs-3-day window). Ignored on snapshot=v2.
webmaster_idNorestrict the ranking to ads of this webmaster/affiliate id (from search_webmasters). Mirrors the visible /trends webmaster dropdown. Not honored on rollup-backed dimensions — the response then reports it in meta.unsupported_filter instead of silently ignoring it.
first_seen_toNoonly ads spytrend first INDEXED on or before this date (YYYY-MM-DD) — internal discovery date, not the Facebook launch date; for 'new ads' questions use date_from/date_to. See first_seen_from for exact-total windows
followers_maxNoadvertisers: maximum page followers
followers_minNoadvertisers: minimum page followers
min_geo_shareNoadvertisers only: dominant-geo gate (0-1) — keep only advertisers whose share of ads in the selected country is at least this fraction (e.g. 0.5 = the country is >=50% of the page's ads). Requires country. Without it the country filter is a mere present-in match: a page with 25% of its ads in GB still ranks in the GB top . Share is computed from the page's total per-country ad distribution; a per-country ACTIVE slice is not tracked.
advertiser_idsNoscaling (snapshot=v4 ONLY): competitor filter — comma-separated advertiser UUIDs; keep only creatives run by ANY of them (hasAny). Invalid UUIDs are dropped; capped at 100. Ignored on snapshot=v2.
ai_subcategoryNoAI subcategory slug filter
min_active_nowNoscaling (snapshot=v4 ONLY): keep creatives with ≥ N ads active RIGHT NOW (active_now). 0 / omitted = no threshold (no default preset). Ignored on snapshot=v2.
min_recent_newNoscaling (snapshot=long ONLY): minimum recent_new_28d — new ads first seen in the last 28 days (the velocity numerator). 0 / omitted = no threshold. Ignored unless snapshot=long.
first_seen_fromNoonly ads spytrend first INDEXED on or after this date (YYYY-MM-DD) — an internal discovery date, NOT the ad's Facebook launch date. Do NOT use it for 'new ads recently' questions: spytrend also indexes OLD ads late, so late-indexed old ads would pollute the answer — use date_from/date_to (Facebook launch) for market newness. Exact totals: any closed window up to 31 days; a single-country request with only AI-category filters can use the canonical daily cube for up to 90 days or from this date through today
landing_changedNoscaling (snapshot=v4 ONLY): landing-page-change filter — any (default), same (one landing domain over the window), new (a new landing appeared) or multiple (2+ landings — affiliate/cloaking distribution). Ignored on snapshot=v2.
min_advertisersNoscaling (snapshot=long ONLY): minimum advertisers_total — unique advertisers that ran the creative over the 126-day window (market spread). 0 / omitted = no threshold. Ignored unless snapshot=long.
min_days_activeNoonly rows whose entity has ads running at least this many days
min_new_domainsNoscaling: minimum NEW webmasters/domains (new_webmasters) running the creative — the domain-spread signal, mirror of min_new_accounts — free-form integer (e.g. 3). 0 / omitted = no threshold.
min_text_spreadNoscaling (snapshot=v4 ONLY): keep creatives whose EXACT text is shared by ≥ N families (the text-spread market signal — 'this script is being copied by N families', doc §16.5). Only non-template text counts. Each returned row also carries text_spread (families sharing its text) when ≥2 and non-boilerplate. 0 / omitted = no threshold. Ignored on snapshot=v2.
min_new_accountsNoscaling: minimum NEW accounts (new advertiser fanpages) running the creative — free-form integer (e.g. 6). 0 / omitted = no threshold.
min_trend_growthNoscaling (snapshot=long ONLY): minimum trend_growth — (new ads over the last 30d ÷ 4 weeks) ÷ (new ads over the prior 90d ÷ 13 weeks), i.e. the recent per-week new-ad rate vs the baseline per-week rate. Free-form float (e.g. 1.5, 2, 3); >1 = sustained growth. 0 / omitted = no threshold. Ignored unless snapshot=long.
exclude_countriesNoISO country codes to EXCLUDE — drops rows whose ads target ANY of them. Mirrors the /trends geo EXCLUDE column. Honored on timeline (and the webmaster-scoped path); NOT applicable to geo_timeline, whose rows are per-country cube aggregates rather than per-ad geo arrays — that response names it under meta.ignored_filters instead of pretending it ran.
min_category_shareNoadvertisers only: vertical-share gate (0-1) — keep only advertisers whose share of ads in the selected ai_category/ai_subcategory is at least this fraction (e.g. 0.2). Requires ai_category or ai_subcategory. Without it the category filter is a presence match: a travel agency with 4% of its ads in gambling still ranks in the gambling top. Share is the same number as the category percentage shown on the advertiser card.
max_first_seen_hoursNoscaling: keep only creatives first seen within the last N hours — your own freshness window (the 'new' preset is fixed at 48h; this is free-form, e.g. 24 or 72).
min_window_advertisersNoscaling (snapshot=v4 ONLY): market-trend threshold — keep creatives with ≥ N unique advertisers over the 37-day window (the 'spreading across the market' signal, doc §16.5). 0 / omitted = no threshold. Ignored on snapshot=v2.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
dataNo
metaNo
errorNoPresent only when isError is true: machine-readable failure. The human explanation stays in content.
totalNo
offsetNo
paramsNoRequest parameter echo: applied = parameters that shaped this result; normalized = parameters rewritten before applying (alias, type coercion, resolved id); ignored = parameters that were accepted but NOT applied, with the reason.
has_moreNo
snapshotNo
total_statusNo
weeks_of_historyNo
days_of_active_historyNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changed
    • addedOutput schema / properties / error
      Added value: +{
      +  "description": "Present only when isError is true: machine-readable failure. The human explanation stays in content.",
      +  "properties": {
      +    "code": {
      +      "description": "fine-grained, stable failure code (e.g. invalid_arguments, backend_busy)",
      +      "type": "string"
      +    },
      +    "kind": {
      +      "description": "failure class: invalid_argument, not_found, permission_denied, unauthenticated, quota_exceeded, rate_limited, temporarily_unavailable, unavailable_until_ready, unsupported, internal",
      +      "type": "string"
      +    },
      +    "message": {
      +      "description": "the same human text as content[0]",
      +      "type": "string"
      +    },
      +    "outcome": {
      +      "description": "activity-feed outcome class",
      +      "type": "string"
      +    },
      +    "param": {
      +      "description": "the request parameter the failure is about, when known",
      +      "type": "string"
      +    },
      +    "retry_after_seconds": {
      +      "description": "wait this long before retrying",
      +      "type": "integer"
      +    },
      +    "retryable": {
      +      "description": "true when repeating the SAME call can succeed (after retry_after_seconds when present)",
      +      "type": "boolean"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / params
      Added value: +{
      +  "description": "Request parameter echo: applied = parameters that shaped this result; normalized = parameters rewritten before applying (alias, type coercion, resolved id); ignored = parameters that were accepted but NOT applied, with the reason.",
      +  "properties": {
      +    "applied": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "ignored": {
      +      "items": {
      +        "properties": {
      +          "param": {
      +            "type": "string"
      +          },
      +          "reason": {
      +            "type": "string"
      +          },
      +          "to": {
      +            "description": "the parameter it was applied as, when renamed",
      +            "type": "string"
      +          },
      +          "value": {
      +            "description": "the value actually applied, when rewritten",
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "normalized": {
      +      "items": {
      +        "properties": {
      +          "param": {
      +            "type": "string"
      +          },
      +          "reason": {
      +            "type": "string"
      +          },
      +          "to": {
      +            "description": "the parameter it was applied as, when renamed",
      +            "type": "string"
      +          },
      +          "value": {
      +            "description": "the value actually applied, when rewritten",
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "type": "object"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "data",
      -  "total"
      -]
  2. Changed1 schema field changed
    • addedInput schema / properties / min_category_share
      Added value: +{
      +  "description": "advertisers only: vertical-share gate (0-1) — keep only advertisers whose share of ads in the selected ai_category/ai_subcategory is at least this fraction (e.g. 0.2). Requires ai_category or ai_subcategory. Without it the category filter is a presence match: a travel agency with 4% of its ads in gambling still ranks in the gambling top. Share is the same number as the category percentage shown on the advertiser card.",
      +  "type": "number"
      +}
  3. Changed1 schema field changed
    • changedInput schema / properties / date_basis / description
      Previous value: -"timeline/geo date axis: fb_start (Facebook launch date — the honest axis for 'what the market launched', and the default here) or parsed (when SpyTrend discovered the ad). ⚠️ The spytrend.com /trends page sends parsed by default, so to REPRODUCE a number a user sees on the site pass date_basis=parsed explicitly; the two axes differ because SpyTrend also indexes older ads late."New value: +"timeline/geo date axis: fb_start (Facebook launch date — the honest axis for 'what the market launched', and the default here) or parsed (when Spytrend discovered the ad). ⚠️ The spytrend.com /trends page sends parsed by default, so to REPRODUCE a number a user sees on the site pass date_basis=parsed explicitly; the two axes differ because Spytrend also indexes older ads late."
  4. First observed

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, openWorldHint=true, destructiveHint=false; the description adds substantial behavioral context beyond that: 1-token-per-result quota, rate limits, one-at-a-time heavy-call admission, free-plan 6-row previews, pagination semantics, and refusal behavior for unlinked agents. There is no contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded: purpose and dimension semantics come first, followed by clearly grouped quota, free-plan, rate-limit, and concurrency notes. The 'FREE PLAN COUNTS' paragraph appears twice almost verbatim, which is a small redundancy; otherwise the length is justified by the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers dimension choice, filter families, pagination, quota, auth linking, rate limits, concurrency, media URL behavior, and plan-specific limitations. With a rich output schema already present, no critical operational context needed to call the tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema descriptions are already rich, so the baseline is 3; the description adds cross-parameter meaning with the common filter list, dimension-specific semantics, page-size differences, and plan restrictions. It deliberately defers per-dimension row semantics to meta.dimension_semantics at runtime, which is a reasonable handoff rather than a gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Get aggregated trend rankings for a dimension' with an explicit dimension list. It distinguishes itself from siblings by saying 'Use for rankings/aggregates, NOT to list individual ads (use search_ads)' and by noting media assets should be fetched via get_media.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use guidance: rankings/aggregates vs individual ads, dimension selection rationale, and cross-tool routing to search_ads and get_media. Also covers plan-specific constraints, rate limits, and concurrency rules, so an agent knows both the intended use and the operational boundaries.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.