Skip to main content

Overview

Recording which ads a user actually saw lets you build audiences from ad exposure rather than content consumption alone. Typical use cases:
  • Retargeting — build a cohort of everyone who saw a particular campaign, and target them with a follow-up.
  • Suppression — stop serving a campaign to users who have already seen it enough times.
  • Sequential messaging — serve creative B only to users who have already seen creative A.
  • Measurement — attribute on-site actions back to prior ad exposure.
All of these depend on capturing an identifier that reliably tells you which ad was shown. That turns out to be the hard part, and it is what most of this guide is about.
Before you start
Scope. This guide covers client-side video, where the Google IMA SDK requests and renders the ad in the user’s browser or app.It does not cover display advertising, which uses different mechanisms, or server-side ad insertion (SSAI/DAI), where the ad is stitched into the video stream before it reaches the player and different metadata is available.Examples throughout use Google Ad Manager, since it is the most common setup, but the underlying behaviour applies to any ad server serving VAST through the IMA SDK.

How Video Ad Tracking Works

When a video ad plays, four things happen in sequence:
1

The player requests an ad

Your player asks the ad server for an ad to fill the break.
2

The ad server responds with VAST

VAST (Video Ad Serving Template) is an XML document describing the ad. It comes in two forms. An inline response contains the ad itself, including the video file. A wrapper response contains no video file, only a pointer to another ad server that will supply one.
3

The SDK follows the chain

If the response is a wrapper, the IMA SDK requests the next URL, and repeats until it reaches an inline response. A single ad can involve several hops. Each hop is a separate ad server with its own identifiers for the same ad.
4

You read the metadata and record an event

The SDK exposes the assembled ad metadata through the google.ima.Ad object. You read the identifiers you need and send them to Permutive as a custom event.
The wrapper chain in step three is where most tracking problems originate. Every hop has its own creative ID, and they are unrelated numbers. The identifier you get back depends on which hop the SDK reads from.

The Identifiers Available to You

The google.ima.Ad object exposes these methods at impression time:
getCreativeId() always reads the innermost ad, not your ad server.If your ad server hosts the video file, the innermost ad is your ad server’s, and getCreativeId() returns the ID you see in your own UI.If your ad server redirects to someone else’s, the innermost ad belongs to that other system, and getCreativeId() returns their creative ID. It will look like a perfectly valid ID. It will simply not correspond to anything in your ad server.
The wrapper arrays are ordered innermost first, outermost last. Since your own ad server initiates the chain, it is the outermost wrapper, so its entry is the last element.
Always capture getAdSystem() alongside any creative ID. It tells you whose numbering scheme the ID belongs to, which is the difference between an ID you can use and one you cannot. Google Ad Manager reports as GDFP; Display & Video 360 reports as DBM.

Which Identifier Should You Use

Find the row that matches how the creative is hosted. In Google Ad Manager you can check this under Delivery → Creatives, in the Type column. The distinction is simply whether the ad server holds the video file itself or holds a pointer to it.
Direct-sold campaigns are usually trafficked as Video, because the publisher receives the asset and uploads it. Programmatic Guaranteed and other deal-based buys are usually Redirect or Programmatic, because the buyer serves the creative from their own ad server.This is why creative-level video retargeting often works perfectly for direct-sold inventory and returns nothing for programmatic inventory on the same site.

Reading the ID From the Wrapper Chain

When the chain reaches the player, your ad server’s creative ID is in getWrapperCreativeIds(). Rather than assuming a fixed position, find your ad server by name in getWrapperAdSystems() and read the same index.
This handles all three cases in the table above, and returns null precisely when no usable ID exists, which is the signal to fall back to deal ID.
Google documents the wrapper arrays as containing the full chain with the initiating ad server as the final element. Permutive has not independently verified this behaviour across ad servers, so treat the wrapper path as Google’s stated behaviour and confirm it against your own inventory before relying on it in production. The verification steps below show how.

When the Wrapper Chain Is Not Available

Some ad servers can resolve the VAST chain on their own servers before responding to the player, returning a single flattened inline ad rather than a chain. In Google Ad Manager this is called Server-Side Unwrapping (SSU). It reduces the number of round trips the player makes, which improves latency and reduces drop-off. The trade-off is that the wrapper chain no longer exists by the time the SDK sees the response.
When server-side unwrapping is enabled, all three wrapper arrays return empty arrays.getWrapperAdIds(), getWrapperCreativeIds() and getWrapperAdSystems() return []. They do not throw and they do not warn. The only ad metadata that reaches the player is the innermost creative, which for third-party creatives belongs to the buyer.In this configuration your ad server’s creative ID cannot be recovered client-side by any means. No SDK change will surface it.
This is easy to misread, because the symptoms look like a coding error rather than a configuration outcome:
  • The methods exist and return cleanly.
  • The creative IDs look entirely normal in your ad server’s UI.
  • Events arrive in Permutive with populated, valid-looking creative IDs.
  • Cohorts built against those IDs simply never match anyone.
If getWrapperAdSystems() returns an empty array while getAdSystem() returns an ad server that is not yours, server-side unwrapping is the most likely explanation. Confirm with your ad server account team whether it is enabled for your network.

Falling Back to Deal ID

Where the creative ID cannot be recovered, getDealId() is populated for programmatic deals and offers a workable alternative. Deal ID identifies the line item, not the creative. Because a line item can carry several creatives, every creative on that line shares one deal ID, and they cannot be told apart from the deal ID alone.
If you need per-creative granularity with deal ID, each creative must sit on its own line item. This is an operational change in your ad server rather than a code change, and it is worth confirming your trafficking team is willing to work that way before committing to the approach.

Implementation

Capture the identifiers on the ad’s STARTED event and send them as a custom event.
Recording all the identifiers, including the ones you do not immediately need, makes future diagnosis much easier and costs very little.
title, duration and creative_id are part of the canonical ad event schema. The remaining properties are additions you would need to define in your own event schema first.
VideoAdView and its ad.* properties follow Permutive’s canonical video ad event schema. Use these names where you can, so cohorts and reporting behave consistently across platforms.If you add properties beyond the canonical set, define them in your workspace’s event schema first, and avoid reusing an existing property for a new identifier — cohorts built before and after the change would silently target different things.

Verifying Your Implementation

1

Log the full ad metadata on a live impression

Play an ad from the inventory you care about, and log every identifier rather than inspecting them in a debugger. Collapsed arrays in dev tools can be hard to distinguish from empty ones.
2

Check the ad system

If getAdSystem() returns your ad server, the inline creative is yours and getCreativeId() is directly usable. If it returns something else, the creative is third-party and you need the wrapper chain or deal ID.
3

Check whether the wrapper chain survived

A populated getWrapperAdSystems() means the chain reached the player and the wrapper lookup will work. An empty array means it did not, and deal ID is your route.
4

Cross-check the ID against your ad server

Take the creative ID your event recorded and search for it in your ad server. If it does not exist there, you are capturing a third-party identifier. This single check settles the question faster than any other.
5

Confirm the event lands in Permutive

In the Events section of your dashboard, look for your event name and confirm the properties are populated as expected.
6

Test both direct-sold and programmatic inventory

These behave differently. An implementation verified only against direct-sold campaigns can still return unusable identifiers on programmatic inventory.

Common Failure Modes

FAQ

They are identifiers from two different systems that happen to describe the same video. Your ad server’s creative ID is a record in your account. The buyer’s creative ID is a record in theirs. When the creative is served through a redirect, getCreativeId() reads the buyer’s.Capturing getAdSystem() alongside the ID tells you immediately which one you are holding.
In principle yes, and it would restore the wrapper chain. In practice it is a meaningful trade-off: server-side unwrapping exists to reduce round trips and improve latency and fill.Weigh it against the alternative of splitting creatives onto separate line items and using deal ID, which achieves the same granularity without changing how ads are delivered. Discuss the options with your ad server account team.
No. Display uses a different delivery mechanism and different tracking. This guide is specific to video ads rendered by the IMA SDK.
SSAI stitches ads into the video stream before it reaches the player, so the metadata available differs from client-side playback. The identifiers described here may not be present. Contact Support to discuss an SSAI setup.
It is worth doing. They are small, and they make it possible to answer questions about historical impressions that you would otherwise need a new live test to investigate. They also make it obvious after the fact whether server-side unwrapping was in play.

Next Steps

Creating & Updating Event Schema

Define the custom event schema your video ad events will validate against.

Tracking Off-Site Events with Pixels

Track conversions and impressions that happen away from your own pages.

IMA SDK Ad reference

Google’s full reference for the ad metadata methods used in this guide.

Contact Support

Troubleshoot an implementation or confirm the right approach for your setup.