Creating Video Ads
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:
-
Upload a video
-
Select a slot
-
Define placements/context (automatic, category, search)
-
Set campaign details: name, budget, and duration
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 supportconst 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 clicksvideo.addEventListener('click', () => { window.topsortEvents.reportEvent({ type: 'click', resolvedBidId: 'YOUR_RESOLVED_BID_ID' }); // Navigate to vendor/product page});</script>
iOS Implementation (Swift)
import AVKitimport 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.ExoPlayerimport com.google.android.exoplayer2.MediaItemimport 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.
-