Skip to content
Knowledge Base

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:

  1. Upload a video

  2. Select a slot

  3. Define placements/context (automatic, category, search)

  4. 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 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

  1. 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)
  2. 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.