Stop Google writing your ad copy
Your ads are running headlines nobody wrote. They read like your landing page, roughly, with the odd sentence that runs on past where a person would have stopped — and they change without a PR.
That’s asset automation: Google Ads generating headlines and
descriptions for your campaign out of your landing pages, your existing
ads, and generative AI. It’s a campaign setting, so you can declare it
off in your .bid and keep it off.
Say no in the file
resource "google_ads_campaign" "brand_search" { name = "Brand — Search" advertising_channel_type = "SEARCH" campaign_budget = google_ads_campaign_budget.brand.id
asset_automation_settings { text_asset_automation = "OPTED_OUT" final_url_expansion_text_asset_automation = "OPTED_OUT" }}bidsmith plan .google_ads_campaign.brand_search ~ update asset_automation_settings: text_asset_automation=OPTED_IN -> text_asset_automation=OPTED_OUT, fi…
Plan: 0 to create, 1 to update, 0 to destroy, 12 unchanged.bidsmith apply . sends it. From then on the campaign’s ads say what
your files say.
The two settings do different things:
text_asset_automation— the one most people mean. Google writes extra headlines and descriptions across the campaign’s ads.final_url_expansion_text_asset_automation— Google sends clicks to landing pages it picks from your site, and writes copy to match whichever page it picked. Turning this off is also what makes turning the first one off complete: while URL expansion runs, generated text comes with it.
Keeping it off
The value of declaring it is what happens next time. Someone opens the
Google Ads UI, switches text customization back on, and the next plan
says so:
google_ads_campaign.brand_search ~ update asset_automation_settings: text_asset_automation=OPTED_IN, fi… -> text_asset_automation=OPTED_O…Run bidsmith plan --detailed-exitcode . in CI and that drift fails the
build. Nothing has to be noticed by a person.
Two limits worth knowing:
- These settings exist on Search and Performance Max campaigns
only.
bidsmith validatewarns if you put the block on anything else. - Defaults differ: a Search campaign starts opted out of text automation and URL expansion, a Performance Max campaign starts opted in to everything, including image and video generation.
The sibling switch: AI Max
Opting out of asset automation says “do not write my ad copy.” AI Max is the setting that lets Google decide which searches your ads answer — and write copy for the ones your keywords never named. Same fence, different post, and a campaign that never mentions it follows whatever Google’s default is on the day:
resource "google_ads_campaign" "brand_search" { name = "Brand — Search" advertising_channel_type = "SEARCH" campaign_budget = google_ads_campaign_budget.brand.id
asset_automation_settings { text_asset_automation = "OPTED_OUT" final_url_expansion_text_asset_automation = "OPTED_OUT" }
ai_max_setting { enable_ai_max = false }}
resource "google_ads_ad_group" "brand" { name = "Brand terms" campaign = google_ads_campaign.brand_search.id type = "SEARCH_STANDARD"
ai_max_ad_group_setting { disable_search_term_matching = true }}The campaign-level switch is the one that matters; the ad-group one is there for the case where AI Max is on across the campaign and one ad group should keep matching only what it declares.
google_ads_campaign.brand_search ~ update ai_max_setting.enable_ai_max: (unset) -> falseAn (unset) on the left is the point of writing the line: the account
was not saying no, it was saying nothing. AI Max is a Search-campaign
feature — validate warns if the block turns up anywhere else.
The third one: dynamic search ads
Asset automation writes copy for the ads you declared. AI Max decides which searches they answer. Dynamic search ads skip the ads entirely: Google crawls your site and generates a headline and a landing page per search.
It is not an on/off flag but a targeting mode, so it is declared as the scope it is:
resource "google_ads_campaign" "site_wide" { name = "Site — dynamic" advertising_channel_type = "SEARCH" campaign_budget = google_ads_campaign_budget.site.id
dynamic_search_ads_setting { domain_name = "example.com" language_code = "en" use_supplied_urls_only = true }}use_supplied_urls_only = true is the important line: Google may still
generate headlines, but only against landing pages you supplied, instead
of anything it finds on the domain.
The case worth checking for is a campaign that has this and never
mentions it — often a paused one nobody has looked at in a while, where
nothing is serving today and enabling it would start generated ads with
no diff anywhere. plan will not switch it off (a setting no file
declares is not bidsmith’s to clear), but it does say so every run:
plan: warning: google_ads_campaign.site_wide has dynamic search adsconfigured live (example.com (en)) and declares no`dynamic_search_ads_setting` block: Google writes headlines and pickslanding pages from that site, and nothing in the file says so.Run bidsmith refresh --in-place . to write the live values into the
file, and it is under review like everything else.
The switch that isn’t in the file
Dynamic sitelinks, dynamic callouts, and the business name and logo that
Google attaches by itself are a different feature: an account-level
“automatically created assets” setting that the Google Ads API does not
expose at all. No .bid can turn it off.
What bidsmith can do is stop the results serving, and tell you the switch is on:
plan: warning: account: Google's asset automation is serving 6 asset(s)nothing declares (4 SITELINK, 2 CALLOUT). Add`owns = ["automatically_created_assets"]` to the campaign — or to the`provider` block for the account-level ones — and bidsmith will pause themso they stop serving.That line comes back on every plan while the switch is on, so flipping it in the UI is caught on the next run.
-
Claim what it already attached. Add
owns = ["automatically_created_assets"]to the campaign, or to theproviderblock for account-level assets. The nextplanshows a~ pauserow per asset, andapplystops them serving. They are paused rather than deleted because Google reattaches anything bidsmith removes — see Serve only the extensions you declared. -
Turn the switch off in the Google Ads UI so no new ones are made. Admin → Account settings → Automatically created assets.
-
Run
bidsmith plan .and check the warning is gone.
See also
- Serve only the extensions you declared — removing sitelinks and callouts nobody declared, and pausing what Google attached.
google_ads_campaign— the fullasset_automation_settingsreference.bidsmith plan— reading an update row.