Skip to content

Commit c00a4e5

Browse files
committed
Add Demand Gen example
Change-Id: I309e7ccd7b220afb63d6dbe592435dd6b23727b9
1 parent ff227e2 commit c00a4e5

File tree

1 file changed

+248
-0
lines changed

1 file changed

+248
-0
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
#!/usr/bin/env ruby
2+
# Encoding: utf-8
3+
#
4+
# Copyright 2025 Google LLC
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
# This example shows how to create a Demand Gen campaign with a video ad.
19+
#
20+
# For more information about Demand Gen campaigns, see
21+
# https://developers.google.com/google-ads/api/docs/demand-gen/overview
22+
23+
require 'optparse'
24+
require 'google/ads/google_ads'
25+
require 'date'
26+
require 'open-uri'
27+
28+
# Temporary IDs for resources.
29+
BUDGET_TEMPORARY_ID = -1
30+
CAMPAIGN_TEMPORARY_ID = -2
31+
AD_GROUP_TEMPORARY_ID = -3
32+
VIDEO_ASSET_TEMPORARY_ID = -4
33+
LOGO_ASSET_TEMPORARY_ID = -5
34+
35+
# URLs for assets
36+
DEFAULT_LOGO_IMAGE_URL = "https://gaagl.page.link/bjYi"
37+
DEFAULT_FINAL_URL = "http://example.com/demand_gen"
38+
39+
def add_demand_gen_campaign(customer_id, video_id)
40+
client = Google::Ads::GoogleAds::GoogleAdsClient.new
41+
42+
budget_resource_name = client.path.campaign_budget(customer_id, BUDGET_TEMPORARY_ID)
43+
campaign_resource_name = client.path.campaign(customer_id, CAMPAIGN_TEMPORARY_ID)
44+
ad_group_resource_name = client.path.ad_group(customer_id, AD_GROUP_TEMPORARY_ID)
45+
video_asset_resource_name = client.path.asset(customer_id, VIDEO_ASSET_TEMPORARY_ID)
46+
logo_asset_resource_name = client.path.asset(customer_id, LOGO_ASSET_TEMPORARY_ID)
47+
48+
# [START add_demand_gen_campaign_1]
49+
operations = []
50+
51+
operations << client.operation.mutate do |m|
52+
m.campaign_budget_operation = create_campaign_budget_operation(client, budget_resource_name)
53+
end
54+
55+
operations << client.operation.mutate do |m|
56+
m.campaign_operation = create_demand_gen_campaign_operation(client, campaign_resource_name, budget_resource_name)
57+
end
58+
59+
operations << client.operation.mutate do |m|
60+
m.ad_group_operation = create_ad_group_operation(client, ad_group_resource_name, campaign_resource_name)
61+
end
62+
63+
operations += create_asset_operations(client, video_asset_resource_name, video_id, logo_asset_resource_name).map do |asset_op|
64+
client.operation.mutate do |m|
65+
m.asset_operation = asset_op
66+
end
67+
end
68+
69+
operations << client.operation.mutate do |m|
70+
m.ad_group_ad_operation = create_demand_gen_ad_operation(client, ad_group_resource_name, video_asset_resource_name, logo_asset_resource_name)
71+
end
72+
73+
response = client.service.google_ads.mutate(
74+
customer_id: customer_id,
75+
mutate_operations: operations,
76+
)
77+
# [END add_demand_gen_campaign_1]
78+
79+
puts "Created campaign with resource name '#{response.mutate_operation_responses.first.campaign_result.resource_name}'"
80+
end
81+
82+
# [START add_demand_gen_campaign_2]
83+
def create_campaign_budget_operation(client, budget_resource_name)
84+
# Creates a campaign budget.
85+
client.operation.create_resource.campaign_budget do |cb|
86+
cb.name = "Demand Gen campaign budget #{Time.now.to_f}"
87+
# The budget period already defaults to DAILY.
88+
cb.amount_micros = 50_000_000
89+
cb.delivery_method = :STANDARD
90+
91+
# A Demand Gen campaign cannot use a shared campaign budget.
92+
cb.explicitly_shared = false
93+
94+
# Set a temporary ID in the budget's resource name so it can be referenced
95+
# by the campaign in later steps.
96+
cb.resource_name = budget_resource_name
97+
end
98+
end
99+
# [END add_demand_gen_campaign_2]
100+
101+
# [START add_demand_gen_campaign_3]
102+
def create_demand_gen_campaign_operation(client, campaign_resource_name, budget_resource_name)
103+
client.operation.create_resource.campaign do |c|
104+
c.name = "Demand Gen ##{Time.now.to_f}"
105+
106+
# Recommendation: Set the campaign to PAUSED when creating it to
107+
# prevent the ads from immediately serving. Set to ENABLED once you've
108+
# added targeting and the ads are ready to serve.
109+
c.status = :PAUSED
110+
111+
# AdvertisingChannelType must be DEMAND_GEN.
112+
c.advertising_channel_type = :DEMAND_GEN
113+
114+
# Assign the resource name with a temporary ID.
115+
c.resource_name = campaign_resource_name
116+
117+
# Set the budget using the given budget resource name.
118+
c.campaign_budget = budget_resource_name
119+
120+
# Use the Target CPA bidding strategy.
121+
c.bidding_strategy_type = :TARGET_CPA
122+
c.target_cpa = client.resource.target_cpa do |tc|
123+
tc.target_cpa_micros = 1_000_000
124+
end
125+
126+
# Declare whether or not this campaign serves political ads targeting the EU.
127+
# Valid values are CONTAINS_EU_POLITICAL_ADVERTISING and
128+
# DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING.
129+
c.contains_eu_political_advertising = :DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING
130+
131+
# Optional fields
132+
c.start_date = DateTime.parse((Date.today + 1).to_s).strftime('%Y%m%d')
133+
c.end_date = DateTime.parse(Date.today.next_year.to_s).strftime('%Y%m%d')
134+
end
135+
end
136+
# [END add_demand_gen_campaign_3]
137+
138+
# [START add_demand_gen_campaign_4]
139+
def create_ad_group_operation(client, ad_group_resource_name, campaign_resource_name)
140+
# Creates an ad group.
141+
client.operation.create_resource.ad_group do |ag|
142+
ag.resource_name = ad_group_resource_name
143+
ag.name = "Earth to Mars Cruises ##{Time.now.to_f}"
144+
ag.status = :ENABLED
145+
ag.campaign = campaign_resource_name
146+
end
147+
end
148+
# [END add_demand_gen_campaign_4]
149+
150+
def create_asset_operations(client, video_asset_resource_name, video_id, logo_asset_resource_name)
151+
[
152+
create_video_asset_operation(client, video_asset_resource_name, video_id, "Video"),
153+
create_image_asset_operation(client, logo_asset_resource_name, DEFAULT_LOGO_IMAGE_URL, "Square Marketing Image"),
154+
]
155+
end
156+
157+
# [START add_demand_gen_campaign_5]
158+
def create_demand_gen_ad_operation(client, ad_group_resource_name, video_asset_resource_name, logo_asset_resource_name)
159+
client.operation.create_resource.ad_group_ad do |aga|
160+
aga.ad_group = ad_group_resource_name
161+
aga.status = :ENABLED
162+
aga.ad = client.resource.ad do |ad|
163+
ad.name = "Demand gen multi asset ad"
164+
ad.final_urls << DEFAULT_FINAL_URL
165+
ad.demand_gen_video_responsive_ad = client.resource.demand_gen_video_responsive_ad_info do |dgv|
166+
dgv.business_name = client.resource.ad_text_asset do |ata|
167+
ata.text = "Interplanetary Cruises"
168+
end
169+
dgv.videos << client.resource.ad_video_asset do |ava|
170+
ava.asset = video_asset_resource_name
171+
end
172+
dgv.logo_images << client.resource.ad_image_asset do |aia|
173+
aia.asset = logo_asset_resource_name
174+
end
175+
dgv.headlines << client.resource.ad_text_asset do |ata|
176+
ata.text = "Interplanetary cruises"
177+
end
178+
dgv.long_headlines << client.resource.ad_text_asset do |ata|
179+
ata.text = "Travel the World"
180+
end
181+
dgv.descriptions << client.resource.ad_text_asset do |ata|
182+
ata.text = "Book now for an extra discount"
183+
end
184+
end
185+
end
186+
end
187+
end
188+
# [END add_demand_gen_campaign_5]
189+
190+
def create_image_asset_operation(client, asset_resource_name, url, asset_name)
191+
client.operation.create_resource.asset do |a|
192+
a.resource_name = asset_resource_name
193+
a.name = asset_name
194+
a.type = :IMAGE
195+
a.image_asset = client.resource.image_asset do |ia|
196+
ia.data = URI.open(url).read
197+
end
198+
end
199+
end
200+
201+
def create_video_asset_operation(client, asset_resource_name, video_id, asset_name)
202+
client.operation.create_resource.asset do |a|
203+
a.resource_name = asset_resource_name
204+
a.name = asset_name
205+
a.type = :YOUTUBE_VIDEO
206+
a.youtube_video_asset = client.resource.youtube_video_asset do |yva|
207+
yva.youtube_video_id = video_id
208+
end
209+
end
210+
end
211+
212+
if __FILE__ == $0
213+
options = {}
214+
# The following parameter(s) should be provided to run the example. You can
215+
# either specify them here or provide them as positional arguments when
216+
# running the code.
217+
#
218+
# e.g. ruby add_demand_gen_campaign.rb -C YOUR_CUSTOMER_ID -V YOUR_VIDEO_ID
219+
OptionParser.new do |opts|
220+
opts.banner = "Usage: add_demand_gen_campaign.rb [options]"
221+
222+
opts.on("-C", "--customer_id CUSTOMER-ID", "Customer ID") do |v|
223+
options[:customer_id] = v
224+
end
225+
226+
opts.on("-V", "--video_id VIDEO-ID", "Video ID") do |v|
227+
options[:video_id] = v
228+
end
229+
end.parse!
230+
231+
begin
232+
add_demand_gen_campaign(
233+
options.fetch(:customer_id).tr("-", ""),
234+
options.fetch(:video_id),
235+
)
236+
rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
237+
e.failure.errors.each do |error|
238+
STDERR.printf("Error with message: %s\n", error.message)
239+
if error.location
240+
error.location.field_path_elements.each do |field_path_element|
241+
STDERR.printf("\tOn field: %s\n", field_path_element.field_name)
242+
end
243+
end
244+
end
245+
raise
246+
end
247+
end
248+

0 commit comments

Comments
 (0)