Video ads are a new format designed to enhance the advertiser’s brand and product experience.
How It Works
The campaign creation process is similar to that of banner ads:
Define placements/context (automatic, category, search)
Set campaign details: name, budget, and duration
Videos uploaded by vendors require approval from the marketplace admin.
Video Requirements
- Duration: 6 to 20 seconds (shorter than 20s recommended)
- Formats: MP4 or MOV
- Max size: 200MB
Auction Flow
During an auction request, marketplaces must send the slot ID and may include contextual information (e.g., category, keywords). The auction response will return the video URL for rendering.
Sample Auction Response
{
"resultType": "banners",
"winners": [
{
"rank": 1,
"asset": [
{
"url": "https://customer-axfyyvfgsfxowp1c.cloudflarestream.com/6541f123389a4796889166a2b9491f09/manifest/video.m3u8"
}
],
"type": "vendor",
"id": "972776",
"resolvedBidId": "ChAGjBuGm-lyS6oE7YQebGh-EhABmTSoITB38Z2Nmqd_rVLpGhABmTLlo1V1wJNc17VoVGUKIgoKBjk3Mjc3NhADMJTpbDoBAUAFSAJQx7rhpZMz",
"vendorId": "972776",
"campaignId": "019934a8-2130-77f1-9d8d-9aa77fad52e9"
}
],
"error": false
}
The response includes an HLS manifest URL (.m3u8) that can be rendered using any HLS-compatible video player.
Video Integration Options
Use Your Own Video Player
Topsort’s video ads are compatible with all players that support HLS and DASH formats. Below are implementation examples for each platform.
Web Implementation
<video id="video-ad" muted autoplay loop playsinline style="width: 100%; max-width: 640px;">
<source src="YOUR_VIDEO_URL_HERE" type="application/x-mpegURL">
</video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
// Initialize HLS.js for better browser support
const video = document.getElementById('video-ad');
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource('YOUR_VIDEO_URL_HERE');
hls.attachMedia(video);
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
// Native HLS support (Safari)
video.src = 'YOUR_VIDEO_URL_HERE';
}
// Track impressions (50% visible for 2+ seconds)
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.intersectionRatio >= 0.5) {
setTimeout(() => {
if (entry.intersectionRatio >= 0.5) {
// Report impression
window.topsortEvents.reportEvent({
type: 'impression',
resolvedBidId: 'YOUR_RESOLVED_BID_ID'
});
}
}, 2000);
}
});
}, { threshold: 0.5 });
observer.observe(video);
// Handle clicks
video.addEventListener('click', () => {
window.topsortEvents.reportEvent({
type: 'click',
resolvedBidId: 'YOUR_RESOLVED_BID_ID'
});
// Navigate to vendor/product page
});
</script>
iOS Implementation (Swift)
import AVKit
import UIKit
class VideoAdView: UIView {
private var player: AVPlayer?
private var playerLayer: AVPlayerLayer?
func loadVideo(url: String, resolvedBidId: String) {
guard let videoURL = URL(string: url) else { return }
// Setup player
player = AVPlayer(url: videoURL)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.frame = bounds
playerLayer?.videoGravity = .resizeAspectFill
layer.addSublayer(playerLayer!)
// Configure for autoplay
player?.isMuted = true
player?.play()
// Loop video
NotificationCenter.default.addObserver(
self,
selector: #selector(playerDidFinishPlaying),
name: .AVPlayerItemDidPlayToEndTime,
object: player?.currentItem
)
// Add tap gesture for clicks
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
addGestureRecognizer(tap)
}
@objc private func playerDidFinishPlaying() {
player?.seek(to: .zero)
player?.play()
}
@objc private func handleTap() {
// Report click event via Topsort SDK
}
}
Android Implementation (Kotlin)
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
class VideoAdView(context: Context) : PlayerView(context) {
private var exoPlayer: ExoPlayer? = null
fun loadVideo(url: String, resolvedBidId: String) {
exoPlayer = ExoPlayer.Builder(context).build().apply {
setMediaItem(MediaItem.fromUri(url))
repeatMode = Player.REPEAT_MODE_ONE // Loop
volume = 0f // Muted for autoplay
prepare()
play()
}
player = exoPlayer
useController = false // Hide controls
// Handle clicks
setOnClickListener {
// Report click via Topsort SDK
}
}
}
For detailed player documentation, see:
Reporting and Metrics
Topsort tracks video impressions and clicks using banners.js.
Impression Tracking
- Viewable Impression (IAB/MRC Standard): 50% of pixels in view for 2+ consecutive seconds
- Engagement Impression: Video watched for at least 5 seconds
- Use the
resolvedBidId from the auction response when reporting events
Attribution and Billing Standards
Per IAB/MRC Retail Media Measurement Guidelines, Topsort uses Viewable Impressions (IAB/MRC Standard) for:
- Attribution of outcomes: Only impressions meeting MRC viewability standards (50% pixels visible for 2+ seconds) are eligible for attribution
- Campaign billing: Advertisers are charged based on viewable impressions
- Performance reporting: Primary metrics and ROAS calculations based on viewable impressions
Note: Engagement impressions (5+ seconds watched) are available as an additional engagement metric but are NOT used for attribution or billing purposes.
Click Tracking
- Report click events when users interact with the video
- Include the
resolvedBidId to properly attribute the click
- Navigate to the appropriate vendor/product page after reporting
Important Considerations
- Autoplay Requirements: Videos must be muted to autoplay on most browsers
- Loop Playback: Videos should loop continuously while in view
- Mobile Optimization: Use
playsinline attribute to prevent fullscreen on iOS
- Performance: Consider lazy loading for videos below the fold
Marketplaces can also configure custom impressions and clicks reporting logic as needed.
Frequently Asked Questions
-
What are the recommended upload settings for video uploads?
- MP4 containers, AAC audio codec, H264 video codec, 30 or below frames per second
- moov atom should be at the front of the file (Fast Start)
- H264 progressive scan (no interlacing)
- H264 high profile
- Closed GOP
- Content should be encoded and uploaded in the same frame rate it was recorded
- Mono or Stereo audio (Stream will mix audio tracks with more than 2 channels down to stereo)
-
What browsers does Stream work on?
-
You can embed the Stream player on the following platforms:
Browser | Version |
Chrome | Supported since Chrome version 88+ |
Firefox | Supported since Firefox version 87+ |
Edge | Supported since Edge 89+ |
Safari | Supported since Safari version 14+ |
Opera | Supported since Opera version 75+ |
Mobile Platform | Version |
Chrome on Android | Supported on Chrome 90 |
UC Browser on Android | Supported on version 12.12+ |
Samsung Internet | Supported on 13+ |
Safari on iOS | Supported on iOS 13.4+. Speed selector supported when not in fullscreen. |