Google Ads Scripts and Performance Max: What Works
AdsApp.campaigns() returns Search and Display only, so it silently omits Performance Max. Use AdsApp.performanceMaxCampaigns() to retrieve, pause and adjust budgets, or GAQL FROM campaign to cover every channel type in one read. Scripts cannot create PMax campaigns, asset groups, or edit text assets.
Performance Max is usually the largest line in a modern account and the one most script libraries silently omit. The reason is a single method call.
AdsApp.campaigns() does not return Performance Max campaigns. It returns Search and Display. There is no error and no warning — the loop simply runs fewer times, and a pacing or budget script built on it reports on a fraction of the account while looking entirely healthy.
What scripts can do with Performance Max
More than the folklore suggests. Google exposes a dedicated selector, AdsApp.performanceMaxCampaigns(), with the usual filtering and iteration:
const it = AdsApp.performanceMaxCampaigns()
.withCondition('metrics.impressions > 100')
.forDateRange('LAST_30_DAYS')
.get();
while (it.hasNext()) {
const c = it.next();
Logger.log(c.getName() + ' ' + c.getStats().getCost());
}
Through that selector you can retrieve campaigns, pause and enable them, adjust budgets, and reach most asset types inside asset groups. You can run reports across them. That covers the majority of what monitoring work requires.
What scripts cannot do
- Create a Performance Max campaign. Not available through scripts at all.
- Create asset groups. Same.
- Modify text assets. Headlines and descriptions are out of reach.
- Manage retail listing groups. Google describes retail Performance Max support as limited for exactly this reason, so product-level control stays in the interface or the API.
The practical consequence: scripts are a monitoring and reporting tool for Performance Max, not a management tool. Build alerts, not automation.
The reporting route, which is usually the right one
For anything account-wide, skip the selector question entirely and read through GAQL. FROM campaign returns every channel type in one query, with no per-type branching:
SELECT campaign.name,
campaign.advertising_channel_type,
metrics.cost_micros,
metrics.conversions
FROM campaign
WHERE segments.date DURING YESTERDAY
AND campaign.status != 'REMOVED'
Performance Max campaigns carry advertising_channel_type = PERFORMANCE_MAX. Filtering on that field is how you separate them; iterating a selector is how you miss them.
This is why every read-only script on this site queries rather than selects. The spend anomaly alert is the clearest example.
What you still cannot see
Scripts inherit the reporting surface Google chooses to expose, and Performance Max exposes less than Search. Search term data arrives as grouped categories rather than raw terms. Channel-level splits inside a single campaign are not broken out. Asset group reporting exists but is shallower than ad group reporting.
No script fixes this, and any tool claiming to reveal the underlying placements is either inferring them or reporting a different metric than you think. The honest position is to monitor the campaign as a unit and hold your questions at the level the data can answer.
A checklist for auditing an existing script
- Search the file for
AdsApp.campaigns(). If it is there and the script claims to be account-wide, it is not. - Check whether the campaign count in the log matches the campaign count in the interface. A gap is almost always Performance Max, Demand Gen or Video.
- If the script sums spend, compare its total against the account total for the same window. They should match to the currency unit.
That last check takes two minutes and finds the problem in most inherited scripts.
Questions
- Does AdsApp.campaigns() include Performance Max?
- No. It returns Search and Display campaigns. Performance Max requires the dedicated AdsApp.performanceMaxCampaigns() selector or a GAQL report.
- Can a script pause a Performance Max campaign?
- Yes, through AdsApp.performanceMaxCampaigns(). You can also enable campaigns, adjust budgets and reach most asset types within asset groups.
- Can a script create a Performance Max campaign?
- No. Creating Performance Max campaigns and asset groups is not supported in scripts, and text assets cannot be modified.
- How do I report on all campaign types at once?
- Use a GAQL query with FROM campaign. It returns every advertising channel type, including Performance Max, in a single result set.