What you'll learn in this article
- The real case for why I automate google ads campaign naming with margins using scripts instead of naming by hand
- The margin-driven convention itself: what each segment of the name means and where the margin band comes from
- How I automate google ads campaign naming using google sheets and scripts, with the external-data read that keeps finance in control
- The exact
setName()rewrite pattern, guarded so a rerun never doubles a suffix - The reporting errors this quietly prevents: split rows, mismatched filters, broken regex segments
- The guardrails I never skip before letting a naming script touch a live account
The reason I automate google ads campaign naming with margins using scripts has nothing to do with tidiness and everything to do with reporting that doesn't lie. When a campaign name carries the product's margin band, every downstream report, filter, and pivot inherits that context for free, and I stop making profitability decisions off revenue alone. Naming that by hand across dozens of campaigns is where the errors creep in: a typo, a missed rename after a margin shifts, a convention two people interpret differently. A script removes all three at once.
This is a narrow, practical piece sitting under the broader pillar on google ads automation. I'm not arguing that every account needs this; I'm showing the one real case where a margin-aware naming convention, driven by external data, paid for itself in cleaner reporting almost immediately. The angle is deliberately concrete: the convention, how I wire it up, and the specific mistakes it stops.
Why a margin-aware naming convention at all
A campaign name is the one label that travels everywhere. It shows up in the Google Ads UI, in every export, in Looker Studio, in the spreadsheet a client scans on Monday. If that name encodes something useful, you get that signal in every one of those places without lifting a finger. Margin is the signal I most often want and most rarely have: Google Ads knows conversion value, but it has no idea what any of it actually costs me.
So the convention I settled on bakes a margin band straight into the name, something like [HM] Search - Kitchen - Brand where HM means high-margin. Once that's in place, a strategist can filter to high-margin
campaigns in seconds, and a target-ROAS conversation stops being abstract. The catch is that margin data lives in finance's world, not Google's, which is exactly why the naming has to be scripted and fed from outside. Doing it once
by hand is fine; keeping it correct as margins move is not, and that's the practical trigger to automate google ads campaign naming with margins using scripts.
The real case: naming tied to margins via external data
Here's the actual situation that pushed me into this. An e-commerce account had campaigns split by product line, and the client's margins on those lines were nothing alike: some sold at forty percent, some at single digits after shipping. Reporting on revenue made the thin-margin lines look like heroes. The fix wasn't a new report; it was making the campaign name itself carry the margin band so every existing report suddenly meant something.
The margin numbers came from a finance-owned spreadsheet, updated monthly. That's the "external data" part: the script doesn't decide margins, it reads them. I map each campaign to a product line, look that line up in the sheet, translate the raw margin into a band (HM, MM, LM), and rewrite the name so the band is the first segment. Because the mapping and the bands live in the sheet, finance can shift a threshold and the next run relabels everything, no code touched. This is the same separation-of-concerns idea behind how I integrate Google Sheets with scripts generally: business logic in the sheet, execution in the script.
I infer the value here rather than quote a benchmark, because the benefit isn't a metric, it's the absence of a recurring argument. Once the band is in the name, nobody debates which campaigns are worth scaling; the reports answer it. That's the whole case in one line.
How I set it up
The mechanics are simpler than the payoff suggests. The script reads a mapping and margin bands from a sheet, iterates campaigns, computes the target name, and applies it with setName(). The official reference for renaming
a campaign this way is Google's documentation for the
AdsApp.Campaign setName method,
which is the single method doing the real work.
Read the margin bands from the sheet
The read is one block, values pulled as a 2D array so I work in memory rather than hitting the sheet per campaign. Each row maps a product line to its current margin band.
function main() {
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/xxxx/edit');
var rows = ss.getSheetByName('margins').getRange(2, 1, ss.getSheetByName('margins').getLastRow() - 1, 2).getValues();
var bandFor = {};
rows.forEach(function(r) { bandFor[r[0]] = r[1]; }); // line -> HM/MM/LM
renameCampaigns(bandFor);
}
Rewrite the name, guarded against reruns
The rewrite is where discipline matters. I strip any existing band prefix first, then prepend the current one, so running the script twice never produces [HM] [HM] .... That idempotence is the difference between a safe scheduled
job and a mess.
function renameCampaigns(bandFor) {
var it = AdsApp.campaigns().get();
while (it.hasNext()) {
var c = it.next();
var line = lineFromName(c.getName()); // your line parser
var band = bandFor[line];
if (!band) continue; // no margin data, leave it
var base = c.getName().replace(/^\[(HM|MM|LM)\]\s*/, '');
var next = '[' + band + '] ' + base;
if (next !== c.getName()) c.setName(next); // only write on real change
}
}
Two details save real pain: the regex strip makes the operation repeatable, and the next !== current check means the script only writes when the band actually changed, keeping the change history clean. Because the thresholds
live in the sheet rather than the code, a non-coder can adjust a band boundary and the next run relabels everything without anyone opening the script.
The reporting errors this quietly avoids
This is the part I care about most, because a naming convention only earns its place if it prevents concrete mistakes. Here's what a scripted, margin-aware convention stops.
Split rows from inconsistent names
When names are typed by hand, Search - Kitchen and Search Kitchen (double space) become two different rows in any grouped report. A script emits one canonical string every time, so a pivot on campaign name never
fragments the same campaign across two lines. That single class of error probably caused me more silent miscounts than anything else before I scripted it.
Filters and regex segments that quietly miss
Most reporting dashboards filter or segment on a slice of the campaign name. If the band position or delimiter drifts, a Looker Studio filter like "starts with [HM]" silently drops campaigns that should match. Because the script always writes the band as the first segment with a fixed delimiter, those filters stay reliable. This is the reporting side of the same coin I cover when I automate Google Ads reporting: the report is only as trustworthy as the names it groups on.
Stale bands after margins move
The subtlest error isn't a typo, it's a name that was right last quarter and is wrong now. Manual naming has no mechanism to catch that. Because the script re-reads the finance sheet on every scheduled run, a margin that drops from high to low relabels the campaign automatically, and the reports follow. Nobody has to remember to do it, which is precisely why the mistake stops happening.
The guardrails I never skip
A script that renames live campaigns is a script that can quietly break every saved filter, automated rule, and Editor bulk sheet that keys on the old name. So I gate it. I run the preview first and log every intended rename without applying it, reading the log like a diff before I let it write. I keep the parser conservative: if a campaign name doesn't match the expected shape, the script skips it rather than guessing, because a wrong rename is worse than no rename.
I also weigh whether a script is even the right tool. Renaming is irreversible in the sense that anything downstream referencing the old string breaks, so this is one place I'm cautious about automation for its own sake, a caution I unpack in the piece on the downsides of automation scripts. My rule: automate the naming only when the margin data genuinely changes often enough that manual upkeep would drift. If margins are static, a one-time manual pass is honestly fine. The script earns its keep specifically because the external data moves.
FAQ on automating campaign naming with scripts
Which method actually renames the campaign?
campaign.setName(newName) on an AdsApp.Campaign object does the rename. You select the campaigns, compute the new name in memory, then call setName() only when the value has actually changed,
which keeps the change history clean and avoids pointless writes.How do the margins get into the name if Google Ads doesn't know them?
Won't running it twice double the prefix?
[HM] [HM] ... can't happen. Idempotence is the single most important property of a naming script you plan
to schedule.