AgencyAnalytics
Automate client reporting
- Category
- Data & Analytics
- Primary Subcategory
- Ad Campaign Analytics & Reporting
Integration details
Description
AgencyAnalytics is the only reporting and insights platform built for marketing agencies — and now it works directly inside ChatGPT. Connect every client's marketing channels into one place across SEO, PPC, social media, email, call tracking, ecommerce, and more, with 85+ integrations. Then query any of it, instantly, without leaving your AI workflow. Ask about a client's Google Ads performance before a call, pull a cross-channel summary to spot what's working, or compare results across multiple clients in a single prompt. No login, no export, no digging through dashboards. Data comes straight from your connected integrations, so it's always accurate and up to date. Your existing AgencyAnalytics permissions carry over automatically, so every team member only sees the clients they're supposed to. Setup takes under 60 seconds with no installation required.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Ad Campaign Analytics & Reporting
- Secondary Subcategories
- None listed
- Brand
- AgencyAnalytics
- Access
- Account required
- First tracked
- 2026-09-17
- Tool count
- 27
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
ChatGPT Plugin Discovery Score
ChatGPT Plugin discovery is coming soon
ChatGPT can surface a Plugin when it matches a user's request.Your Plugin Discovery Score measures how often yours appears.
No spam. Unsubscribe any time.
What discovery looks like

Competing in ChatGPT Ad Campaign Analytics & Reporting
View Category27 tools agents can invoke
List the custom metrics available for a single client — both campaign-level and account-level — so you can discover which formula-driven KPIs exist (e.g. "Cost per Lead", "ROAS"). Returns one row per custom metric with its `id`, `name`, `data_type`, `change_format`, `scope` (campaign or account), `formula`, and `description`. The `formula` is human-readable: each referenced metric is shown as `provider.asset.field` (e.g. `google_analytics4.event_analytics.conversions`) joined by the formula's arithmetic operators. Use the returned `id`s with read_client_custom_metrics to fetch each metric's computed output for a date range. This is the discovery step — it does not compute any values.
browse_client_custom_metrics
List the custom views available for a single client — both campaign-level and account-level. A custom view is a blended data table (the client section's "Views"): named columns mapped onto metrics from one or more connected data sources, e.g. a cross-platform ad spend table. Returns one row per view with its `id`, `name`, `scope` (campaign or account), the column names with their roles (`Date:dimension | Spend:value`), and the data sources it blends (readable `provider.asset` labels). This is the discovery step — it lists definitions, it does not compute any values. Creating a new view is create_client_custom_view, NOT this tool.
browse_client_custom_views
Use this tool to list all dashboards for a client/campaign. Returns paginated dashboards (10 per page). If the user does not see what they are looking for, increment page and call again. Use this when no specific dashboard was named and you need to present options or pick the most relevant one. Requires client_id on every call. Each result has an id and a name. Multiple dashboards will share the same id — this is intentional and expected, not a data issue. The id is the parent container identifier; the name is the individual dashboard tab within it. Do not surface or mention dashboard ids to the user; refer to dashboards by name only.
browse_client_dashboards
Discover connected providers and available metric data sources for a campaign in one call. Pass message (the user's question) to filter the returned data sources to only those relevant to the question. Omit or pass an empty string to return all data sources. Returns providers (connected slugs relevant to the question) and data_sources (AAQL data source definitions with available fields and pre-hydrated filters). Each data_source includes a filter map (slot -> pre-hydrated value) and a filter_types map (slot -> data type: array, string, integer, date, boolean, …). When you pass filters to read_client_data_source, send each value in the shape its filter_types entry declares — in particular an "array" filter (e.g. channel, event, source_medium) MUST be a list (["Organic Search"]); a scalar is silently ignored. Set requireDateRange to true to return only data sources that accept a start_date/end_date filter — use it when the question is scoped to a time window (a trend, a month, a comparison) so snapshot-only sources are excluded. Date-less id-lookup sources are still returned when a kept source requires a parent id (e.g. form_id) that only they can supply. Set testMode to true ONLY when the user explicitly asks for demo/test data: discovery then spans the whole connector catalog instead of the client's connected integrations, so a demo read (read_client_data_source with testMode=true) can be built even when nothing is connected. Always pass message with it. Input: clientId (integer), message (string — the user's original question), requireDateRange (boolean, default false), testMode (boolean, default false).
browse_client_data_sources
Use this tool to list all reports for a client/campaign. Use this when no specific report was named and you need to present options or pick the most relevant one. Requires client_id on every call.
browse_client_reports
Browse or enumerate clients. Use this whenever the user wants to see, list, or browse clients — including "show all clients", "list my clients", "what clients do I have", or any request to navigate by folder. Two modes based on whether `groupId` is provided: - **Folder mode** (omit `groupId`): returns all folders with their client counts, plus any ungrouped clients. Each client includes a `providers` field with connected integration slugs. - **Drill-down mode** (`groupId` provided): returns all clients inside the specified folder, each with a `providers` field. Optional `search` filters by client name / URL (and folder name in folder mode). Optional `status` filters by client status (e.g. "active"). Results are paginated via `limit` and `offset`. Use `search_clients` instead ONLY when the user already knows a specific client name, brand token, or domain and wants the single best match.
browse_clients
Create a new client (a campaign) on YOUR OWN account. Call search_clients FIRST — client names are not unique, so a second "Acme Co" will be created silently if one already exists. Listing existing clients is browse_clients, NOT this tool. This creates clients; creating account users is create_user, and creating a report section is create_client_report_section. Fields: name is the company name, website is their site (REQUIRED — a client cannot be worked with until it has one). timezone is an IANA identifier such as America/Toronto and defaults to the account's when omitted. group is the client group the app shows as a folder, and is FIND-OR-CREATE — an unrecognised name makes a NEW group, so pass one only when the user named it, and prefer a name browse_clients has already shown you. BILLING — read this before calling. If the account is already at its client limit, this tool RAISES the plan's client allowance, which CHARGES the customer, and then creates the client. It does not ask a second time. The tool result says so whenever it happens: relay that note to the user in full and never omit or soften it. Changing billing requires billing permission, so a caller without it is refused at the limit (creating a client below the limit needs only client-management permission). Accounts that cannot self-serve — on trial, cancelled, paused, with an unpaid invoice, or already at the plan's maximum — are refused with the reason. This tool runs in TWO steps. ALWAYS begin with confirmed=false — a first call with confirmed=true is a protocol violation, even when the user's request sounds pre-approved: - FIRST call it with confirmed=false (the default). Nothing is created — it returns the fully-resolved client, and the billing consequence when there is one, for the user to approve. Relay that summary verbatim and END YOUR TURN. - If the user wants changes, apply them and call again (still confirmed=false) to re-confirm. - ONLY after the user has REPLIED with explicit approval — a real message that arrives after they have seen the preview — call again with confirmed=true to create. The preview and the confirmed=true call must NEVER happen in the same turn. Never approve on the user's behalf, never treat the original request as pre-approval, and never set confirmed=true on the first call. Creating clients requires client-management permission — the tool refuses with an explanation when the caller does not have it. At most 50 PAID clients can be added per hour per user — that is, creates that raise the plan because the account is at its limit. Creates that fit inside the current plan are not counted. If the cap is reached while working through a list or an uploaded file, tell the user how many were created, that the rest were not, and when the remainder can be added. Input: name (string), website (string), timezone (string, optional — defaults to the account's), group (string, optional — find-or-create), confirmed (boolean — leave false to preview; set true only after the user approves).
create_client
Create a custom metric — a formula-driven KPI (like "Cost per Lead" or a blended ROAS) computed from connected integration metrics. Pass clientId for a single client's metric; OMIT clientId to create an ACCOUNT-LEVEL metric that appears on EVERY client's dashboard (each client computes its own slice; requires an admin or all-access staff caller). Reading existing custom metrics is browse_client_custom_metrics / read_client_custom_metrics, NOT this tool. The formula is passed as STRUCTURED parts — never as a raw variable string: - terms: the metrics the formula uses. Each is {ref, provider, asset, field, groupBy?, filters?} — discover valid provider/asset/field combinations via browse_client_data_sources (pick sources whose group_by includes "date"). ref is a short handle like "spend" or "leads" (letters/digits/underscores). Optional filters narrow a term (e.g. one campaign); a filter value may be a scalar or a list (list = "any of these values"). At most 15 terms; each must be used in the expression. - expression: arithmetic over {ref} placeholders, e.g. "({spend} / {leads}) * 100". Allowed: + - * / ( ) and numbers. Nothing else — no functions, no comparisons. dataType is REQUIRED and must be chosen deliberately: currency for money (cost per lead), percent for rates, float/integer for counts and plain numbers — a wrong type renders wrong everywhere the metric appears. changeFormat is percent (default; up = good) or percent_inverted (up = bad, e.g. cost metrics). After a confirmed create the tool immediately computes the metric over the last 30 days and reports the value — the server does NOT validate arithmetic, so this is where a broken formula (divide-by-zero and the like) surfaces. A failed computation does not undo the creation; the response says so and the metric can be fixed or deleted in the app. Account-level metrics compute per client, so that verification is skipped for them — check any client's dashboard or read_client_custom_metrics instead. This tool runs in TWO steps. ALWAYS begin with confirmed=false — a first call with confirmed=true is a protocol violation, even when the user's request sounds pre-approved: - FIRST call it with confirmed=false (the default). Nothing is created — it returns the fully-resolved metric (name, type, the formula in plain provider.asset.field terms, and a warning if a same-named metric already exists) for the user to approve. Relay that summary verbatim and END YOUR TURN. - If the user wants changes, apply them and call again (still confirmed=false) to re-confirm. - ONLY after the user has REPLIED with explicit approval — a real message that arrives after they have seen the preview — call again with confirmed=true to create. The preview and the confirmed=true call must NEVER happen in the same turn. Never approve on the user's behalf, never treat the original request as pre-approval, and never set confirmed=true on the first call. Custom metrics must be enabled for the account (plan feature) — the tool refuses with an explanation when they are not. Input: clientId (integer — omit for an account-level metric), name (string), description (string, optional), dataType ("integer"/"float"/"currency"/"percent"), changeFormat ("percent"/"percent_inverted", default percent), terms (array of term objects as above), expression (string), confirmed (boolean — leave false to preview; set true only after the user approves).
create_client_custom_metric
Create a custom view for one client — a blended data table (the client's "Views" section) combining metrics from one or more connected data sources, e.g. a cross-platform ad spend table with Google Ads and Facebook Ads side by side. Listing existing views is browse_client_custom_views, NOT this tool. Describe the view in plain language via `prompt` (e.g. "a table of daily sessions and conversions from GA4 next to Google Ads spend") — the platform generates the column and data-source definition from the client's connected sources. You do NOT pass columns. This tool runs in TWO steps. ALWAYS begin with confirmed=false — a first call with confirmed=true is a protocol violation, even when the user's request sounds pre-approved: - FIRST call it with confirmed=false (the default). Nothing is created — the platform generates the view, renders a sample of it over the last 30 days, and returns the columns, data sources, sample rows, and a generatedView JSON block for the user to approve. Relay that summary verbatim and END YOUR TURN. - If the user wants changes, adjust the prompt and call again (still confirmed=false). - ONLY after the user has REPLIED with explicit approval — a real message that arrives after they have seen the preview — call again with confirmed=true AND generatedView set to EXACTLY the JSON block from the preview. Generation is not deterministic: echoing the block back is what guarantees the created view is the one the user approved. The preview and the confirmed=true call must NEVER happen in the same turn. Never approve on the user's behalf, never treat the original request as pre-approval, and never set confirmed=true on the first call. Custom views must be enabled for the caller (plan/role feature) — the tool refuses with an explanation when they are not. Requires permission to update the client. Campaign-level only (clientId is required). Input: clientId (integer), prompt (string, max 2000 — the plain-language description), name (string, optional — overrides the generated view name, max 100), generatedView (JSON string — ONLY on the confirmed call, copied exactly from the preview), confirmed (boolean — leave false to preview; set true only after the user approves).
create_client_custom_view
Create a new user on YOUR OWN account (a teammate or a client login) and optionally send them the invite email. Call search_users FIRST to check the person does not already exist — a duplicate email is rejected. This creates account users; it does NOT create clients (campaigns) and does NOT email arbitrary addresses (create_email emails existing users). Fields: firstName, lastName, email, role ("staff" — a teammate; or "client" — a client-portal login). Access: clientIds (client ids from search_clients/browse_clients) grants restricted access to those clients — REQUIRED (at least one) when role=client, since a client user with no clients sees an empty portal. allClients=true (staff only, instead of clientIds) grants a standing pass to ALL clients INCLUDING ONES ADDED IN THE FUTURE — only use it when the user explicitly asks for access to everything. sendInvite (default true) controls whether the invite email is sent; creation alone never emails anyone, and the person cannot log in until they accept an invite. This tool runs in TWO steps. ALWAYS begin with confirmed=false — a first call with confirmed=true is a protocol violation, even when the user's request sounds pre-approved: - FIRST call it with confirmed=false (the default). Nothing is created — it returns the fully-resolved user (name, email, role, access, whether an email will be sent) for the user to approve. Relay that summary verbatim and END YOUR TURN. - If the user wants changes, apply them and call again (still confirmed=false) to re-confirm. - ONLY after the user has REPLIED with explicit approval — a real message that arrives after they have seen the preview — call again with confirmed=true to create. The preview and the confirmed=true call must NEVER happen in the same turn. Never approve on the user's behalf, never treat the original request as pre-approval, and never set confirmed=true on the first call. Creating users requires user-management permission, and staff seats may be capped by the plan — the tool refuses with an explanation when either applies. Input: firstName (string), lastName (string), email (string), role ("staff"/"client"), clientIds (integer[], optional — required for role=client), allClients (boolean, staff only, excludes clientIds), sendInvite (boolean, default true), confirmed (boolean — leave false to preview; set true only after the user approves).
create_user
Fetch a single public web page or document by URL and return its readable text. Sends realistic desktop-browser headers so the page responds as it would for a human visitor. HTML is reduced to plain text (scripts, styles, and markup removed); JSON, plain-text, and XML responses are returned as-is. Binary, image, and other non-text content is not supported. Output is truncated to `maxLength` characters (default 30000). Provide one absolute http(s) URL — private, internal, and cloud-metadata addresses are blocked. Use to read an article, documentation page, or API/JSON endpoint the user names. For live web search use search_web instead; for AgencyAnalytics help articles use read_knowledge_base.
fetch_web
Fetch a client's AI Tracker analytics — how visible the brand is inside AI assistants' answers, broken down by a dimension. Returns one row per dimension value with the AI-visibility metrics: visibility (share of AI answers that mention the brand, 0-100), citations (cited URLs on the brand's own domain), position (the brand's rank among the brands an answer mentions), sentiment (0-100), citation_rate, and prompts (whichever the breakdown reports). Platforms tracked: ChatGPT, Google AI Overview, Google AI Mode, Claude, Perplexity, Gemini. Use this for AI-search / generative-engine-optimization questions — e.g. "which AI assistants mention us most?", "our visibility in ChatGPT vs Perplexity", "which prompts surface our brand", "which domains do AI answers cite for our topics", "AI visibility trend over the last 30 days". This is AI-answer visibility — NOT Google SERP keyword rankings or search volume (that is tracked keyword data — read it via browse_client_data_sources → read_client_data_source; it tracks a keyword's rank position in classic search results). Pass an entityType. Only these provider/entityType combinations work: - agency-analytics-ai-tracker-v1: platform, prompt, topic, citation_domain, citation_url, by_date, by_date_platform, by_date_topic Breakdown families: visibility by platform/prompt/topic; citations by cited domain/URL; and time-series (by_date, by_date_platform, by_date_topic). The date-series breakdowns live here — read_client_metrics does NOT cover AI Tracker. Metric availability differs slightly per breakdown (e.g. citation_rate is a citation-breakdown metric; prompts appears on topic/citation breakdowns) — columns a breakdown does not report are simply absent. If the campaign's prompts have never been fetched yet the tool returns no rows with an "initializing" note — AI Tracker is still collecting its first results, not an error. Before calling, determine provider availability using this priority order: 1. If `connected_providers` is in the system prompt and non-empty, use it — confirm the desired provider is listed there. 2. If `connected_providers` is in the system prompt but empty, decline without calling this tool — no providers are connected. 3. If `connected_providers` is absent but `search_clients` was called earlier in this conversation, use those cached results. 4. If none of the above, call `search_clients` first to resolve connected providers. If the provider is absent from whichever source applies, decline — unless testMode is explicitly requested by the user, in which case call the tool with testMode=true; testMode bypasses the integration connection check by design and returns demo data. Pass the provider slug directly ('agency-analytics-ai-tracker-v1') — no conversion needed.
read_client_ai_tracker
Fetch the computed output of a single client's custom metrics (formula-driven KPIs such as "Cost per Lead" or "ROAS") over a date range. Custom metrics combine multiple providers/fields through a user-defined formula — use this when the user asks about a named KPI that is not a raw provider metric. Provide `customMetricIds` to read specific metrics; omit it to read every custom metric available for the client (both campaign-level and account-level). Use browse_client_custom_metrics first to discover the available metric ids, names, and types. By default returns one aggregated value per metric (id, name, value, data_type, change_format). Set byDate=true to return a per-date time series (id, name, date, value) for each metric.
read_client_custom_metrics
Use this tool to fetch data for a specific dashboard. Requires client_id on every call. If the user already selected a dashboard by name (e.g. from browse_client_dashboards), go directly to step 2 — pass dashboard_id and section_name in the same call. Do not call step 1 first. Step 1 (no section_name) — only use when you do not yet know which dashboard the user wants: resolves a dashboard container by dashboard_id or dashboard_name and returns the list of available dashboards. Use this to present options to the user. Step 2 (with section_name) — fetches provider data for the named dashboard. Never fetch data across all dashboards at once. Always ask the user which dashboard they want before calling this step. Never refer to dashboards as "sections" when communicating with the user.
read_client_dashboard
Run a raw AAQL read query for one client and return the raw connector rows as CSV, followed by a `Totals:` section when the connector reports totals. Use those totals rather than summing the rows yourself. Use this for per-entity breakdown questions (ad campaigns, keywords, pages, calls, reviews, deals, orders, …) and for raw data exports — always after browse_client_data_sources has resolved the data source. For trend-over-time questions prefer read_client_metrics, and for biggest-mover questions prefer read_client_metric_signals — both are far more token-efficient. Workflow: call browse_client_data_sources with the client id and the user's question first, pick the matching data_sources entry, then call this tool with that entry's provider, asset, fields, group_by, and filter map (set start_date/end_date from the user's question). It runs immediately — derive the date range and filters from what the user asked rather than interrogating them. For an open-ended export request where the user has not said what they want ("dump my data"), present the available data sources as friendly options and let them pick before calling. integration_campaign_id is a single account id — browse_client_data_sources returns one entry per connected account, so to export from several accounts make ONE call per account rather than passing a list. Row limit defaults to 50 (max 500); paginate with offset for large exports. Do not invent provider/asset/field/filter values; this tool does not validate them against a known list and relies on browse_client_data_sources for valid inputs. Match each filter value to the shape declared in that data source's filter_types map — an "array" filter MUST be passed as a list (["Organic Search"]); A scalar value may be silently ignored, rejected, or not applied. Input: clientId (integer), provider (string), asset (string), filters (object — start_date/end_date and any provider filter slots; integration_campaign_id is a single account id, make one call per account to export from several), fields (string[]; omit or [] for all fields of the asset), groupBy (string[]), sort ({field_name, direction}), limit (integer, default 50, max 500), offset (integer, default 0), testMode (boolean — serve the provider's demo data instead of the client's live data, so a source can be read without a live integration and without calling the provider's real API; only pass true when the user explicitly asks for testMode).
read_client_data_source
Answer questions grounded in a client's uploaded documents — contracts, invoices, statements of work, proposals, briefs, meeting notes, reports — or the account's shared docs (brand guidelines, templates, policies). Use it whenever the answer lives in uploaded paperwork rather than live analytics: contract or retainer terms, invoice amounts or line items, scope and deliverables, goals/KPIs, or action items — even when the user never says "document", "file", or "upload". If a factual client question could plausibly be answered from their files, check here before answering from memory or saying you do not have it. Pass clientId to scope to one client (shared account-level docs are still included); omit it to search all accessible clients plus shared docs. Not for AgencyAnalytics platform how-to (use read_knowledge_base) or live metric/analytics data (use the analytics tools). Returns a grounded, source-cited answer, plus (when clientId is given) a business_context list of the client's structured profile fields — company details, services, pricing, tone of voice, target audience, competitors, and any custom fields the agency maintains — which you should use and cite the same way as the document answer.
read_client_knowledge
Return a single client's biggest-moving metrics (trend signals), ranked by the magnitude of their percent change — biggest movers first, whether up or down. Use this to answer "what changed the most for this client?", "what are the biggest movers / drops / gains?", or "what's notable about this client right now?". To focus on only gains or only declines, pass direction=up or direction=down. These are pre-computed trend signals (period-over-period and year-over-year comparisons) refreshed once daily — NOT real-time. Each row carries the metric (variable), the comparison window (period_days), the comparison type (previous_period / year_over_year), current_value, comparison_value, absolute_change, percentage_change, and trend_direction. Signals span every connected provider at once, so no provider argument is needed and no provider-connection check is required. By default it returns the 30- and 90-day comparison windows (365-day comparisons are excluded as too noisy to be actionable) and both comparison types, so a single metric can appear up to ~4 times (once per window × comparison). Narrow the results with the optional filters: - period: restrict to one window (30 or 90 days). - comparisonType: restrict to previous_period or year_over_year. - direction: restrict to up, down, or flat movers. - minPercentageChangeMagnitude: only movers whose |percent change| meets this floor. - limit: max rows to return (default 50, max 200). For raw daily/monthly time series use read_client_metrics; for per-entity breakdowns use browse_client_data_sources followed by read_client_data_source. This tool is for surfacing the notable movements, not exporting full series.
read_client_metric_signals
Fetch aggregated time-series metrics for a single client over a date range, scoped to one connected integration provider. Returns one row per day or month — NOT one row per campaign, keyword, page, call, or traffic entity. Responses are limited to a maximum of 200 rows. Use this for trend questions: "how has this client's overall performance changed over time?". For data broken down by entity (campaigns, ad groups, keywords, pages, calls, traffic sources, …), use browse_client_data_sources to pick the matching data source, then read_client_data_source. Supported providers (26): adroll, bing-ads, bird-eye, callrail, facebook, facebook-ads, google-analytics4, google-display-video360, google-local-services-ads, google-my-business, google-search-console, googleadwords, ground-truth-v1, high-level, instagram, linked-in, linked-in-ads, pinterest-ads, reddit-ads-v1, simpli-fi, spotify-ads, stack-adapt, tiktok-ads, tiktok-v1, twitter-ads, yelp-ads. Before calling, determine provider availability using this priority order: 1. If `connected_providers` is in the system prompt and non-empty, use it — confirm the desired provider is listed there. 2. If `connected_providers` is in the system prompt but empty, decline without calling this tool — no providers are connected. 3. If `connected_providers` is absent but `search_clients` was called earlier in this conversation, use those cached results. 4. If none of the above, call `search_clients` first to resolve connected providers. If the provider is absent from whichever source applies, decline — this tool has no testMode parameter and cannot bypass the connection check. To compare metrics across providers, call this tool once per provider and compare the responses — multi-provider scoping is not supported. Note: this tool no longer accepts `'all'` or any aggregate scoping; callers that previously used `'all'` must now call once per provider from `connected_providers` and combine results themselves.
read_client_metrics
Fetch a client's Rank Tracker data — where the client ranks in classic search results for the keywords the agency tracks, broken down by a dimension. Engines covered: Google, Google Mobile, Google Local, and Bing. Metrics per breakdown: ranking position, best position (_top), average position (_avg), cumulative movement (_change), how many keywords rank (_ranking_count), the ranking URL, monthly search volume, and competition. Use this for SEO keyword-ranking questions — e.g. "which keywords rank best?", "how have our rankings trended?", "how many keywords are on page one?", "which pages earn our rankings?", "why did this keyword drop?". LOWER IS BETTER for every position metric: rank 1 beats rank 40, and `ranking_average` is a mean SERP position, not a score. A rank that falls from 40 to 3 is an improvement. This is classic-SERP rank tracking — NOT AI-answer visibility (that is read_client_ai_tracker: mention rate and citations inside ChatGPT/Gemini/Claude/Perplexity answers) and NOT a live SERP lookup (that is search_web). It reads only the keywords this client has chosen to track. Pass an entityType — one of: keyword, date, tag, url, range, date_range, serp, date_serp, date_keyword. - `keyword` (default): one row per tracked keyword. - `date`: campaign rollup per day — the ranking trend. read_client_metrics does NOT cover Rank Tracker, so the trend lives here. - `tag` / `url`: keywords rolled up by tag label, or by the page that ranks. - `range` / `date_range`: position buckets (1-3, 4-10, 11-20, 21-50, 51+), overall or per day. - `serp` / `date_serp`: mean position per search engine, overall or per day. - `date_keyword`: ONE keyword's daily history — requires keywordId (get it from the `keyword` breakdown first). Do not pass keywordId to any other breakdown. Optional filters, each valid only on the breakdowns whose schema declares it — passing one elsewhere is REFUSED (it would be silently ignored, not applied): - `search`, on keyword / tag / url. `range`, on date / range / date_range. `serp`, on serp / date_serp. - `tags`, `primaryKeyword`, `searchLocationId`, `searchLanguageId` — every breakdown except date_keyword. - `tags` takes tag IDs, NOT labels: read them from the `tag` breakdown's tag_id column first, or the filter matches nothing. - `googleSerpFeatures` / `googleMobileSerpFeatures` — the date, range, date_range, serp and date_serp breakdowns only. These select on the SERP features a keyword holds ON THE END DATE of the range: membership only, so the position metrics still span the whole window. Setting both keeps a keyword matching EITHER engine, not both. - `dateInterval` — the date-grain breakdowns only. Rows are daily by default; `monthly` buckets by month, `automatic` derives it from the span (over 30 days becomes monthly). On the `keyword` breakdown the rows are not sorted purely by rank: the starred keyword is pinned first and keywords that have never ranked are pushed below ranked ones, so do not report row 1 as "the best-ranking keyword" — read the position values. Rankings are collected by a nightly job. If the campaign's rankers have not run yet the tool returns an "initializing" note rather than zeros. CAUTION on dates before collection started: the rollup returns a row for EVERY date in the window and fills gaps from the nearest measured day — forward from the last one, and where there is none, BACKWARD from the first later one. So a range beginning before this campaign's first ranker run shows those earlier dates carrying the first measured day's numbers, which look like real history. Treat the start of a long range with suspicion and prefer a window you know was tracked. Before calling, determine provider availability using this priority order: 1. If `connected_providers` is in the system prompt and non-empty, use it — confirm the desired provider is listed there. 2. If `connected_providers` is in the system prompt but empty, decline without calling this tool — no providers are connected. 3. If `connected_providers` is absent but `search_clients` was called earlier in this conversation, use those cached results. 4. If none of the above, call `search_clients` first to resolve connected providers. If the provider is absent from whichever source applies, decline — unless testMode is explicitly requested by the user, in which case call the tool with testMode=true; testMode bypasses the integration connection check by design and returns demo data. Rank Tracker reports as the provider slug 'rank-tracker'. This tool takes no provider parameter — it serves only Rank Tracker.
read_client_rank_tracker
Investigate ONE tracked keyword's disputed ranking: returns the evidence behind the recorded position for a single keyword + engine — NOT ranking numbers over time (that is read_client_rank_tracker). Use when a ranking looks wrong — "shows Not Found but we rank #1", a sudden unexplained drop, or disagreement with another rank tracker. Get the keywordId from read_client_rank_tracker's `keyword` breakdown first. Returns three labeled sections: 1. SETTINGS — what the ranking matcher ran under: keyword phrase, search location and language, the campaign's tracked URL with its URL-scope matching rule, Google 3-pack handling, CID enforcement, the configured Google Business Profile CIDs, refresh interval, and the last POSITIVE recorded position per engine (a spike-detection baseline that a Not Found reading does not clear — use read_client_rank_tracker's date_keyword breakdown for the latest reading). 2. STORED SERP — the capture behind the last recorded position: when it was fetched, how many fetch attempts it took, how many results it holds, and each notable result classified against the campaign settings with a verdict: matched / matched_not_rankable (the site IS on the SERP but inside a feature block — an ad, video, knowledge panel — that the ranking never counts) / same_domain_out_of_scope (the URL exists on the tracked domain but the URL scope excludes it) / cid_enforced_skip (URL matched but CID enforcement rejected it) / ignored_local / local_link_unresolvable (Google wrapped or omitted the link and no CID was configured) / no_match. Each result row carries TWO positions: serp_position (the provider's raw slot on the SERP) and counted_position (the rank the matcher records — only organic-rankable rows advance it, so ads and feature blocks make the two diverge). The recorded ranking corresponds to counted_position. An explicit line states when the tracked domain appears NOWHERE in the capture — with a valid capture, that is the SERP-volatility signature, not a bug. 3. KNOWN OUTAGES — registered provider outage windows for the engine, to correlate a disputed date with a period whose readings are excluded or masked. Read this BEFORE suggesting a refresh: a refresh OVERWRITES the stored capture, destroying the evidence under dispute. An empty or near-empty capture (very few results, none organic) indicates a degraded provider response — a data problem worth escalating, not a real ranking loss. This tool reads stored data only; it never triggers a fetch and consumes no credits.
read_client_rank_tracker_diagnostics
Use this tool to read a specific scheduled report for a client/campaign. Requires report_id or report_name. Step 1 (no section_name): resolves the report and returns its list of sections. Always call without section_name first to discover sections. Step 2 (with section_name): fetches provider data for one specific section. You must never fetch data across all sections at once — always ask the user which section they want before step 2. Requires client_id on every call.
read_client_report
Fetch a client's Site Auditor results — the technical site health found by AgencyAnalytics' own crawler: the audit score, which checks pass or fail (broken links, missing titles, slow pages, duplicate content, …), and per-page detail. Use this for site-health questions — e.g. "how healthy is the site?", "what technical SEO issues does it have?", "which pages are broken?", "is site health improving?", "why is this page failing?". Scores are 0-100 and HIGHER IS BETTER (the opposite of a SERP rank). Check severities, worst first: critical, error, warning. This tool READS finished crawls only — it cannot start, re-run, or stop a crawl. Every breakdown except `audits` and `history` reads ONE crawl, chosen by auditId: pass a task_id from the `audits` breakdown, or leave the default 'latest' (the newest crawl, even if it is still running or failed). To read last month's crawl, list `audits` first — do NOT pass startDate/endDate, which only the `history` breakdown accepts. Pass an entityType — one of: summary, tests, audits, history, pages, test_pages, page_detail. - `summary` (default): the chosen crawl's rollup — score, pages crawled, per-severity check counts, and the task_id that 'latest' resolved to. - `tests`: one row per audit check with failure counts — the main site-health table. Failed checks first. - `audits`: one row per crawl — status (initiating/processing/completed/error/cancelled), dates, and the error_message when a crawl failed. The place to find auditIds and to see WHY results look empty. - `history`: the audit score per crawl date — the trend. The only breakdown taking startDate/endDate (both required there). - `pages`: one row per crawled page, worst score first. Fetched live from the crawl provider, so it is slower than the other breakdowns. - `test_pages`: the pages failing ONE check — requires testId (get it from the `tests` breakdown first). Columns vary by check: link checks list the broken target, threshold checks carry the measured value. - `page_detail`: ONE page's per-check results — requires url (copy it exactly from the `pages` breakdown). Optional filters, each valid only on the breakdowns whose schema declares it — passing one elsewhere is REFUSED (it would be silently ignored, not applied): `search` on tests / pages; `statusCode` on pages; `showPassed` on tests. testMode (demo data) is REFUSED on the audits and test_pages breakdowns — their schemas author no demo data, so the empty result would look like a real finding. This is the platform's own crawler — NOT Google PageSpeed or Lighthouse scores (those are separate integrations read via browse_client_data_sources), NOT keyword rankings (read_client_rank_tracker), and NOT a live page fetch (fetch_web). If no audit has ever run the tool says so instead of returning zeros. A crawl still in progress returns partial rows plus a status note. An errored crawl can legitimately return no rows — check entityType=audits for its error_message before reporting "the site has no issues". Before calling, determine provider availability using this priority order: 1. If `connected_providers` is in the system prompt and non-empty, use it — confirm the desired provider is listed there. 2. If `connected_providers` is in the system prompt but empty, decline without calling this tool — no providers are connected. 3. If `connected_providers` is absent but `search_clients` was called earlier in this conversation, use those cached results. 4. If none of the above, call `search_clients` first to resolve connected providers. If the provider is absent from whichever source applies, decline — unless testMode is explicitly requested by the user, in which case call the tool with testMode=true; testMode bypasses the integration connection check by design and returns demo data. Site Auditor reports as the provider slug 'agency-analytics-auditor-4'. This tool takes no provider parameter — it serves only Site Auditor.
read_client_site_auditor
Search the AgencyAnalytics knowledge base for how-to articles and platform documentation.
read_knowledge_base
Look up ONE specific client by name fragment, brand token, or domain. Returns the single best-matching client (highest cosine similarity over `company`+`url`) with a `providers` field — use that to confirm a provider is connected before calling any entity tool. See the `query` parameter description for usage guardrails. If the user wants to list, browse, or enumerate clients — including "show all clients", "list my clients", "what clients do I have", or browsing by folder — use `browse_clients` instead.
search_clients
Search the teammates and contacts in your own AgencyAnalytics account by name or email. Use this to resolve who you can email before calling create_email — it returns only users you are allowed to contact (your account, honouring your access permissions). Natural for requests like "email John the report": first search_users for "John", then create_email to the matching user_id. Input: query (string — a name or email fragment, required), limit (integer, optional, default 10, max 50). Returns a JSON array of matching users, each with id, name, email, and role. Pass the chosen user's id as create_email's user_id. If nothing matches, refine the query or ask the user to confirm the recipient's name.
search_users
Search the live web and return a compact keyword-research result set: organic results (position, title, link, domain, snippet), related searches, People Also Ask questions, and the answer box when present. Defaults to Google desktop. Set `engine=google_mobile` for the mobile SERP, or `engine=bing` for Bing (Bing returns no People Also Ask or answer box). Set `engine=google_local` for the Google local-finder (places) results — businesses with position, title, link, CID, rating, and address under `places_results`; no organic results, related searches, or People Also Ask. Use it to verify local/map rankings; always pass a `location`. Use for keyword research, SERP inspection, and competitor discovery. Not client-scoped — no clientId required. Results are token-heavy, so prefer one well-chosen query over looping many variations. Localize Google results with `location` (free-form, e.g. "Toronto, Ontario, Canada") or the `countryCode`/`language` codes. For Bing only `location` and `language` apply. If the response includes `showing_results_for`, Google rewrote the query — re-search with the exact phrase only if the original spelling matters.
search_web
Record user feedback explicitly directed at the AgencyAnalytics MCP server experience — its tools, ergonomics, or quality of results. Only call this when the user clearly intends to leave feedback (e.g. "I want to give feedback on the MCP", "this MCP is great", "the MCP is broken"). Do not call for incidental opinions about underlying data, individual integrations, or unrelated workflows.
create_mcp_feedback
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are AgencyAnalytics alternatives on ChatGPT?
As of 2026-09-17, AgencyAnalytics competes with Ad Superpowers, AdKit - Ads Manager, AdPage, adplane, Adspirer, Adszy, Agentio, Billy Grace Insights, Channel99, DashThis, Data Bloo, Delivra, Dynamoi, Flyweel, HYPD AI - Paid Ads & Analytics, Jepto, Kreel, Lead Recorder, Lily Apple Ads, LoomaScale, Markifact - Ads & Analytics, Masha, Nexoya, PaidSync, Reportei, StoreAdOps, Supermetrics, Triple Whale, Voluum, Whatagraph, Windsor.ai Facebook Ads, Windsor.ai Google Ads, Windsor.ai TikTok Ads in ChatGPT Ad Campaign Analytics & Reporting, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.