Stop ads running overnight
Clicks at 3 a.m. rarely turn into customers, but a campaign with no
schedule serves around the clock. An ad schedule (the Google Ads
website also calls this dayparting) restricts a campaign to the days
and hours you pick — and declaring it in a .bid file means the
schedule is visible in review, and anyone quietly widening it in the UI
shows up as drift on the next plan.
Declare the windows
One ad_schedule block covers one day. A window is start_hour to
end_hour on a 24-hour clock, minutes snapping to the quarter hour
("ZERO", "FIFTEEN", "THIRTY", "FORTY_FIVE"). One resource can
hold the whole week — each block becomes its own criterion, the same
way repeated negative_keyword blocks do:
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" }
# ... WEDNESDAY through SUNDAY}When every day gets the same window, writing seven near-identical
blocks is still boilerplate — fan one block out with
for_each
instead:
resource "google_ads_campaign_criterion" "daytime" { for_each = [ "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY", ] campaign = google_ads_campaign.summer_search.id
ad_schedule { day_of_week = each.value start_hour = 8 start_minute = "ZERO" end_hour = 22 end_minute = "ZERO" }}Then the usual loop: bidsmith plan shows one + create per window,
the PR gets reviewed, apply after merge. The campaign now serves
8:00–22:00 in the account’s time zone and spends nothing overnight.
Bid less instead of switching off
If overnight traffic is worth something, keep the campaign on
around the clock and lower bids in the quiet hours instead: give the
quiet window its own criterion and pair it with bid_modifier —
0.7 bids 30% less inside that window.
resource "google_ads_campaign_criterion" "monday_night_trim" { campaign = google_ads_campaign.summer_search.id bid_modifier = 0.7
ad_schedule { day_of_week = "MONDAY" start_hour = 0 start_minute = "ZERO" end_hour = 8 end_minute = "ZERO" }}Remember the caveat above still applies: once any window exists, hours outside every window don’t serve at all. A “cheaper at night” setup declares the day windows and the night windows, with the modifier on the night ones.
Editing and removing windows
- Widening or moving a window — edit the block;
planshows it as a create of the new window plus a destroy of the old one. That’s normal: the window itself is the identity, and Google keeps no history on a schedule window worth preserving. - Back to 24/7 — delete all the
ad_scheduleresources and apply. - A window can’t cross midnight — for “Friday 20:00 to Saturday
2:00”, declare Friday
20–24and Saturday0–2.
Which campaigns can have one
Search, Display, and Demand Gen campaigns all take ad schedules — including Demand Gen video campaigns on YouTube. Video (the classic YouTube campaign type) can’t be changed through the API at all; bidsmith will block the plan and say so.
See also
google_ads_campaign_criterion— the fullad_schedulereference.- Repeat a resource with for_each — the fan-out used above.
- Budget a campaign that runs for a fixed period — date-based rather than hour-based control.