google_ads_campaign_criterion
A campaign criterion is targeting that applies to a whole campaign: negative keywords (excluded across every ad group), geo targets (which locations your ads can show in), language targets, proximity (latitude / longitude radius around a point), ad schedules (which days and hours the campaign runs), and device bid adjustments (spend more or less — or nothing at all — on a device type).
For video campaigns it is also how you say who should see the ad and where it can run: audiences, YouTube channels and videos, topics, interests, and age / gender.
Example
Block negative keywords campaign-wide:
resource "google_ads_campaign_criterion" "summer_negatives" { campaign = google_ads_campaign.summer_search.id status = "ENABLED"
negative_keyword { text = "free" match_type = "BROAD" }
negative_keyword { text = "diy" match_type = "BROAD" }
negative_keyword { text = "used" match_type = "BROAD" }}Or, more compactly, with a negative_keywords list (optionally fanned
out across match_types):
resource "google_ads_campaign_criterion" "summer_negatives" { campaign = google_ads_campaign.summer_search.id status = "ENABLED"
negative_keywords { match_type = "BROAD" texts = ["free", "diy", "used"] }}Target the United States (geo target constant 2840):
resource "google_ads_campaign_criterion" "summer_geo_us" { campaign = google_ads_campaign.summer_search.id status = "ENABLED"
location { geo_target_constant = "geoTargetConstants/2840" }}Target Polish-speaking users (language constant 1030):
resource "google_ads_campaign_criterion" "summer_lang_pl" { campaign = google_ads_campaign.summer_search.id status = "ENABLED"
language { language_constant = "languageConstants/1030" }}Show only within 15 km of central Warsaw:
resource "google_ads_campaign_criterion" "summer_warsaw" { campaign = google_ads_campaign.summer_search.id status = "ENABLED"
proximity { latitude = 52.229675 longitude = 21.012228 radius = 15 radius_units = "KILOMETERS" }}Only spend during waking hours — one ad_schedule block per day, and
one resource can hold the whole week, the same way one resource holds
many negative_keyword blocks. Each block becomes its own criterion in
the account. A campaign with no schedule runs around the clock; the
moment you declare one window, the campaign serves only inside the
windows you declare:
resource "google_ads_campaign_criterion" "daytime" { campaign = google_ads_campaign.summer_search.id
ad_schedule { day_of_week = "MONDAY" start_hour = 8 start_minute = "ZERO" end_hour = 22 end_minute = "ZERO" }
ad_schedule { day_of_week = "TUESDAY" start_hour = 8 start_minute = "ZERO" end_hour = 22 end_minute = "ZERO" }}Stop showing on mobile entirely — a bid_modifier of 0 is a −100%
adjustment, so nothing spends there. This is the classic setup for a
browser-extension campaign, where installs only happen on desktop and
mobile clicks are wasted budget:
resource "google_ads_campaign_criterion" "no_mobile" { campaign = google_ads_campaign.extension_installs.id bid_modifier = 0.0
device { type = "MOBILE" }}Or nudge bids rather than switch a device off — bid 20% more on desktop
(bid_modifier = 1.2) and 30% less on tablets (bid_modifier = 0.7):
resource "google_ads_campaign_criterion" "desktop_boost" { campaign = google_ads_campaign.summer_search.id bid_modifier = 1.2
device { type = "DESKTOP" }}
resource "google_ads_campaign_criterion" "tablet_trim" { campaign = google_ads_campaign.summer_search.id bid_modifier = 0.7
device { type = "TABLET" }}Narrowing a video campaign
Video campaigns are the case where targeting is the strategy. Show only to people who searched for what you sell, on the channels where they already watch, and exclude the slices you don’t want:
resource "google_ads_campaign_criterion" "privacy_intent" { campaign = google_ads_campaign.instream.id
audience { custom_audience = google_ads_custom_audience.privacy_searchers.id }}
resource "google_ads_campaign_criterion" "tech_channel" { campaign = google_ads_campaign.instream.id
youtube_channel { channel_id = "UCXuqSBlHAE6Xw-yeJA0Tunw" }}
resource "google_ads_campaign_criterion" "exclude_under_25" { campaign = google_ads_campaign.instream.id negative = true
age_range { type = "AGE_RANGE_18_24" }}Every one of these blocks takes negative = true to flip it from
“target this” to “exclude this” — the same switch negative keywords use.
Schema
Required
-
campaign( Reference togoogle_ads_campaign)
Optional
-
status( String ) One of:ENABLED,PAUSED,REMOVED. Default"ENABLED"; omit to manage at the default. -
negative( Boolean ) Defaultfalse; omit to manage at the default. -
bid_modifier( Number )
Nested blocks documented below: keyword, negative_keyword, negative_keywords, device, location, language, proximity, ad_schedule, youtube_channel, youtube_video, topic, user_interest, age_range, gender, audience.
Nested blocks
keyword
A positive keyword scoped to the entire campaign. Uncommon — usually keywords live at ad-group scope. Use this only if you genuinely want a keyword to apply across every ad group.
Required
-
text( String ) -
match_type( String ) One of:EXACT,PHRASE,BROAD.
negative_keyword
A negative keyword that excludes searches campaign-wide. Repeat the
block to list many. The most common use of google_ads_campaign_criterion.
Required
-
text( String ) -
match_type( String ) One of:EXACT,PHRASE,BROAD.
negative_keywords
The compact form: a list of texts fanned out across a single
match_type or a list of match_types. One block stands in for many
negative_keyword blocks. Set exactly one of match_type or match_types.
Required
-
texts( List of String )
Optional
-
match_type( String ) One of:EXACT,PHRASE,BROAD. -
match_types( List of String )
location
A geo target — restricts where your ads can show. Use Google’s
geo target constants
(e.g. geoTargetConstants/2840 for the United States).
Required
-
geo_target_constant( String )
language
A language target — restricts what user-language settings can see your
ads. Use Google’s
language constants
(e.g. languageConstants/1030 for Polish, languageConstants/1000 for English).
Required
-
language_constant( String )
proximity
A circular radius target — ads only show to users within radius of
the given (latitude, longitude). Use for hyperlocal campaigns.
Required
-
latitude( Number ) -
longitude( Number ) -
radius( Number ) -
radius_units( String ) One of:MILES,KILOMETERS.
ad_schedule
One day-and-hours window the campaign is allowed to serve in — the
setting the Google Ads website calls an ad schedule (or dayparting).
Repeat the block for each day: a Monday-to-Friday 8:00–22:00 schedule
is five ad_schedule blocks — in one resource or spread across
several — and lands as five criteria, one per day. Minutes snap to the
quarter hour ("ZERO", "FIFTEEN", "THIRTY", "FORTY_FIVE"), hours
run 0–24, and a window can’t cross midnight — for an overnight window,
declare one block up to 24 and another from 0.
Pair a window with the resource’s bid_modifier to bid more or less in
that window instead of switching the rest of the week off entirely; the
modifier applies to every window in the resource, so give a differently
weighted window its own resource.
Works on Search and Demand Gen campaigns alike.
Required
-
day_of_week( String ) One of:MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY. -
start_hour( Number ) -
start_minute( String ) One of:ZERO,FIFTEEN,THIRTY,FORTY_FIVE. -
end_hour( Number ) -
end_minute( String ) One of:ZERO,FIFTEEN,THIRTY,FORTY_FIVE.
device
A device bid adjustment. Pair a device block with the resource’s
bid_modifier attribute to spend more, less, or nothing on a device
type. type is one of MOBILE, DESKTOP, TABLET, CONNECTED_TV,
or OTHER.
bid_modifier is a multiplier on your bid: 1.0 is no change, 1.25
bids 25% more, 0.5 bids 50% less, and 0.0 is a −100% adjustment that
opts the device out completely. Editing the modifier later is an
in-place update — Google Ads keeps the campaign’s history.
You only need to declare the device types you’re adjusting. As soon as a
campaign has any device adjustment, Google Ads quietly adds entries for
every other device type (desktop, mobile, tablet, and so on) at no
adjustment — that’s normal, and bidsmith leaves them alone. If one of
those undeclared types picks up an adjustment outside your files (say,
someone changes it in the Google Ads website), plan prints a warning:
add a matching device block to take it over, or leave out
bid_modifier to clear the adjustment.
Required
-
type( String ) One of:MOBILE,DESKTOP,TABLET,CONNECTED_TV,OTHER.
audience
Who should see the ad, by audience. Set exactly one of three sources:
custom_audience— a segment you build yourself from search terms, URLs, or apps. Point it at agoogle_ads_custom_audienceyou declare, or paste the resource name of one that already exists (customers/1234567890/customAudiences/9876).user_list— a remarketing list (site visitors, customer match). bidsmith doesn’t build these; name the existing list by its resource name.combined_audience— an audience assembled in the Google Ads website out of other audiences, again named by resource name.
Optional
-
custom_audience( reference_or_resource_name ) -
user_list( String ) -
combined_audience( String )
youtube_channel
A YouTube channel to run on (or, with negative = true, to stay off).
channel_id is the UC… id in the channel’s URL —
youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw. For a channel that only
shows a handle (youtube.com/@somechannel), open any of its videos and
click the channel name to get the UC… form.
Required
-
channel_id( String )
youtube_video
A single YouTube video to run on. video_id is the 11-character id
after watch?v=.
Required
-
video_id( String )
topic
A subject category — ads run on videos and pages about that topic. Use
Google’s
verticals table
for the id (e.g. topicConstants/278 for Computers & Electronics).
Required
-
topic_constant( String )
user_interest
An affinity or in-market audience — people Google has classified by interest or purchase intent. Use Google’s user interest table for the id.
Required
-
user_interest_category( String )
age_range
An age bracket. Most often used with negative = true to exclude one.
Note AGE_RANGE_UNDETERMINED — people Google can’t place in a bracket,
which is a large share of viewers; excluding it cuts reach hard.
Required
-
type( String ) One of:AGE_RANGE_18_24,AGE_RANGE_25_34,AGE_RANGE_35_44,AGE_RANGE_45_54,AGE_RANGE_55_64,AGE_RANGE_65_UP,AGE_RANGE_UNDETERMINED.
gender
A gender bracket, with the same UNDETERMINED caveat as age_range.
Required
-
type( String ) One of:MALE,FEMALE,UNDETERMINED.
See also
google_ads_campaign— required parent.google_ads_custom_audience— build the segment anaudienceblock targets.google_ads_ad_group_criterion— the same targeting scoped to one ad group, for when ad groups in a campaign should differ.google_ads_shared_set— share negative lists across campaigns.- Recipe: Narrow a video campaign to a specific audience.