Skip to content

Reuse a headline set across many ads

You have one good set of headlines, and it’s pasted — verbatim — into twenty responsive search ads. Same descriptions. Same competitor keyword list in every ad group. When the legal team tweaks one line, you get to find the other nineteen copies and change them by hand.

The fix is a local that holds the list, and ads that reference it instead of copying it.

Name the list once

A locals block can hold a list, not just a single value. Put your headline set, description set, and any shared keyword themes in one place:

locals {
brand_headlines = [
"Ghostery Blocks Trackers",
"Privacy That Just Works",
"Switch to Ghostery Free",
{ text = "Ghostery — Private by Default", pin = "HEADLINE_1" },
]
brand_descriptions = [
"Block ads, trackers, and popups. Manifest V3 ready.",
"The privacy extension millions of people already trust.",
]
competitor_terms = ["ublock", "ublock origin", "adblock alternative"]
}

Headlines can be plain strings or { text, pin } objects for pinned positions — mix both in one list, just like an inline headlines list.

Point every ad at it

Anywhere an attribute expects a list, hand it the local. reference:

resource "google_ads_ad_group_ad" "search_ad_1" {
ad_group = google_ads_ad_group.core.id
ad {
final_urls = ["https://ghostery.com/get"]
responsive_search_ad {
headlines = local.brand_headlines
descriptions = local.brand_descriptions
}
}
}
resource "google_ads_ad_group_ad" "search_ad_2" {
ad_group = google_ads_ad_group.core.id
ad {
final_urls = ["https://ghostery.com/extension"]
responsive_search_ad {
headlines = local.brand_headlines
descriptions = local.brand_descriptions
}
}
}

Two ads, one source of truth. Edit a headline in the local, run bidsmith plan, and the change shows up on every ad that points at the list — that fan-out is exactly what you want.

Reuse a keyword list too

The same trick works for keywords. A compact keywords block already turns a texts list into one keyword each, so point texts at a local:

resource "google_ads_ad_group_criterion" "competitors" {
ad_group = google_ads_ad_group.core.id
keywords {
texts = local.competitor_terms
match_type = "PHRASE"
}
}

It also works for final_urls, and for a campaign’s languages / locations lists — so every campaign can share one geo/language list.

Merge a shared tail into per-ad headlines

Most real accounts don’t share the whole list — each ad opens with its own hook, then closes with the same brand tail (“Add to Chrome, Free”, “Open Source & Private”, …). concat() merges lists in order, so keep the tail in one local and prepend the ad-specific lines inline:

locals {
brand_tail = [
"Add to Chrome, Free",
"Open Source & Private",
"100M+ Downloads Worldwide",
]
}
resource "google_ads_ad_group_ad" "cookie_popups" {
ad_group = google_ads_ad_group.popups.id
ad {
final_urls = ["https://ghostery.com/get"]
responsive_search_ad {
headlines = concat(["Stop Cookie Pop-Ups for Good"], local.brand_tail)
descriptions = local.brand_descriptions
}
}
}

A brand-copy edit now touches one local instead of every RSA in every file. Pinned { text, pin } objects and bare strings mix freely in the merged result, and the usual checks (at least 3 headlines, the 30-character cap) run on the combined list.

Share it across files

If the same set is copied across several campaign files, lift it into one file that holds nothing but locals — call it shared.bid:

shared.bid
locals {
brand_headlines = [ /* ... */ ]
brand_descriptions = [ /* ... */ ]
competitor_terms = [ /* ... */ ]
}

Every other file in the folder references local.brand_headlines and bidsmith resolves it from the shared file. One declaration for the whole account; one place to edit.

See also