Account data tools
These tools cover the property-scoped surface of the MCP server: your own private data, one brand at a time. Every one on this page is read-only except add_pitch_list_publishers, which adds publishers to a pitch list, and all of them are gated by your membership: the server checks that your signed-in account can access the property (or organization) before returning anything.
Almost everything here starts from a propertyId, so the first call in any account session is list_properties. (The account surfaces that aren't property-scoped are bulk placement scoring, which starts from an organizationId and writes, and organization-level pitch lists.)
Many of these tools return numeric series over time. Nothing is charted server-side — the assistant builds any visualization from the returned data. Just ask for "a chart of share of voice over the last 90 days" and it will.
Discover your properties
list_properties
Lists the properties (brands / sites) on your account, each with its organization and your role. Use a returned id as the propertyId for every other tool on this page.
| Parameter | Type | Notes |
|---|---|---|
organizationId | string (optional) | Restrict to one of your organizations. |
includeProspects | boolean (optional) | Include bulk-imported prospect properties (default false). |
Projects
Projects are bundled, time-bound tracking efforts (an SEO push, a PR campaign). See the Projects dashboard for the concept.
list_projects
Lists a property's projects with each one's type, status, date range, goals, and counts. A returned id is also the projectId argument on get_metrics_history, get_competitor_share_of_voice, get_answer_drilldown and get_answer_summaries, which scopes any of them to that project's prompts.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
status | ACTIVE | COMPLETED | ARCHIVED (optional) | Filter by status. |
get_project_insights
A project's deep insights, matching its exported report: metric deltas from start to now (consistency, share of voice, mentions, owned citations, owned citation rate, and cumulative goal citations), a weekly trend series (including weekly goal hits), goals with their first-hit details plus hit counts and influence rates (the share of the project's citations each tracked publisher/article/author/coverage group accounts for), the annotation timeline, key insights, and next steps.
| Parameter | Type | Notes |
|---|---|---|
projectId | string | From list_projects. |
Project-level deltas and weekly trends come from get_project_insights. Property-wide history (not scoped to a project) comes from get_metrics_history below.
The four shared filters
Four tools take the same slice arguments, and they mean the same thing in each: stage (awareness / consideration / decision), platform, tag (a prompt tag), projectId, plus locationPropertyId for one tracked market. The tools are get_metrics_history (trend), get_competitor_share_of_voice (ranking), get_answer_drilldown (one day's prompts and answers) and get_answer_summaries (one prompt's wording week by week). So "share of answers on Perplexity, decision stage, for the pricing tag" is one question you can follow from the trend line down to the raw answer.
Resolve the values first: tags from list_prompt_tags, project ids from list_projects, location ids from list_locations. An id that belongs to another property is rejected, not silently ignored, because a filter that matches nothing returns an empty slice that reads like "nothing happened".
Every filter slices the numerator and the denominator together, so a sliced share is a real share of that slice. Two rules follow. Tag slices overlap (one prompt can carry several tags), so per-tag numbers do not sum to the property total. And an empty slice is empty: no answers landed in it. It is never a reason to call again without the filters and present those numbers as the answer to the sliced question.
Historical trends
get_metrics_history
A property's AI visibility metrics over time, one point per report or prompt-tracking run: share of voice, mentions, citations, citation rate, and per-platform breakdowns.
Pass stage and/or platform to add a slice to every point: the stored stage-scoped cell for that combination, or the consideration + decision headline when only a platform is given. A slice of null is a day whose stored row carries no cell for that combination: unknown for the slice, never zero, and never the brand-wide total standing in for it.
Pass a tag to get a theme-scoped series instead: one point per UTC day, each with per-stage mentions, opportunities and share of voice for that tag, plus the day's headline (which narrows to your stage when you pass one). stage and platform combine with it.
Pass a projectId to scope the whole discovery series to that project's prompts (recomputed live from the source answers, the same way the dashboard's project filter does it) and to get the grounding-search ranking trend for the project's tracked queries alongside. That recompute is brand-wide, so projectId and locationPropertyId cannot be combined; ask for one or the other. Project-level deltas and weekly trends come from get_project_insights.
Everything in discovery is the focal subject's number. A CATEGORY property tracks a market with no focal brand, so this series measures a subject that does not exist and sits at zero from end to end. The payload's focalSubject field says so explicitly. For the market's own trend use get_competitor_share_of_voice with includeSeries: true; for the prompts and answers behind one day use get_answer_drilldown.
An empty tag slice means no tagged data existed on those days, not that brand activity was zero. A tag added last week has nothing before then; read that as "no data", never as a drop.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
projectId | string (optional) | Scope the discovery series to this project's prompts and add its grounding-search trends. Cannot be combined with locationPropertyId. |
tag | string (optional) | Return the tag-scoped daily series instead of the brand-wide one. Tags come from list_prompt_tags. |
stage | awareness | consideration | decision (optional) | Narrow every point to one funnel stage. Works with and without tag. |
platform | string (optional) | all, chatgpt, gemini, perplexity, claude, or googleAiOverview. Works with and without tag. |
locationPropertyId | string (optional) | Scope to one LOCATION child of this property. Ids come from list_locations; anything else is rejected. |
startDate / endDate | string (optional) | ISO date bounds. |
limit | number (optional) | Max points when no date range is given (default 30, max 100). |
list_prompt_tags
The tag vocabulary for a property: the free-form tags on its tracked prompts, plus their categories and use-cases. Call this before slicing anything by theme: a tag that does not appear here returns an empty slice. The same tags are the tag argument on get_metrics_history, get_competitor_share_of_voice, get_answer_drilldown and get_answer_summaries.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
get_answer_drilldown
The L3 drill-down behind the visibility dashboard. For one UTC day it returns the raw prompt text of every tracked prompt that ran in scope, and for each prompt every platform execution: which model answered, the tracked brands that answer named (brandsNamed), the focal brand's mention flag and rank, and its citation counts. Totals reconcile exactly with the same day's point from get_metrics_history for the same scope. This is how you answer "why did share of voice move on this date?".
Check hasFocalSubject first. When it is false the property tracks a market with no focal brand, so totals.mentions, every execution's mentioned and every rank are computed against nothing. Narrating "0 mentions" there is simply wrong. The finding is brandTotals: each tracked brand's answersNamedIn, promptsNamedIn and shareOfAnswers over exactly this slice, ranked. Those shares do not sum to 100, because one answer can name several brands.
brandName puts one brand under a lens, not a filter: no prompt is removed, every execution gains namedFocusedBrand (null means that execution produced no answer), and focusedBrand summarizes it, with tracked: false when the name matches none of the property's tracked brands. "Which answers named Roborock" is only answerable beside the ones that did not.
Raw answer text: pass a queryId from this tool's own prompts list and the response gains an answers block: that prompt's answers for the day, one entry per platform, each with the full text (capped at 6,000 characters, with answerTextTruncated saying when it was cut), the brands it named, and up to 25 citations. get_answer_summaries returns one prompt's answers uncapped and week by week instead.
If the day has no completed run (or falls outside the tracked range) the call reports that rather than returning zeros; pick a date that appears in get_metrics_history.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
date | string | The UTC day to explain, YYYY-MM-DD. |
stage | awareness | consideration | decision (optional) | Restrict to one funnel stage (default: all three). |
platform | string (optional) | all, chatgpt, gemini, perplexity, claude, or googleAiOverview. |
tag | string (optional) | Only prompts carrying this tag. |
locationPropertyId | string (optional) | Scope to one LOCATION child. Ids come from list_locations; anything else is rejected. |
projectId | string (optional) | Only prompts assigned to this project. Ids come from list_projects; anything else is rejected. |
brandName | string (optional) | Put one tracked brand under a lens. Never removes prompts. |
queryId | string (optional) | Also return that one prompt's full answer text for the day. |
get_site_consultations
How often AI platforms consulted one specific site directly — a site:acme.com … grounding search — instead of searching the open web, split into your own site, tracked competitors, and third parties, for a window and the window immediately before it.
A scoped search means the model had already decided where the answer lives. Consulting your site is an authority signal; competitors consulted while you get none is the absence of one. See the Brand Dashboard for the concept and the in-app drill-down.
The payload has two halves on different bases, and they are not meant to reconcile. The headline counters — current, previous, delta, consultRate, byPlatform, byFunnelStage — exclude brand_identity and brand_comparison prompts, because a prompt that names the brand is expected to send the model to its site and counting it would be circular. The domains evidence rows include them, so a domain row's count can exceed what the headline counters imply.
consultRate is normalized per execution, not per search: consultedExecutions / totalExecutions, the share of answers that searched at all in which the model consulted your site. One answer can fan out into a dozen searches, so a chatty platform cannot inflate it.
Each domains row carries the bare hostname, its class (own / competitor / third_party), the competitor it belongs to where relevant, the consultation count, the platforms that consulted it, when it was last seen, and residualQuery — the topic searched, with the site: operator stripped (empty for a bare site:acme.com, which reads as "just go read their site").
A third_party row with brandAffine: true is a suspected wrong domain: one that looks like the brand's but isn't. That is the signal the wrong-domain alerts fire on. Treat it as a lead — the domain may be real and holding authority that should be yours, or it may serve nothing at all — never as a settled fact.
The domains list is capped at the 50 most-consulted; domainsTotal gives the full count so a truncated list is never mistaken for the whole inventory.
This tool counts only searches carrying the site: operator. A search that consults a brand by naming it (CompetitorX pricing) is a different thing and does not appear here — it has no scoped domain to attribute. Those searches are still excluded from SERP checks and gap opportunities everywhere else, on the grounds that nothing you publish can rank for a question about a competitor's product; see list_tracked_fanouts.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
days | number (optional) | Current window length in days (default 7, max 90). The previous window is the same length immediately before it — the pair delta compares. |
locationPropertyId | string (optional) | Scope to one LOCATION child of this property. Ids come from list_locations; anything else is rejected. |
Good in a weekly summary or digest alongside get_metrics_history — pass days: 7 and narrate current against previous using delta.
get_consistency_history
A property's brand-consistency score over time (overall and per platform) — how consistently AI platforms describe the brand vs. its source-of-truth identity.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
startDate / endDate | string (optional) | ISO date bounds. |
limit | number (optional) | Max points (default 30, max 100). |
Locations and competitors
list_locations
Per-market AI share of voice for a brand's tracked locations (its LOCATION child properties). Each entry carries the market's city / region / country and its latest measurement — share of voice, mentions, citations, citation rate, and the measurement date — alongside a rollup.
averageSov is equal-weighted across the markets that have data: a "typical market" number that treats a small market and a large one alike. It deliberately will not match the brand-wide share of voice from get_metrics_history, which pools every answer. Feed a returned id back as locationPropertyId to scope get_metrics_history, get_competitor_share_of_voice, get_answer_drilldown or get_answer_summaries to that one market; an id that is not this property's own location is rejected. A brand with no tracked locations returns an empty list, not an error.
Each market also carries leader — the brand AI named most often there in that same measurement, as a name and a shareOfVoice — or null when the market has no competitor data yet. For a CATEGORY parent, which tracks a market with no focal brand and therefore has no share of voice of its own, leader is the only ranking the row carries.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | The parent property id, from list_properties. |
get_competitor_share_of_voice
The ranked share of answers for the brands AI names, over a window you choose and any slice of it. For a CATEGORY property the same tool ranks the market's tracked brands, which the product calls Brands rather than competitors.
The ranking is pooled over the window: each brand's share is the answers that named it divided by the answers analyzed across every measured day in the window. It is not read off the latest measurement, because a single night is a handful of answers per brand and reorders on noise. The default window is 7 days; pass windowDays: 30 or 90 for a steadier order.
shareOfVoice is a share of answers and it does not sum to 100 across brands, because one answer can name several of them. answersNamedIn is a brand's numerator; the snapshot's answersAnalyzed is the denominator every row shares. shareOfAnswersDelta compares this slice with the window of equal length immediately before it, in percentage points, and is null (never 0) when that earlier window held no answers in the slice.
Each brand also carries totalCitations, queriesAppeared and gapQueriesCount, the prompts where the brand appeared and the focal subject did not, which is the acquisition gap worth acting on. Those three are not slice-scoped: they come from the latest whole measurement and ignore every filter, so label them as whole-measurement numbers or leave them out of a filtered answer.
How to read the rest of the payload:
empty: true: the slice was measured and held no answers. Report the empty slice.thin: true: fewer than 20 answers landed in it, so the order is unstable. Widen the window before ranking anything on it.basis: "latest_row": the window carries no stage-scoped history, so no filter could be honored. The figures are the latest single measurement as stored,answersAnalyzedis0andseriesis empty. Say that rather than presenting them as a filtered answer.daysWithDimensionbelowdaysMeasuredunder a platform or tag filter: the remaining days never recorded that detail. QuotedimensionStartDate("platform and tag detail starts on that date") instead of a share that silently undercounts them.brandShareOfAnswers/brandAnswersNamedIn/brandShareOfAnswersDeltaare the focal subject's side of the same slice. Top-levelbrandShareOfVoiceis the unsliced latest-measurement figure, so the two are not comparable.headlinepools the consideration and decision stages of the same window (narrowed to your stage when you pass one), which is the definition the brand dashboard's share-of-voice hero uses. It isnullfor properties whose data predates stage scoping; never mix it with the top-level figures inside one ranking.
For a CATEGORY property every focal-subject figure is null by design: brandShareOfVoice, brandShareOfAnswers, brandAnswersNamedIn, brandPreviousShareOfAnswers and brandShareOfAnswersDelta. A zero would read as "this market is invisible" rather than "there is no subject here". Each brand's gapQueriesCount then equals its queriesAppeared, which is correct: every prompt a brand appeared in is one the absent subject did not.
includeSeries: true adds series, the per-day line for the slice's top 6 brands, in table order, for charting. A point with hasDimension: false is a day that recorded no platform or tag detail: break the line there, never plot it as 0. The series is omitted by default to keep an ordinary call small.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
windowDays | 7 | 30 | 90 (optional) | Days to pool the ranking over (default 7). |
stage | awareness | consideration | decision (optional) | One funnel stage (default: all three pooled). Also narrows headline. |
platform | string (optional) | chatgpt, gemini, perplexity, claude, or googleAiOverview. |
tag | string (optional) | One prompt tag, from list_prompt_tags. |
projectId | string (optional) | Restrict to one project's prompts, recomputed live. Ids come from list_projects; anything else is rejected. |
locationPropertyId | string (optional) | Rank inside one tracked market. Ids come from list_locations; anything else is rejected. |
includeSeries | boolean (optional) | Add the per-day series for the slice's top brands (default false). |
get_recommendation_categories
How AI recommends your brand and every other brand it names, read from your daily tracking answers only. AI Visibility reports are not included. For each answer to a discovery prompt, Spyglasses classifies every brand the answer names, tracked or not, into one of four categories:
- Top choice: the answer singles the brand out as its pick or its explicit top recommendation.
- One of many: the answer recommends the brand alongside others, often with a note on who it is best for.
- Generic mention: the answer names the brand without evaluating or recommending it.
- Cautioned against: the answer steers this buyer away from the brand, usually for a stated reason such as price or complexity.
Each brand in each answer also comes with the caveats the answer gives (a reason type, a short reason and the audience it applies to) and a short quote from the answer.
The payload has two families of numbers, and they answer different questions. Rates in summary are per answer, for your brand: topChoice is the percent of answers in the slice that name you as AI's pick, and answers that never name you are in the denominator (notMentioned). Shares in leaderboard are across every brand AI named, including brands you don't track: sharePct is a brand's recommendations (top choice plus one of many, with a top choice counted once) out of all brands' recommendations, so the column adds up to 100 with the Other row. cautionedRatePct in the leaderboard is a per-answer rate, not a share.
How to read the rest of the payload:
hasAssessedAnswers: false: daily tracking has not produced classified answers yet. Say it is not set up, not that the brand scored zero.- An answer count of
0is an empty slice.isEarlyRead: truemeans fewer than 30 answers, so treat the rates as directional. summary.previousandoverview.previoushold the window of the same length just before this one. Each isnullwhen your history does not reach back a full window. When history reaches back but nothing ran in that window (a new project, for example),previousreports0answers. In both cases the deltas (deltaPoints) arenull, never0, so there is no change to report.reasonslists why AI steers buyers away (cautioned-against answers only), grouped by reason type, with the audience each reason applies to.isNewmarks a reason that did not appear in the previous window.bestForlists who AI says you are best for when it recommends you.citedNotRecommendedcounts answers that cite one of your own pages but leave you out of the recommendations.unclassifiedcounts answers where a tracked brand was named but not rated. It is rare and is not a verdict.isTrackedis worked out when you ask, so a brand you start tracking today shows its full history right away.
A CATEGORY property tracks a market with no focal brand, so summary and bestFor are null by design and reasons covers every brand. Rank the leaderboard instead.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
windowDays | 7 | 30 | 90 (optional) | Days of daily tracking to read (default 7). Changes compare with the window of the same length just before it. |
stage | awareness | consideration | decision (optional) | One funnel stage (default: all three). |
platform | string (optional) | chatgpt, gemini, perplexity, claude, or googleAiOverview. |
tag | string (optional) | One prompt tag, from list_prompt_tags. |
projectId | string (optional) | Restrict to one project's prompts. Ids come from list_projects; anything else is rejected. |
locationPropertyId | string (optional) | One tracked market. Ids come from list_locations; anything else is rejected. |
personaId | string (optional) | Read the answers asked as this persona instead of the baseline. Ids come from list_personas; anything else is rejected. Persona answers run on the parent property only. |
topN | number (optional) | Brands listed before the rest fold into Other (default 8). Your own brand is always listed. |
includeTrend | boolean (optional) | Add your brand's top-choice and cautioned rates by day or by week (default false). |
Personas
Every discovery prompt on a project with personas also runs daily as each persona: the same question, with the persona's one-line description in front ("I'm the CFO at a 120-person B2B SaaS company in the US; we run NetSuite and HubSpot…"). Persona answers run on your AI platforms except Google AI Overviews, which is a search query with no asker. They never change your headline metrics: every other tool reads the baseline answers, asked with no persona.
list_personas
A property's buyer personas. Each comes with a role-first label (for example "CFO, early-stage startup"), its fields (role group, seniority, decision role, segment, company size, industry, region, tech stack, priorities and constraints), contextText (the exact description sent in front of each question), its version (it goes up when that text changes) and the projects it is on. Only personas on an active project run.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
includeArchived | boolean (optional) | Include archived personas (default false). |
get_persona_lens
How AI answers each buyer compared with the baseline: the same prompts and platforms asked with no persona, over the same window. Each row is one persona, or a group of personas that share a role group, segment, company size or seniority. For each row and each lens brand (your brand, your tracked competitors and the most-named untracked brands) you get:
- the persona's rates in percent (mention, top choice, recommended, cautioned against) and the baseline's;
deltaPoints, the difference, withdeltaIntervalPoints(its 90% interval) andclear, true when the difference is larger than its interval;inBuyerStack, true for a brand the persona says it already uses.
Each row also has whoAiRecommends: each brand's share of the recommendations AI gave this buyer (untracked brands included, adding up to 100 with Other), next to the same brand's baseline share.
Persona samples are small. A row marked thin has fewer answers than thinThreshold, so treat it as directional, and only call a difference real when clear is true. pending means the persona is on a project but its first answers have not arrived yet. Answers often repeat the tools a buyer already uses; inBuyerStack marks those brands so a restated tool is not read as a recommendation.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
windowDays | 7 | 30 | 90 (optional) | Days of daily tracking to read (default 30). |
platform | string (optional) | chatgpt, gemini, perplexity or claude. |
projectId | string (optional) | One project's prompts and personas. Ids come from list_projects; anything else is rejected. |
groupBy | persona | roleGroup | segment | companySize | seniority (optional) | One row per persona (default), or one per shared attribute. |
includeArchived | boolean (optional) | Include archived personas (default false). |
Brand & comparison prompts
Prompts typed brand_identity ("What is [brand]?") or brand_comparison ("[brand] vs [competitor]") always mention the brand, so they are excluded from share of voice and measured by these two tools instead.
get_brand_prompt_health
Per-prompt health metrics for brand/comparison prompts, one row per prompt per day: expected-message coverage (% of the prompt's "should appear" messages found in answers), unwanted-message incidence (% of answers containing a "should not appear" message — lower is better), and theme drift.
Drift is 0–1 against the prompt's trailing 28-day theme pool: 0 means today's answers cover the same themes as the recent past; 1 means an entirely new story. Each row includes the day's themes, the novelThemes driving the drift (themes with no close match in the pool), and a messageBreakdown showing each expected message's per-day match count and a sample matched sentence — so you can say which messages appeared and what shifted, not just the aggregate numbers.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
queryId | string (optional) | Restrict to one prompt. |
startDate / endDate | string (optional) | ISO date bounds. |
limit | number (optional) | Max rows when no date range is given (default 60, max 200). |
get_comparison_verdicts
Aggregated head-to-head outcomes from brand_comparison prompts: per compared brand and day, how often answers favor it, what they favor it for (topFavoredFor — "agencies", "multi-language teams"), the verdict shapes (clear_winner, segmented_winners, no_verdict, list_only), the latest framing summary from an answer that compared that brand, and frequency-ranked strengths/weaknesses the answers attribute to it. isOurBrand marks the property's own brand.
Each row also carries a derived favoredRate (0–100, one decimal) — favoredCount / totalComparisons for that row.
Read both counts carefully. Favored counts are not zero-sum: a segmented answer ("X for agencies, Y for in-house teams") favors several brands at once, so per-brand favored counts can each exceed half the total and the rates across brands can sum past 100. And totalComparisons is the day's count of comparison answers, shared by every brand row for that day — it is not that brand's own sample size.
brand is alias-aware: pass a tracked competitor's name and rows recorded under any of its aliases are included too, because stored rows key on whatever name the answer used. A name that matches no tracked competitor is still accepted as a raw compared-brand name.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
brand | string (optional) | Restrict to one compared brand (case-insensitive; matches a tracked competitor's name or any alias, or a raw compared-brand name). |
projectId | string (optional) | Re-aggregate over this project's comparison prompts only, instead of all of the property's. |
startDate / endDate | string (optional) | ISO date bounds. |
limit | number (optional) | Max rows returned (default 100, max 400) — applied to date-ranged reads too. |
Message tracking and drift
These two pair together: one shows how often your key messages get pulled through, the other shows how the wording changes.
get_message_tracking
How often each tracked key message is pulled through into AI answers over time — a mention rate per message, plus first/latest values and the change. Good for a per-message trend chart.
Filter by tags and/or sentiment. Tags plus sentiment: NEGATIVE is the crisis-monitoring cut: the messages you never want AI to repeat, and whether it is repeating them — a rising rate there is bad news, the inverse of every other metric on this page.
Key-message tags are a separate namespace from prompt tags. They live on the messages, not on the prompts, and teams usually mirror the names by convention — but a tag from list_prompt_tags may not exist here, and vice versa.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
tags | string[] (optional) | Only messages carrying at least one of these key-message tags (e.g. ["crisis"]). |
sentiment | POSITIVE | NEGATIVE | NEUTRAL (optional) | Only messages with this polarity. NEGATIVE = "should not appear" messages. |
startDate / endDate | string (optional) | ISO date bounds. |
get_answer_summaries
The full answer text AI platforms gave for one tracked query, bucketed by week (one representative answer per week per platform). Compare weeks to narrate how the AI's description of the brand shifts. Omit query to first list the property's tracked queries, then call again with the one you want.
tag, stage, projectId and locationPropertyId narrow the candidate prompts before anything is read, so the list you pick from is already the slice and the filters are never applied to a truncated result. stage maps each prompt's type to its funnel stage the same way every other tool does, which puts brand_identity prompts in awareness and brand_comparison prompts in decision.
Answer text is returned in full here, with no cap. get_answer_drilldown returns a capped version of the same day's answers alongside the prompts that produced them.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
query | string (optional) | A tracked query (exact or substring). Omit to list available queries. |
platform | string (optional) | openai, claude, gemini, perplexity, or google_ai_overview. |
tag | string (optional) | Only prompts carrying this tag, from list_prompt_tags. |
stage | awareness | consideration | decision (optional) | Only prompts whose type maps to this funnel stage. |
projectId | string (optional) | Only prompts assigned to this project. Ids come from list_projects; anything else is rejected. |
locationPropertyId | string (optional) | Only answers from one LOCATION child's runs. Ids come from list_locations; anything else is rejected. |
maxWeeks | number (optional) | Most-recent weeks to return (default 12, max 52). |
startDate / endDate | string (optional) | ISO date bounds. |
See the Key Messages dashboard for the concept behind both.
Citation intelligence
get_citation_intelligence
A property's citation intelligence: the mix of sources AI cites, broken down by media type, authority type, content format, and page type; per-platform stats; a historical trend (citation mix over time); and the top citation sources by owner (brand / competitor / third-party). Use the historicalData series to chart how the mix shifts.
The summary also includes the cited-vs-evaluated split (citationTypeBreakdown — sources referenced in the answer text vs merely fetched while composing it) and earned-media rollups (earnedMedia — third-party sources whose fetched page content mentions the brand, including hidden earned media that never surfaces in answer-text attribution). Each top source carries contentMentions: brands found in its pages' content, distinct from answer-text brandMentions.
For "what would this filter give me?" questions, facetCounts holds per-dimension value counts computed with that dimension's own filter lifted (so media type, authority type, content format and platform compose instead of zeroing each other out), and facetTotals holds the same tallies with all four lifted.
facetPublisherCounts holds the same facet-excluded tallies counted in distinct publishers instead of citations, and facetPublisherDistinct gives the distinct publisher total for each dimension (one publisher can appear under several values, so the values can add up to more). Each top source also carries platformCitations, its citations split by platform, and summary.answerCount is the number of distinct AI answers behind totalCitations.
For a category property (a tracked market with no focal brand) nothing is "our brand": earnedMedia is always zero, no source has mentionsOurBrand, and contentMentions only lists the tracked brands.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
platform | string (optional) | Filter by platform, or all. |
contentFormat | string (optional) | |
mediaType | string (optional) | |
authorityType | string (optional) | |
brandAttributed | string (optional) | A brand name, _any_brand, or _unattributed — matches answer-text attribution. |
citationType | string (optional) | cited_inline, evaluated_source, search_result, or unclassified. |
mentionedBrand | string (optional) | A brand name, _our_brand, or _any_competitor — matches fetched page content, catching earned media the answer never attributes. |
startDate / endDate | string (optional) | ISO date bounds. |
See the Citation Intelligence dashboard for how these breakdowns are defined.
get_coverage_citations
For a coverage group (a list of earned-media placement URLs), the AI citations its URLs earned from the property's tracked prompts and reports. Answers "which prompt and platform cited my placement, and in what context?"
Returns a funnel (coverage URLs → cited by AI → cited inline), a cited-vs-uncited comparison (average AIPQS, word count, content age, byline share, top authors), per-URL rollups, and the individual citation hits — each with the prompt text, platform, model, date, citation type (cited_inline = referenced in the answer text, a true citation; evaluated_source = fetched but not referenced), and, for inline citations, the answer-text context around the reference.
Call without groupId to first list the property's coverage groups, then call again with the one you want.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string | From list_properties. |
groupId | string (optional) | A coverage group id. Omit to list available groups. |
url | string (optional) | Filter hits to one coverage URL (any variant — normalized). |
citationType | string (optional) | cited_inline (referenced in the answer — a true citation), evaluated_source (the AI read the page but didn't reference it), search_result (appeared in the AI's web search but wasn't picked up), unclassified, or all. |
platform | string (optional) | openai, claude, gemini, perplexity, or google_ai_overview. |
startDate / endDate | string (optional) | ISO date bounds on the citing answer's date. |
limit | number (optional) | Max citation hits to return (default 50, max 200). |
Counts here are scoped to your property's own tracked prompts and reports — the same numbers as the coverage group's citations page in the dashboard.
get_project_goal_citations
For a project goal, the citations behind its hit count — with each citation classified by brand relevance. Publisher (and author / page-group) goals match on the source, so their counts include citations unrelated to the brand; this tool separates them:
attributed— the answer credited the brand for this source by name, or (on Google AI Overviews) the overview mentions the brand while this source is in its list. AIO doesn't credit sources individually, so those hits carryattributedViaAio: true— treat them as strong-but-circumstantialcontent_mention— the cited page's fetched content mentions the brand, but the answer never credited it (hidden earned media; includes the mention context from the page)answer_mention— the answer mentions the brand somewhere, just not attached to this citationunrelated— the source matched on its own authority, and the answer never mentions the brand
Hits are scoped to the project window, so totals match the project page's goal counts exactly. Returns a breakdown (total / attributed / content mentions / hidden earned media / answer mentions / cited inline / unrelated) plus per-citation prompt, platform, model, date, citation type, and answer context. Call without goalId to list the project's goals with their citation counts, then call again with the one you want.
| Parameter | Type | Notes |
|---|---|---|
projectId | string | From list_projects. |
goalId | string (optional) | A goal id. Omit to list the project's goals. |
relevance | string (optional) | attributed, content_mention, answer_mention, unrelated, brand (attributed or content mention), hidden (content mention but not cited inline), or all. |
citationType | string (optional) | cited_inline, evaluated_source, search_result, unclassified, or all. |
platform | string (optional) | openai, claude, gemini, perplexity, or google_ai_overview. |
startDate / endDate | string (optional) | ISO date bounds on the citing answer's date. |
limit | number (optional) | Max citation hits to return (default 50, max 200). |
Pitch lists
A pitch list is a named list of publishers a PR team plans to pitch. A property list belongs to one brand; an organization list spans many, and each of its rows can name a brand or none. These three tools read pitch lists and add to them. add_pitch_list_publishers is the one tool on this page that writes.
list_pitch_lists
Lists the pitch lists on a property, or the organization-level lists on an organization. Pass one of the two ids. Use a returned id as the listId for the other two tools.
| Parameter | Type | Notes |
|---|---|---|
propertyId | string (optional) | From list_properties. Returns that property's pitch lists. |
organizationId | string (optional) | From list_my_organizations. Returns the organization-level pitch lists. |
get_pitch_list
One pitch list with its rows. Each row carries the publisher's domain and name, Est. Traffic, Domain Rank, status, note and, on organization lists, its brand; the AI citation counts for the window, split by platform; and a Placed suggestion when a scored placement for the brand exists on a publisher whose row is still Target or Pitched. The suggestion is only a suggestion: the status changes only when someone changes it.
Citation counts come from tracked brands' prompts and reports. On an organization list, a row with a tracked brand counts that brand's citations, a row with no brand counts citations across every tracked brand in the organization, and a row with a scoring-only brand has no count (it reads Not tracked in the app). Domain Rank is DataForSEO's third-party authority score and is not an input to AIPVS.
| Parameter | Type | Notes |
|---|---|---|
listId | string | From list_pitch_lists. |
window | number (optional) | Citation window in days: 30, 90, or 365. Defaults to 90. |
includeAipvs | boolean (optional) | Also return each publisher's AI Placement Value Score and tier, scored in the row's brand context (without brand context for rows that have no brand). |
limit | number (optional) | Max rows to return, in list order (default 200, max 500). The status and citation counts always cover the whole list. |
add_pitch_list_publishers
Writes. Adds publisher domains to a pitch list in your account. Name the list one of two ways:
listIdadds to an existing list.propertyIdororganizationIdplusnameadds to the list with that name in that scope, and creates the list first if there isn't one.
Each domain (or URL, trimmed to its domain) becomes a row with the status Target. Domains already on the list are skipped, and values that aren't a domain are reported back rather than failing the call. A domain Spyglasses hasn't seen before gets a publisher record and is queued for enrichment, so its traffic and logo fill in shortly afterward and its Domain Rank within a few hours. Rows added to an organization list this way carry no brand. The call spends no credits.
| Parameter | Type | Notes |
|---|---|---|
listId | string (optional) | An existing list, from list_pitch_lists. Use this, or a scope plus name. |
propertyId | string (optional) | With name: add to that property's list of that name. |
organizationId | string (optional) | With name: add to that organization's list of that name. |
name | string (optional) | The list name, used with propertyId or organizationId. |
domains | string[] | Publisher domains or URLs to add, up to 200 per call. |
note | string (optional) | A note applied to every row this call adds. It shows on the list, on the shared page and in exports. |
A typical flow
list_properties → copy the propertyId you want to work with.
For trends: get_metrics_history / get_consistency_history, then ask for charts.
For messaging: get_message_tracking, then get_answer_summaries on the most strategic query.
For a specific effort: list_projects → get_project_insights.
For one slice: list_prompt_tags → get_competitor_share_of_voice with the filters → get_answer_drilldown on a date from its series, with the same filters and a brandName lens.
For outreach: list_pitch_lists → get_pitch_list with includeAipvs: true, then add_pitch_list_publishers for the outlets worth adding.
Or run the Analyze a project, Who does AI name here?, Track message drift, or Citation mix over time prompts.
Related
- Projects dashboard · Key Messages dashboard · Citation Intelligence dashboard · Pitch Lists
- Scoring tools — evaluate publishers and placements for a property