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:
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
- Locals — the full reference, including chains and module scope.
- Add a whole keyword list at once
— the compact
keywordsblock this recipe reuses.