Put a video ad's tracking URL under review
A YouTube video test is measured on the UTM parameters hanging off its
landing page URL — something like
?utm_campaign=GH_YouTubeUS_v1_0811-instream. Get that slug wrong and
the campaign still runs, still spends, and reports its results into the
wrong bucket, or into no bucket at all.
If the ad was built in the Google Ads UI and left there, that slug is a
text field in a web form. Nobody reviews it, nothing diffs it, and the
only way to check it is to click into the ad. This recipe brings the ad
itself into your .bid files so the URL is a line someone approves.
Pull the ad you already have
You don’t write the block by hand. refresh reads the account and
renders the live creative into a .bid file:
bidsmith refresh -o campaigns/youtube-us.bidThe video ad comes out looking like this:
resource "google_ads_youtube_video_asset" "ghostery_12s" { youtube_video_id = "dQw4w9WgXcQ"}
resource "google_ads_ad_group_ad" "us_instream" { ad_group = google_ads_ad_group.us_instream.id status = "ENABLED"
ad { final_urls = ["https://www.ghostery.com/?utm_campaign=GH_YouTubeUS_v1_0811-instream"] final_mobile_urls = ["https://m.ghostery.com/?utm_campaign=GH_YouTubeUS_v1_0811-instream"] display_url = "www.ghostery.com"
video_ad { video = google_ads_youtube_video_asset.ghostery_12s.id } }}video_ad is the creative a UI-built video campaign carries. refresh
renders it along with the two other URL fields — final_mobile_urls,
which overrides the landing page on phones, and display_url, the
shortened address the ad shows rather than navigates to.
Commit it, then plan
-
Commit the file. The tracking URL is now in version control, and the next person to change it has to open a pull request to do it.
-
Run
bidsmith plan. The ad reports as an adoption — bidsmith found the live ad and will label it, changing nothing else:google_ads_ad_group_ad.us_instream ~ adopt (label only) -
Apply. From here on the file and the ad are joined, and a plan that says
unchangedis speaking about that URL.
Mark it adopt-only
The ad exists; bidsmith should find it, not make a second one. Say so:
resource "google_ads_ad_group_ad" "us_instream" { ad_group = google_ads_ad_group.us_instream.id
lifecycle { create = false }
ad { /* … */ }}Now a block that matches nothing live stops the plan with an explanation, rather than quietly turning into a create.
What you get
- The UTM slug every video test is measured on is reviewable, and a change to it shows up as a diff with a name attached.
unchangedon that ad now means something. An ad body is compared whole, so if someone edits the URL in the Google Ads UI the file stops matching the live ad and the nextplansays so — where before the field was invisible to bidsmith and every plan reported agreement.bidsmith driftstops listing these fields as gaps, because they are now compared rather than merely present.
See also
- Adopt a campaign you built in the Google Ads UI — the same move for the campaign the ad sits in.
google_ads_ad_group_ad— every field anad {}block takes.- Build tracking URLs from a shared prefix — keeping UTM parameters consistent once they’re in the repo.