Skip to main content

Overview

Web-based CTV platforms run JavaScript applications in embedded browser engines. Permutive’s JavaScript SDK integrates with these platforms through the CTV addon, which provides specialized video tracking capabilities for streaming content. Supported Platforms:

Prerequisites

1

Permutive Workspace

An active Permutive workspace. If you’re not yet a customer, get in touch.
2

Public API Key

Your API key from the Dashboard.
3

CTV Addon

Enable the CTV addon in your Dashboard integrations.

Setup

The JavaScript Tag

Deploy the Permutive JavaScript tag in your CTV web application. The tag initializes the SDK and downloads your workspace-specific bundle.
<!-- start Permutive -->
<script>
  !function(e,o,n,i){if(!e){e=e||{},window.permutive=e,e.q=[];var t=function(){return([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,function(e){return(e^(window.crypto||window.msCrypto).getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16)})};e.config=i||{},e.config.apiKey=o,e.config.workspaceId=n,e.config.environment=e.config.environment||"production",(window.crypto||window.msCrypto)&&(e.config.viewId=t());for(var g=["addon","identify","track","trigger","query","segment","segments","ready","on","once","user","consent"],r=0;r<g.length;r++){var w=g[r];e[w]=function(o){return function(){var n=Array.prototype.slice.call(arguments,0);e.q.push({functionName:o,arguments:n})}}(w)}}}(window.permutive,"<WORKSPACE_API_KEY>","<WORKSPACE_ID>",{});
  window.googletag=window.googletag||{},window.googletag.cmd=window.googletag.cmd||[],window.googletag.cmd.push(function(){if(0===window.googletag.pubads().getTargeting("permutive").length){var e=window.localStorage.getItem("_pdfps");window.googletag.pubads().setTargeting("permutive",e?JSON.parse(e):[]);var o=window.localStorage.getItem("permutive-id");o&&(window.googletag.pubads().setTargeting("puid",o),window.googletag.pubads().setTargeting("ptime",Date.now().toString())),window.permutive.config.viewId&&window.googletag.pubads().setTargeting("prmtvvid",window.permutive.config.viewId),window.permutive.config.workspaceId&&window.googletag.pubads().setTargeting("prmtvwid",window.permutive.config.workspaceId)}});
</script>
<script async src="https://<ORGANIZATION_ID>.edge.permutive.app/<WORKSPACE_ID>-<CTV_PLATFORM>.js"></script>
<!-- end Permutive -->
Replace the following placeholders:
  • <WORKSPACE_API_KEY> - Your workspace API key
  • <WORKSPACE_ID> - Your workspace ID
  • <ORGANIZATION_ID> - Your organization ID
  • <CTV_PLATFORM> - The platform identifier (e.g., hbbtv, lg-webos-24)

Deployment Considerations

CTV Browser Limitations: CTV platforms use embedded browser engines with different JavaScript capabilities than desktop browsers. Always use the platform-specific SDK bundle that matches your target platform version.
  • Use the correct platform bundle - Each platform version has a specific SDK bundle optimized for its JavaScript engine
  • Initialize before video playback - Ensure the SDK is loaded before initializing the CTV addon
  • Test on device - Emulators may not reflect actual device behavior; test on physical CTV hardware
  • Configure network access - Add required domains to your app’s external access policy (especially on Tizen)

Samsung Tizen

Platform Version SDKs

Tizen requires platform-specific SDK bundles. Select the bundle matching your target Tizen platform version:
Platform VersionScript Source
Tizen 8.0<WORKSPACE_ID>-tizen-8-0.js
Tizen 7.0<WORKSPACE_ID>-tizen-7-0.js
Tizen 6.5<WORKSPACE_ID>-tizen-6-5.js
Tizen 6.0<WORKSPACE_ID>-tizen-6-0.js
Tizen 5.5<WORKSPACE_ID>-tizen-5-5.js
Tizen 5.0<WORKSPACE_ID>-tizen-5-0.js
Tizen 4.0<WORKSPACE_ID>-tizen-4-0.js
Tizen 3.0<WORKSPACE_ID>-tizen-3-0.js
Tizen 2.4<WORKSPACE_ID>-tizen-2-4.js
Tizen 2.3<WORKSPACE_ID>-tizen-2-3.js
Tizen Deployment Note: The Tizen script path includes a /tizensdk prefix:
<script async src="https://<ORGANIZATION_ID>.edge.permutive.app/tizensdk/<WORKSPACE_ID>-tizen-8-0.js"></script>

Privileges

Configure the required Tizen privileges in your application:
PrivilegeDescription
http://tizen.org/privilege/internetRequired for network access

External Access Policy

Add Permutive’s CDN and APIs to your external access policy in config.xml:
<access origin="https://<ORGANIZATION_ID>.edge.permutive.app" subdomains="true"/>
<access origin="https://api.permutive.com" subdomains="true"/>
<access origin="https://api.permutive.app" subdomains="true"/>

TIFA (Tizen ID for Advertising)

Samsung provides TIFA as a unique advertising identifier. To use TIFA with Permutive:
  1. Add tifa as an identifier in your Dashboard identifiers settings
  2. Identify users using the TIFA ID:
permutive.identify([{
  id: "<TIFA_ID>",
  tag: "tifa"
}])
See the Tizen TIFA documentation for retrieving the TIFA value.

LG WebOS

Platform Version SDKs

LG WebOS requires platform-specific SDK bundles. Select the bundle matching your target WebOS platform version:
Platform VersionScript Source
webOS TV 24<WORKSPACE_ID>-lg-webos-24.js
webOS TV 23<WORKSPACE_ID>-lg-webos-23.js
webOS TV 22<WORKSPACE_ID>-lg-webos-22.js
webOS TV 6.x<WORKSPACE_ID>-lg-webos-6.js
webOS TV 5.x<WORKSPACE_ID>-lg-webos-5.js
webOS TV 4.x<WORKSPACE_ID>-lg-webos-4.js
webOS TV 3.x<WORKSPACE_ID>-lg-webos-3.js
webOS TV 2.x<WORKSPACE_ID>-lg-webos-2.js
webOS TV 1.x<WORKSPACE_ID>-lg-webos-1.js

Script Example

<script async src="https://<ORGANIZATION_ID>.edge.permutive.app/<WORKSPACE_ID>-lg-webos-24.js"></script>

HbbTV

HbbTV (Hybrid Broadcast Broadband TV) applications use the standard CTV script path:
<script async src="https://<ORGANIZATION_ID>.edge.permutive.app/<WORKSPACE_ID>-hbbtv.js"></script>

CTV Addon

The CTV addon provides video-specific tracking APIs. Initialize it when video content starts:

Initialization

const props = {
  videoProperties: {
    title: "Episode Title",
    genre: ["Drama", "Thriller"],
    audio_language: "en"
  },
  duration: 3600000 // Duration in milliseconds (1 hour)
}

// Tracks Videoview event
permutive.addon("ctv", props)
The addon becomes available at permutive.addons.ctv.

Addon Methods

MethodDescriptionEvents Tracked
.play(position?)Call when content plays or position changes. Starts engagement tracking. Position in milliseconds.-
.pause(position?)Call when content pauses. Stops engagement tracking. Position in milliseconds.-
.stop(position?)Call when user stops/exits content. Sends completion event. Position in milliseconds.VideoCompletion
.setDuration(duration)Update content duration in milliseconds. Set before stopping for accurate completion.-
.track(name, properties, options)Track custom events (e.g., ad events).Specified event

Video Properties

The following properties are available for video events. All are optional but tracking more enables richer cohort building:
PropertyTypeDescription
titlestringVideo title
genrestring[]List of genres
content_typestring[]Content types
age_ratingstringAge rating (e.g., “PG-13”)
runtimenumberRuntime in seconds
countrystringOrigin country
original_languagestringOriginal language code
audio_languagestringAudio language being watched
subtitles.enabledbooleanWhether subtitles are enabled
subtitles.languagestringSubtitle language
season_numbernumberSeason number
episode_numbernumberEpisode number
consecutive_episodesnumberConsecutive episodes watched
iab_categoriesstring[]IAB content taxonomy categories
Properties are sanitized to match expected types. Invalid types are removed rather than causing errors.

Complete Example

// Initialize CTV addon with video metadata
permutive.addon("ctv", {
  duration: 3600000, // 1 hour in milliseconds
  videoProperties: {
    title: "Breaking Bad",
    genre: ["Drama", "Crime"],
    season_number: 1,
    episode_number: 1,
    audio_language: "en",
    runtime: 3600
  }
})

// Get video element reference
const videoElement = document.querySelector("video")

// Track play events
videoElement.addEventListener("play", function() {
  permutive.addons.ctv.play(videoElement.currentTime * 1000)
})

// Track pause events
videoElement.addEventListener("pause", function() {
  permutive.addons.ctv.pause(videoElement.currentTime * 1000)
})

// Track ad breaks
const onAdStart = () => {
  videoElement.pause()
  permutive.addons.ctv.track("VideoAdView", {
    ad_id: "ad_12345",
    ad_position: "midroll"
  })
}

const onAdComplete = () => {
  permutive.addons.ctv.track("VideoAdCompletion", {
    ad_id: "ad_12345"
  })
}

// Track video completion
const onVideoEnd = () => {
  permutive.addons.ctv.stop(videoElement.currentTime * 1000)
}

Event Tracking

Automatic Events

The CTV addon automatically tracks:
EventDescription
VideoviewTracked when addon is initialized. Indicates user intent to watch content.
VideoCompletionTracked when .stop() is called. Includes completion percentage and engaged_time.

Manual Events

Track additional video events using .track():
EventDescription
VideoAdViewVideo ad started playing
VideoAdCompletionVideo ad finished
VideoAdClickedUser clicked on video ad
// Track ad view
permutive.addons.ctv.track("VideoAdView", {
  ad_id: "creative_123",
  ad_duration: 30,
  ad_position: "preroll"
})

// Track ad completion
permutive.addons.ctv.track("VideoAdCompletion", {
  ad_id: "creative_123"
})

JavaScript SDK Reference

For advanced use cases, the full JavaScript SDK is available. Key APIs include:
  • permutive.identify([...]) - Set user identities
  • permutive.track(eventName, properties) - Track custom events
  • permutive.segments() - Get current cohort memberships
  • permutive.ready(callback) - Execute code when SDK is ready

Troubleshooting

Problem: Permutive SDK fails to load on CTV device.Solutions:
  • Verify external access policy includes Permutive domains
  • Check network connectivity on the device
  • Ensure correct platform-specific script URL
  • Verify API key and workspace ID are correct
Problem: Events don’t appear in the dashboard.Solutions:
  • Verify CTV addon is enabled in dashboard settings
  • Check browser console for JavaScript errors
  • Ensure events match your workspace schema
  • Wait 5-10 minutes for events to process
Problem: Engagement metrics don’t match expected values.Solutions:
  • Ensure .play() is called when video plays
  • Ensure .pause() is called when video pauses or buffers
  • Call .stop() when video ends or user exits
  • Set correct duration before calling .stop()
Problem: Google Ad Manager targeting values not applied.Solutions:
  • Ensure GPT library loads before Permutive
  • Verify _pdfps exists in localStorage
  • Check that ad requests fire after Permutive initializes