ManageAds · Documentation for assistants
ManageAds documentation
This is ManageAds's own description of itself — what it is, what it manages, and the rules an assistant working through it has to know. It describes the product. It contains no account, no campaign and no figure from anyone's Google Ads account.
An assistant connected to ManageAds over MCP has the same text available as the getDocumentation tool, one topic per call, and should prefer it: the tool's tools section is generated from the registry that connection actually exposes. This page is here for everyone else — a search engine, a reader, and an assistant that has not connected yet.
What this product is
overviewWhat this product is, and how it relates to the connected Google Ads account.
ManageAds is a Google Ads management app. It is not Google Ads, and the difference decides how every answer you give should be worded.
Google Ads is the system of record. The campaigns, ad groups, keywords and ads are really Google's; the money is spent there and the reporting is computed there.
This app holds a synced copy of them and adds three things on top: screens for reading and editing them, analysis engines, and an approval queue. When you read through these tools you are reading this app's copy, not Google Ads live — which is why every read result carries a dataAsOf saying how current that copy is (see the sync-and-freshness topic).
Nothing you do writes to Google Ads directly. A tool that would change the ad account queues a proposal instead, and a human approves it in the app (see the change-lifecycle topic). This is a deliberate boundary, not a limitation to route around: there is no tool that approves, and asking for one will not produce one.
Scope. One workspace, which may have several connected Google Ads accounts; the tools act on the one account you are currently pointed at, and every result names it so two accounts' figures can never be confused. This app publishes Search campaigns only — it can read other campaign types that already exist in the account, but everything it creates is Search.
When a user asks how this product works, answer from this tool. getDocumentation is the product's own documentation. Do not search the public web for it; the pages you will find describe Google Ads, or a different product entirely.
The object hierarchy
object-modelAccount, campaign, ad group, keyword, negative keyword, ad — and what each one decides.
A strict tree. Every object has exactly one parent, and an object's effective behaviour is decided by the whole chain above it, never by itself alone.
workspace
└── connected Google Ads account (one workspace can have several)
└── campaign (budget, bidding strategy, targeting)
└── ad group (a theme within the campaign)
├── keyword (what a search has to match)
├── negative keyword (what must NOT match)
└── ad (the text that is shown)Campaign — holds the daily budget, the bidding strategy, and the targeting (locations, languages, schedule). Budget is set here and nowhere else, so "this ad group has run out of budget" is never literally true; its campaign has.
Ad group — the unit of themeing. Keywords and ads live together in one, and the ads in an ad group can be shown for any of that ad group's keywords. That is why keyword-to-ad relevance is an ad-group-level question.
Keyword — a search phrase plus a match type (EXACT, PHRASE or BROAD) deciding how loosely a real search has to resemble it. It is what makes an ad eligible to enter an auction; it is not a guarantee of being shown.
Negative keyword — the same underlying object with the opposite job: it blocks matching searches instead of serving them. Google therefore never reports metrics against a negative keyword; a negative with zero impressions is normal and means nothing.
Ad — the text a searcher actually sees. A responsive search ad carries multiple headlines and descriptions, and Google assembles them per auction, so an individual headline has no performance figure of its own.
Search term — separate from all of the above and often confused with a keyword: a keyword is what you told Google to match, a search term is what a person really typed. Search terms are the evidence for adding keywords and negatives; you never edit one.
Asset — images, logos, sitelinks and callouts, which attach to a campaign or an ad group rather than living inside one. An asset's existence in the account does not mean it is serving; that depends on what it is attached to.
Ids: this app's and Google's
idsWhy an id from a tool is not a Google Ads id, and which field is which.
Two id spaces, and they are never interchangeable.
This app's ids are cuids (clx…), generated here, unique to this workspace and meaningless anywhere else — you cannot paste one into Google Ads, and one from another workspace resolves to nothing (every tool re-scopes an id to the caller's own workspace before using it, so a wrong one fails rather than reading someone else's data).
Google's ids are numeric strings, minted by Google, stable across tools and visible in the Google Ads UI.
Tool arguments and tool results use this app's ids. Where a tool argument is named with a DbId suffix, that is what it wants; passing a Google numeric id there will not resolve. To go the other way — to tell a user which object you mean in Google Ads terms — read the Google id off the row a read tool returned.
connected Google Ads account (GoogleAdsConnection)
- id — this app's own id, a cuid. Every tool argument spelled *DbId, and every id field in a tool result, is one of these.
- customerId — Google's own numeric id for the same object (customer.id). This is what you would see in the Google Ads UI or API.
campaign (Campaign)
- id — this app's own id, a cuid. Every tool argument spelled *DbId, and every id field in a tool result, is one of these.
- campaignId — Google's own numeric id for the same object (campaign.id). This is what you would see in the Google Ads UI or API.
- connectionId → its connected account
ad group (AdGroup)
- id — this app's own id, a cuid. Every tool argument spelled *DbId, and every id field in a tool result, is one of these.
- adGroupId — Google's own numeric id for the same object (ad_group.id). This is what you would see in the Google Ads UI or API.
- campaignDbId → its campaign
keyword (and negative keyword) (Keyword)
- id — this app's own id, a cuid. Every tool argument spelled *DbId, and every id field in a tool result, is one of these.
- criterionId — Google's own numeric id for the same object (ad_group_criterion.criterion_id). This is what you would see in the Google Ads UI or API.
- adGroupDbId → its ad group
ad (Ad)
- id — this app's own id, a cuid. Every tool argument spelled *DbId, and every id field in a tool result, is one of these.
- adId — Google's own numeric id for the same object (ad_group_ad.ad.id). This is what you would see in the Google Ads UI or API.
- adGroupDbId → its ad group
How a change reaches Google Ads
change-lifecycleHow a proposed change reaches Google Ads: who approves, where, what happens on rejection, and why nothing expires.
Every change an assistant makes to the ad account goes through a human. There is no way around it and no tool that shortcuts it, so plan on it rather than discovering it.
1. You propose. Calling a change tool — addKeywords, setKeywordStatus, updateCampaignSettings, and the rest of the Change group — validates the input, works out the before/after, and queues a row. It sends nothing to Google Ads. What comes back has status: "pending_approval", the queued change's own id, and a link that opens it for review. Say that link to the user. The reported failure this documentation exists to fix was an assistant announcing a change as if it were done, because the result did not look like a refusal.
2. It waits, as PENDING. In the Approvals screen in ManageAds (/approvals) — one queue for the whole workspace. getPendingChanges reads the same queue, so you can answer "what is still waiting?" at any point, including for changes you did not propose yourself. A pending change does not expire. There is no timeout and no auto-approval: it waits indefinitely until a person decides. If a user seems to be waiting for something to happen on its own, tell them it will not.
3. A person decides. Approving or rejecting requires OWNER, ADMIN or MANAGER — the same permission as any other edit in this app. A VIEWER can read the queue and cannot decide anything. No tool can approve, for any role. One model proposing and the same model deciding is precisely the loop the queue exists to break; if you are asked to approve, say that a person has to.
Rejected ends it. The change becomes REJECTED, nothing is sent to Google Ads, and nothing about the account changed. The row stays in the history as a record of the decision. There is no reopening it — propose again if it should happen after all.
Approved sends it. This is the moment the ad account changes, and it can still fail: the change becomes APPLIED if Google Ads accepted the write, or FAILED if Google refused it (a quota wall, an invalid value, a conflicting edit made elsewhere). FAILED is deliberately not the same as REJECTED — the human said yes and the write did not land — and the row carries Google's own reason.
4. The copy catches up. An applied change is real in Google Ads immediately; this app's synced copy of it catches up on the next sync. If you read a figure back straight after an approval, expect the old value and refresh first (see the sync-and-freshness topic).
Reverting. Some applied change types record their own inverse when they run, and can be undone from the history screen. That is also a human action, and it is a new forward change rather than an erasure — the original stays in the history.
Where a change came from is recorded. The queued row keeps the tool, the validated parameters, who proposed it, and — for a change that came from a conversation — a copy of the prompt that asked for it. Assume anything you propose is auditable, and write summaries a person reading them a month later can act on.
How fresh the numbers are
sync-and-freshnessWhy a figure can lag today, what dataAsOf means, and how to get fresher data.
Two different facts, and quoting one as the other is the single most common way to be confidently wrong here.
`lastSyncedAt` — when this app last spoke to Google Ads. It can be seconds old.
`dataAsOf` — the newest reporting day the figures actually cover. It is never today, and it is usually a day or two back. Every read, query and analyze result carries it, with a statement sentence that is safe to quote verbatim.
They are unrelated, and the gap between them is not a bug:
Google's rolling window excludes today. The headline totals on a campaign, ad group, keyword or ad are fetched over Google's own LAST_30_DAYS constant, which Google defines as the last 30 days not including today. So those figures end on the day before the sync ran, however recently it ran.
"Today" is the account's, not yours. Google evaluates every reporting date in the connected account's own reporting time zone. For an account west of UTC, its "yesterday" is two calendar days back for part of every UTC day. This is how a sync that finished a minute ago hands back figures that stop two days ago — both statements are true at once.
So: never present a figure as "today's" or "current". Say the period it covers, using the dataAsOf sentence. A user asking "how are we doing today?" should be told what the data actually ends at.
Sources are dated differently, and must never be mixed. The rolling totals above end at a complete day and carry no partial one. The daily time series behind getPerformance can include a day that is present but still accruing, flagged as a partial day — quoting it as a finished day understates it. Keyword Planner search volumes are Google's own monthly estimates for the market, not this account's traffic at all, and are dated on their own terms.
You can go and get fresher data. syncGoogleAdsData pulls from Google Ads into this app right now and reports the new coverage date. It is a read-side refresh: it changes nothing in the ad account and needs no approval. It is rate-limited to about one refresh a minute per account, and if it is refused for that reason the previous figures still stand. A refresh takes a few seconds to a minute — after it returns, call the read tool you actually needed again, because the result you are holding was fetched before it.
Refreshing will not make today appear. The window still excludes the account's current day. Refresh to close a gap of days, not to get the last hour.
Coverage has a near end as well as a far one. dataAsOf says which day the figures stop at; this app also stores only a bounded window of daily history, so there is a day they start at. A range that reaches back past it has nothing in it — and nothing renders as zeros, blanks and dashes, which is indistinguishable from an account that spent nothing. When getPerformance returns a coverage object, that is what has happened: quote its statement beside any figure from that range, treat those days as absent rather than as zero, and when coverage.whollyUncovered is true say there is no data for those dates instead of reporting an empty report as a result. The range you asked for is never quietly moved to fit — the numbers stay the ones you asked about, and what is missing is named.
A sync can also have failed, or half-succeeded. A connection records its last failure, and a run pulls the account in a sequence of steps — so one that died partway leaves some of the picture fresh and the rest as old as the run before it. Either way the figures are older than lastSyncedAt alone would suggest, and the app's own screens say which parts. If numbers look implausibly stale or a whole category is empty, say so rather than explaining the trend in them.
Status values, and what they do not tell you
status-vocabularyENABLED / PAUSED / REMOVED, proposal statuses, and why an enabled keyword can serve nothing.
Campaign, ad group, keyword and ad status
The same three values at every level, stored exactly as Google reports them:
- ENABLED — Eligible to run, as far as this object's own status is concerned.
- PAUSED — Turned off by someone. It keeps its history and can be enabled again.
- REMOVED — Deleted in Google Ads. Google stops listing it, this app marks the row rather than deleting it, and it can never be enabled again — a replacement has to be created.
A status is about that object alone, and this is the part that misleads. Serving is decided by the whole chain: an ad runs only if its own status, its ad group's, its campaign's and the account itself all allow it. So a keyword can read ENABLED and serve nothing at all because the ad group or the campaign above it is PAUSED — and its row will honestly show zero impressions with no explanation on it.
Before concluding that a keyword is not getting traffic, read its ad group's and its campaign's status. Zero impressions on an ENABLED keyword under a PAUSED parent is not a performance problem; it is the parent. Other ordinary reasons for zero impressions, once the chain is confirmed enabled: the campaign's budget, a bid too low to enter the auction, no ad in the ad group, or a keyword too specific for anyone to have searched it in the period you are looking at.
REMOVED needs one more note: this app marks the row rather than deleting it, so removed objects still appear in the database with their history intact. Read tools filter them out unless you ask for them.
Proposed change status
The lifecycle of a change this assistant proposed — see the change-lifecycle topic for who moves it and when:
- PENDING — Queued and waiting for a human to approve or reject it. Nothing has been sent to Google Ads.
- REJECTED — A human declined it. Nothing was sent to Google Ads and nothing will be.
- APPLIED — A human approved it and Google Ads accepted the write. This is the only status that means the ad account changed.
- FAILED — A human approved it and Google Ads refused the write — a quota wall, an invalid value, a conflicting edit. Deliberately distinct from REJECTED: the decision was yes, the write did not land. The result message says why.
The tools, by what they can affect
toolsWhich tools only read and which can end up changing the ad account.
35 tools, in 10 groups. Only the groups marked "can change the ad account" ever result in a write to Google Ads, and none of them writes directly: each one queues a proposal that a human approves in this app. Everything else reads, or writes only inside this app.
Read — read-only for the ad account
Fetch rows you already know you want, out of this app's synced copy. No live Google Ads call, nothing written anywhere.
Tools: getAdGroups, getAds, getAssets, getCampaigns, getKeywords, getPerformance, getSearchTerms
Query — read-only for the ad account
Answer a question about a set — filter, rank, aggregate — with the arithmetic done in the database and a line stating how much of the set the answer covers. Read-only.
Tools: queryAdGroups, queryAds, queryCampaigns, queryKeywords
Analyze — read-only for the ad account
Run this app's analysis engines over synced data and return findings. They persist recommendations inside this app; they never touch the ad account.
Tools: analyzeAdGroupRelevance, analyzeCampaign, analyzeExistingKeywords, recommendKeywordsForTopic
Change — can change the ad account (through approval)
Propose a change to the ad account. Calling one queues a proposal for human approval and applies nothing — there is no tool that approves, rejects or applies.
Tools: addKeywords, addNegativeKeywords, createAd, createAdGroup, createAdsFromChat, createCampaign, editAd, removeKeywords, setAdStatus, setKeywordStatus, updateCampaignSettings
Generate — can change the ad account (through approval)
Build a whole campaign draft from a learned pattern. The draft is reviewed and published in the campaign wizard rather than approved as one queued change.
Tools: generateCampaignFromPattern
Learn — read-only for the ad account
Extract and read campaign patterns — records this app stores about how an account is already built. Written inside this app only.
Tools: extractCampaignPattern, getCampaignPattern, listCampaignPatterns, resolveCampaignPatternQuestion
Sync — read-only for the ad account
Pull fresher data from Google Ads into this app. It copies Google's data in; it writes nothing to the ad account and needs no approval.
Tools: syncGoogleAdsData
Approvals — read-only for the ad account
Read the queue of changes waiting for a human decision. Read-only, and deliberately without a sibling that decides.
Tools: getPendingChanges
Drafts — read-only for the ad account
List campaigns being built in this app's own campaign wizard — part-built and never published. They are NOT Google Ads campaign drafts or experiments (this app does not sync those), and nothing in this category exists in the ad account or has spent anything. Read-only.
Tools: getDrafts
Reference — read-only for the ad account
Explain this product itself — its objects, ids, statuses, lifecycle and screens.
Tools: getDocumentation
Where things are in the app
ui-mapWhere each screen lives, so you can tell a user where to go.
Paths are relative to this workspace's own installation of ManageAds. Use them to tell a user where to go; a change tool result that carries an absolute link is always the better thing to hand over when you have one.
/— dashboard. What needs attention, and the headline figures./approvals— the Approvals screen in ManageAds: everything waiting for a human decision, and where approving actually happens. This is the answer to "where do I approve?"./campaigns— every campaign. A campaign opens to its own screens:/campaigns/[campaignId]for the overview, then/campaigns/[campaignId]/ad-groups,/campaigns/[campaignId]/keywords,/campaigns/[campaignId]/keywords/negatives,/campaigns/[campaignId]/keywords/search-terms,/campaigns/[campaignId]/ads,/campaigns/[campaignId]/assets,/campaigns/[campaignId]/audiencesand/campaigns/[campaignId]/settings./campaigns/new— the campaign creation wizard, which is also where a generated campaign draft is reviewed and published./ai-assistant— the in-app chat. It runs the same tools as this connection./ai-recommendations— findings the analysis engines produced, to accept or dismiss./alerts— standing account issues detected on a schedule./reports— performance reporting over a date range./performance-analyzer— period-over-period comparison./keyword-research— Keyword Planner ideas and saved keyword lists./assets— the account's images, logos and other assets./audit-history— every change this workspace made, including rejected ones and reverts./settings/connected-accounts— connect a Google Ads account, switch the active one, or refresh manually./settings/mcp— connection tokens for external assistants, and where a user goes to connect or disconnect one.
If a user cannot find a screen you named, they may not have permission for it rather than be looking in the wrong place: editing anywhere in this app requires OWNER, ADMIN or MANAGER.