Reporting exposure
Report a playback event by firing the URL the server stamped on the ad, appending the fire-time facts. There’s no need to build the URL from scratch; the player fires what the server handed it. The /v1alpha2/track path is illustrative; the real host, path, and query params live inside each <Impression> and <Tracking> element of the VAST.
Firing
Section titled “Firing”Fire each <Impression> and <Tracking> the ad’s VAST contains, at the lifecycle moment its event name denotes. Don’t hardcode a fixed set; the server controls which events are present. If it stamps more later, the player’s loop fires them with no code change.
| Lifecycle moment | Event | Stamped today |
|---|---|---|
| Creative first renders | ae=impression, ce=creativeView, ce=start |
impression, creativeView, start |
| 25% / 50% / 75% of video playback | ce=firstQuartile, ce=midpoint, ce=thirdQuartile |
video only |
| Play completes (end / Duration) | ce=complete |
complete |
The VAST stamps impression, creativeView, start, and complete on every creative; video also carries the three quartiles. Image and HTML5 have no timeline, so they omit the quartiles and fire impression/start on first render and complete when their <Duration> elapses (see Creative formats).
The player does not need to worry about how these become billable impressions; that reconciliation happens server-side. Fire what was stamped, at its moment.
Every play fires afresh, including repeated offline plays. The stamped URLs are reusable, not single-use. Each time a stored ad plays again (offline rotation, no new /ads request), fire its impression (and start, complete) again with a fresh ets. One /ads response can yield many impressions. Each play is a distinct impression, keyed by ets (occurrence time). The server does not derive plays from the token alone, so a player that fires once per token under-counts every replay.
Request parameters
Section titled “Request parameters”| Param | Set by | Present | Notes |
|---|---|---|---|
asid |
server (stamped) | always | The ad serving id (also emitted as <AdServingId>). Fire verbatim. |
ae / ce |
server (stamped) | always | Which event fired. |
sts |
server (stamped) | always | Server clock at decision time. Opaque; fire verbatim. Anchors drift correction. |
ets |
the player (appends) | every fire | RFC3339 occurrence time. |
dvactid is not sent on fires. The player provides it on /ads, where it is captured and attributed to that ad’s events automatically.
Event markers. The server stamps exactly one per URL:
| Marker | Values |
|---|---|
ae |
impression |
ce |
creativeView, start, firstQuartile, midpoint, thirdQuartile, complete |
Response and retries
Section titled “Response and retries”Fire each URL as an HTTP GET. A well-formed fire returns 200 OK with an empty body, meaning “accepted for processing.” The server resolves and records it asynchronously, so a 200 is not a guarantee the event was stored (an expired or unknown token is accepted, then dropped server-side). Don’t gate playback on the response.
A 400 means the request was malformed (missing asid or ets, or an unrecognized event marker): the URL was relayed wrong, so log it and drop. Treat 5xx as transient and retry with backoff.
Offline buffering
Section titled “Offline buffering”Buffer the whole fire (the stamped URL plus the ets the player would have appended) and replay it as a GET on reconnect; nothing about it changes between buffering and replay. Replays and retries are safe: the server counts a given fire once, so a retried 5xx or a re-drained buffer never double-counts.
Play a stored ad; append &ets=2026-06-05T09:15:18Z to each stamped URL.If offline, buffer the whole fire and replay it as a GET on reconnect;each fire keeps its own ets.For the operational concerns around draining a long offline buffer (clock drift, late events, reconnect stampede, and buffer bounds), see Operating offline.