Event Tracking
Adlocaite uses a VAST 4.0 compliant event tracking system to record ad playout progress. Instead of a single confirmation call, individual events (start, quartiles, complete) are tracked as they occur -- enabling granular reporting and accurate billing.
Overview
When a screen plays an advertisement, your player fires tracking pixels at defined points during playback. These events are ingested by the Adlocaite Tracking Service and stored per offer for reporting and billing.
OpenRTB loss notices (lurl) for SSP integrations are not handled here; they go to the OpenRTB endpoint, see Loss notifications.
Integration Flow: Request Offer → Accept Offer → Display Ad → Fire Tracking Events
Two integration paths are available:
- VAST players (recommended) -- Request offers with
vast=true. The returned VAST XML already contains all tracking pixel URLs, including the correct tracking host, publisher ID and screen ID for the environment you called. Your player fires them automatically during playback and never has to build a tracking URL itself. - Custom / SDK integration -- Fire tracking events yourself via HTTP, either as individual GET pixel requests or as a batch POST. Use this path only if your player cannot consume VAST. You are then responsible for the host and for the
pubandscrparameters described below.
Environments
The Tracking Service runs as a separate host per environment. Events must go to the tracking host that belongs to the API host you requested the offer from.
| Environment | API host | Tracking host |
|---|---|---|
| Staging | https://staging.api.adlocaite.com | https://staging.tracking.adlocaite.io |
| Production | https://api.adlocaite.com | https://tracking.adlocaite.io |
An offer requested from the staging API only exists in staging. If your player sends its tracking events to the production tracking host, they arrive in an environment where neither the offer nor the screen is known. The events are discarded, never appear in your staging reports, and the playout cannot be matched to a deal. VAST URLs returned by the API already point to the right host; if you build URLs yourself, make the tracking host part of the same configuration as the API host.
VAST tracking events
The tracking system supports the following standard VAST events. Each event corresponds to a specific moment during ad playback:
- Name
impression- Type
- event
- Description
The ad was loaded and is about to be displayed. Fired once when the ad unit is first rendered.
- Name
start- Type
- event
- Description
Video/image playback has started (0% progress).
- Name
firstQuartile- Type
- event
- Description
Playback reached 25% of total duration.
- Name
midpoint- Type
- event
- Description
Playback reached 50% of total duration.
- Name
thirdQuartile- Type
- event
- Description
Playback reached 75% of total duration.
- Name
complete- Type
- event
- Description
Playback finished (100% of duration). This is the primary billing-relevant event.
The tracking service also accepts an error event with a code parameter for VAST 4.0 error reporting, but this is not relevant for billing.
Required events for billing
For a playout to be counted as billable, a minimum set of events must be received. This follows the VAST 3.0 minimum standard:
| Event | Required | Description |
|---|---|---|
| impression | Required | Must be fired for the playout to be registered at all. |
| start | Required | Confirms that playback actually began. |
| firstQuartile | Recommended | Improves reporting granularity. |
| midpoint | Recommended | Improves reporting granularity. |
| thirdQuartile | Recommended | Improves reporting granularity. |
| complete | Required | Must be fired for the playout to count as billable. |
At minimum, impression, start, and complete must be received for a playout to be billed. Missing any of these three events means the playout will not be counted. We strongly recommend sending all six standard events for full reporting coverage.
Tracking via VAST pixels
When you request offers with vast=true, the returned VAST XML contains tracking pixel URLs for all standard events. A VAST-compliant player fires these URLs automatically as HTTP GET requests during playback. This is the recommended path: the URLs already carry the right host, publisher ID and screen ID.
If your player cannot consume VAST, you can build the same URLs yourself. Use the tracking host of the environment you requested the offer from and include all parameters below.
URL format
https://tracking.adlocaite.io/track?offer_id={offer_id}&event={event}&ts={timestamp}&pub={publisher_id}&scr={screen_id}
Query parameters
- Name
offer_id- Type
- string
- Description
Required. The UUID of the ad offer being tracked.
- Name
event- Type
- string
- Description
Required. Event type:
impression,start,firstQuartile,midpoint,thirdQuartile,complete, orerror.
- Name
ts- Type
- integer
- Description
Required. Client timestamp in Unix milliseconds. In VAST URLs it is set at generation time; when you build URLs yourself, set it to the moment the event occurred.
- Name
pub- Type
- string
- Description
Required. Publisher ID (UUID) of the screen's publisher, as provided during onboarding. Events without
pubare discarded.
- Name
scr- Type
- string
- Description
Required. Screen ID (UUID) of the screen that played the ad. Must be a screen registered in the same environment and belonging to
pub; events for unknown screens are discarded.
Discarded events return the same 1x1 GIF as accepted ones. They are not stored, never show up in reporting, and the playout does not count as billable. If you fire pixels yourself, verify during integration that your playouts appear in reporting with all expected events.
The endpoint returns a 1x1 transparent GIF with Cache-Control: no-store headers. No authentication is required -- VAST players cannot set custom headers, so these URLs are designed to work as fire-and-forget pixels.
VAST XML tracking section
<TrackingEvents>
<Tracking event="start">
<![CDATA[https://tracking.adlocaite.io/track
?offer_id=550e8400-e29b-41d4-a716-446655440000
&event=start
&ts=1710340000000
&pub=pub-123-uuid
&scr=screen-456-uuid]]>
</Tracking>
<Tracking event="firstQuartile">
<![CDATA[https://tracking.adlocaite.io/track
?offer_id=550e8400-e29b-41d4-a716-446655440000
&event=firstQuartile
&ts=1710340000000
&pub=pub-123-uuid
&scr=screen-456-uuid]]>
</Tracking>
<Tracking event="midpoint">
<![CDATA[https://tracking.adlocaite.io/track
?offer_id=550e8400-e29b-41d4-a716-446655440000
&event=midpoint
&ts=1710340000000
&pub=pub-123-uuid
&scr=screen-456-uuid]]>
</Tracking>
<Tracking event="thirdQuartile">
<![CDATA[https://tracking.adlocaite.io/track
?offer_id=550e8400-e29b-41d4-a716-446655440000
&event=thirdQuartile
&ts=1710340000000
&pub=pub-123-uuid
&scr=screen-456-uuid]]>
</Tracking>
<Tracking event="complete">
<![CDATA[https://tracking.adlocaite.io/track
?offer_id=550e8400-e29b-41d4-a716-446655440000
&event=complete
&ts=1710340000000
&pub=pub-123-uuid
&scr=screen-456-uuid]]>
</Tracking>
</TrackingEvents>
Manual pixel request
curl "https://tracking.adlocaite.io/track?offer_id=550e8400-e29b-41d4-a716-446655440000&event=complete&ts=1710340000000&pub=pub-123-uuid&scr=screen-456-uuid"
# Returns: 1x1 transparent GIF
Tracking via SDK batch
For custom player integrations or high-volume setups, you can submit multiple events in a single authenticated POST request.
Authentication
The POST endpoint requires HMAC-SHA256 authentication. Generate a token by signing the current Unix timestamp (milliseconds) with your tracking secret:
Authorization: Bearer {timestamp}::{hmac_sha256_hex}
Tokens are valid for 5 minutes after generation.
Request body
- Name
offer_id- Type
- string
- Description
The UUID of the ad offer. Must be a valid UUID format.
- Name
events- Type
- array
- Description
Non-empty array of event objects. Each event requires a
type(string) andtimestamp(ISO-8601 or Unix milliseconds).
- Name
publisher_id- Type
- string
- Description
Required. Publisher UUID. Batches without it are discarded.
- Name
screen_id- Type
- string
- Description
Required. Screen UUID. Must be registered in the same environment and belong to
publisher_id; batches for unknown screens are discarded.
- Name
player_version- Type
- string
- Description
Optional. Your player software version identifier.
- Name
screen_resolution- Type
- string
- Description
Optional. Screen resolution during playback (e.g., "1920x1080").
Request
curl -X POST "https://tracking.adlocaite.io/track" \
-H "Authorization: Bearer 1710340000000::a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"offer_id": "550e8400-e29b-41d4-a716-446655440000",
"publisher_id": "pub-123-uuid",
"screen_id": "screen-456-uuid",
"events": [
{ "type": "impression", "timestamp": "2026-03-13T10:00:00Z" },
{ "type": "start", "timestamp": "2026-03-13T10:00:01Z" },
{ "type": "firstQuartile", "timestamp": "2026-03-13T10:00:04Z" },
{ "type": "midpoint", "timestamp": "2026-03-13T10:00:06Z" },
{ "type": "thirdQuartile", "timestamp": "2026-03-13T10:00:09Z" },
{ "type": "complete", "timestamp": "2026-03-13T10:00:11Z" }
],
"player_version": "2.1.0",
"screen_resolution": "1920x1080"
}'
Success response (200)
{
"success": true,
"event_id": "evt-a1b2c3d4-uuid",
"events_count": 6
}
Error: invalid offer_id (400)
{
"error": "Invalid offer_id: must be a valid UUID"
}
Error: unauthorized (401)
{
"error": "Missing or invalid authorization token"
}
Best practices
Event timing
Fire each tracking event as close to the actual playback moment as possible. The tracking service stores both the client-provided timestamp (ts) and the server receive time (received_at), so large discrepancies between these two values may flag the playout for review.
Retry logic
- GET pixel requests -- Fire-and-forget. If a pixel fails, the VAST standard does not require retries. However, for accurate billing, we recommend retrying failed
impression,start, andcompletepixels up to 3 times with exponential backoff. - POST batch requests -- Implement retry with backoff on 5xx responses. 4xx errors indicate a client-side issue (invalid token, malformed body) and should not be retried without fixing the request.
Offline / buffered playback
For screens with intermittent connectivity, buffer events locally and submit them via the POST batch endpoint when connectivity is restored. Include accurate client timestamps so the events can be attributed to the correct playback session.
Performance
- Tracking pixel requests are non-blocking -- they return a 1x1 GIF immediately and process asynchronously
- For high-volume setups with many screens, prefer the POST batch endpoint to reduce HTTP overhead
- Set reasonable timeouts (3-5 seconds) for pixel requests to avoid blocking your content pipeline
Deprecated: playout/confirm
The legacy POST /playout/confirm/{dealId} endpoint is deprecated. It still works but only fires a single complete event internally and does not provide the granular tracking data needed for full billing and reporting.
Migration guide
The old endpoint accepted a deal_id and optional metadata. The new system tracks by offer_id and uses standard VAST events:
| Old (playout/confirm) | New (event tracking) |
|---|---|
| Single POST per deal | Multiple events per offer |
deal_id based | offer_id based |
completion_rate: 100 | complete event fired |
played_at timestamp | start event timestamp |
| No quartile data | Full quartile tracking |
| Requires API key auth | GET pixels: no auth / POST batch: HMAC |
How to migrate
- VAST players: Request offers with
vast=true. The VAST XML includes all tracking pixel URLs. Remove any manualplayout/confirmcalls. - Custom players: Replace the single
playout/confirmPOST with individual GET pixel requests (or a POST batch) forimpression,start, andcompleteat minimum. Always includepubandscr, and use the tracking host of the environment your API key belongs to. - Verify: Check that your playouts appear in reporting with all expected events.
Old (deprecated)
# Don't use this anymore
curl -X POST "https://api.adlocaite.com/functions/v1/api/playout/confirm/DEAL_ID" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"played_at": "2026-03-13T14:30:00Z",
"duration_seconds": 15,
"completion_rate": 100
}'
New (VAST pixel -- recommended)
# Request offer with VAST
curl "https://api.adlocaite.com/functions/v1/api/offers/request/SCREEN_ID?vast=true" \
-H "Authorization: Bearer YOUR_API_KEY"
# Player automatically fires pixels from VAST XML:
# impression, start, firstQuartile, midpoint,
# thirdQuartile, complete
New (manual pixels)
# Fire events individually. pub and scr are required;
# use the tracking host of your environment (see Environments).
curl "https://tracking.adlocaite.io/track?offer_id=OFFER_ID&event=impression&ts=$(date +%s000)&pub=PUBLISHER_ID&scr=SCREEN_ID"
curl "https://tracking.adlocaite.io/track?offer_id=OFFER_ID&event=start&ts=$(date +%s000)&pub=PUBLISHER_ID&scr=SCREEN_ID"
# ... playback happens ...
curl "https://tracking.adlocaite.io/track?offer_id=OFFER_ID&event=complete&ts=$(date +%s000)&pub=PUBLISHER_ID&scr=SCREEN_ID"
Deprecation response
{
"success": true,
"deprecated": true,
"message": "This endpoint is deprecated and will be removed after 2026-06-01. Playout tracking now happens automatically via VAST tracking pixels.",
"deal_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}