Migrate Web SDK

Use this guide to migrate your Player Web SDK from AMP1 to AMP2.

The guide lists specific player features and functions, their AMP1 implementation, and how you should implement them in AMP2 for successful migration.
Review Comprehensive coverage analysis for a summary of AMP1 vs. AMP2 coverage for API methods, events, and features. For a detailed feature and function mapping with examples, see the following tables:

Additional reference:

1. Get started with basic integration changes

Player script tag

AMP can be embedded using a CDN-hosted model or self-hosted model. Compare implementation of the player script tags for AMP1 and AMP2.

  • CDN-hosted script

AMP1 implementation:

<html>
  <head>
    <script src="https://amp.akamaized.net/hosted/1.1/player.esi?apikey=MY_API_KEY&version=9.1.36"></script>
  </head>
  <body>
  </body>
</html>

AMP2 implementation (development):

<html>
  <head>
<script src="https://cdn.bitmovin.com/player/web/8/bitmovinplayer.js" type="text/javascript"></script>
  </head>
  <body>
  </body>
</html>
  • Self-hosted script

AMP1 implementation:

<html>
  <head>
    <script src="akamai/amp/core/amp.js"></script>
  </head>
  <body>
  </body>
</html>

AMP2 implementation (production):

For the production version, it is recommended to use self-hosting. The web integration option is available using the NPM package .

NPM package

AMP1 implementation:

npm install adaptive-media-player
// Import player module 
import  AMP  from  'adaptive-media-player'

AMP2 implementation:

npm install bitmovin-player
// Import player modules in the correct order 
import { Player, PlayerEvent } from 'bitmovin-player/modules/bitmovinplayer-core';
import EngineBitmovinModule from 'bitmovin-player/modules/bitmovinplayer-engine-bitmovin';
import MseRendererModule from 'bitmovin-player/modules/bitmovinplayer-mserenderer';

Initialize the player

AMP1 implementation:

// Include player script 
// Define empty DIV for player
// Define config object
// Instantiate player
akamai.amp.AMP.create("amp", config)
  .then(function (player) {
    console.log("AMP Player ready");
  });

AMP2 implementation:

// Include player script
// Define empty DIV for player
// Define config object
// Instantiate player (new())
// Load Media into player
var player = new bitmovin.player.Player(document.getElementById("container-id"), config);

2. Migrate player configurations

Stream URL configuration

AMP1 implementation:

media: {
  source: [{
    src: "https://akamtrans-a.akamaihd.net/delivery/20/35/2035ef57-5cac.m3u8",
    type: "application/x-mpegURL"
  }]
}

AMP2 implementation:

const source = {
  title: 'Art of Motion',
  hls: 'https://akamtrans-a.akamaihd.net/delivery/20/35/2035ef57-5cac.m3u8'
};

player.load(source);

Autoplay configuration

AMP1 implementation:

{
  autoplay: true,
  autoplayPolicy: "muted"
}

AMP2 implementation:

playback: {
  autoplay: true,
  muted: true
}

Low Latency configuration

AMP1 implementation:

  • For HLS:
    {
     hls: {
     	data: {
       		lowLatencyMode: true,
    			liveMaxLatencyDuration: 4,
     	}
    }
    
  • For Dash:
    dash: {
     	settings: {
       		streaming: {
    			lowLatencyEnabled: true,
    			delay: {
    					liveDelay: 4
    			},
    		}
     	}
    }
    

AMP2 implementation:

Supporting both HLS and Dash:

const config = new util.PlayerConfigBuilder("MY-PLAYER-KEY")
  .enableLowLatency({ targetLatency: 4 })
  .build();

User settings configuration

The player stores a user's preferences in the browser's local storage, so AMP remembers and applies them across sessions for user convenience and more personalized playback experience.

AMP1 implementation:

settings: {
		defaults: {
			captions: {
				visible: true,
				fontFamily: "monospacedSerif",
				fontSize: "large",
				fontColor: "white",
				fontOpacity: "100%",
				edgeType: "rightShadow",
				edgeColor: "black",
				edgeOpacity: "50%"
				backgroundColor: "black",
				backgroundOpacity: "50%",
				windowColor: "black",
				windowOpacity: "50%",
				scroll: "popout"
			}
		}
	}

AMP2 implementation:

Check with a Bitmovin representative for options to configure user preferences.

3. Perform playback fine tuning

Fast playback startup

To improve playback startup time, start playback at a lower resolution irrespective of the user’s bandwidth capabilities.

AMP1 implementation:

 const config = {
		autoplay: true,
		autoplayPolicy: "muted",
		hls: {
			quality: {
					startLevel: 0 // use the lowest rendition available
			}
		}
	}

AMP2 implementation:

{
    key: 'USER_PLAYER_LICENSE_KEY',
    playback: {
        autoplay: false,
        muted: false
          },
    adaptation: {
        startupBitrate: "4000kbps",
        maxStartupBitrate: "7mbps", //ignored if startupBitrate defined
        }
}

Playback Bitrate Ceiling

In some cases, you may want to limit the player's maximum ABR quality level. You can configure a ceiling to avoid playback at higher bitrates when they aren't required, reducing unnecessary resource usage.

AMP1 implementation:

    const config = {
		autoplay: true,
		autoplayPolicy: "muted",
		hls: {
			maxBitrate: 500000 // 0.5 Mbps
		}
	}

AMP2 implementation:

{
    key: 'USER_PLAYER_LICENSE_KEY',
    playback: {
        autoplay: false,
        muted: false
          },
    adaptation: {
        bitrates: {
            maxSelectableVideoBitrate: "0.5mbps",
            minSelectedVideoBitrate: 0,
         },
     }
}

4. Migrate advanced features

Use this information and examples to migrate advanced features for your player.

Player transforms

AMP1 transformAMP2 eventMigration notesCode example
adbreakonAdsManagerAvailableCoult integrate accessing IMA’s ad managerSee Ad break transforms
adrequestN/ACould integrate with preprocessHttpRequestSee Ad request transforms
cuechangecueenter, cueupdateDirect mappingplayer.on(‘cueenter’, callback)
errorerrorDirect mappingplayer.on(‘error’, callback)
mediamediaCould integrate with preprocessHttpRequestSee Media transforms

📘

See Event mapping for Web SDK for a complete list of AMP1 vs. AMP2 event mapping.

Media transforms

AMP1: Just-in-time changes to media source object or URLs.

player.addTransform('media', function(media) {
  media.src += '?token=' + getToken();
  return media;
});

AMP2: Use Network API for HTTP request/response manipulation.

player.network.preprocessHttpRequest = function(type, request) {
  if (type === player.network.HttpRequestType.MEDIA) {
    request.url += '?token=' + getToken();
  }
  return Promise.resolve(request);
};

Ad request transforms

AMP1: Just-in-time changes to ad request object or URLs, before an ad client request to the ad server.

player.addTransform(akamai.amp.TransformType.AD_REQUEST, function (ad) {
    ad.request.setAdWillAutoPlay(false)
       ad.request.setAdWillPlayMuted(true)
       ad.request.adTagUrl += "&testing=123456"

   return ad;
});

AMP2: Use Network API for HTTP request/response manipulation.

player.network.preprocessHttpRequest = function(type, request) {
  if (type === player.network.HttpRequestType.MANIFEST_ADS) {
    adrequest.url += '?cust_params=' + getAdParams();
  }
  return Promise.resolve(request);
};

Ad break transforms

AMP1: Just-in-time changes after the ad request is made and break is ready to play.

akamai.amp.AMP.create("akamai-media-player", config, function (event) {
                   amp = event.player
                   // skip prerolls
                   amp.addTransform(akamai.amp.TransformType.AD_BREAK, function (adbreak) {
                       if (adbreak.type === "preroll" || adbreak.type == "postroll") {
                           return; // return a null value to skip the ad break
                       }
                       return adbreak;
                   });
               });

AMP2: Use Network API for HTTP request/response manipulation.

const player = new bitmovin.player.Player(container, {

  advertising: {
    adClient: 'ima',
    ima: {
      onAdsManagerAvailable: ({ adsManager, adDisplayContainer }) => {
        // Example: require manual start of ad breaks
        const settings = new google.ima.AdsRenderingSettings();
        settings.autoPlayAdBreaks = false;
        adsManager.updateAdsRenderingSettings(settings);

        // Listen for a pod *before* it plays:
        adsManager.addEventListener(
          google.ima.AdEvent.Type.AD_BREAK_READY,
          (evt) => {
            // intercept here: decide to start, delay, or cancel
            // e.g., start it yourself:
            adsManager.start(); // or adsManager.discardAdBreak(); to ignore it
          }
        );
      }
    }
  }
});

Data binding

AMP1: Advanced parameterization.

{
  plugins: {
    googleanalytics: {
      trackingId: "#{accountId}",
      dimensions: {
        dimension1: "${media.title}"
      }
    }
  }
}

AMP2: Requires programmatic implementation. See the Property mapping table to fetch the required metadata.

// Bitmovin alternative - access via API
const current = player.getSource();
const videoId = current?.metadata?.videoId
const title = player.getSource().title;
const version = player.version;
// Manually construct analytics parameters

Plugins

AMP2 offers a variety of third-party extensions that work with the AMP ecosystem, including analytics, advertisement, and monetization. See Bitmovin Player Integrations for available third-party web player integrations.

Custom plugins

AMP1: Supports customized plugins that have access to player’s API and events for specific customer needs. These plugins are mostly developed by customers.

akamai.amp.AMP.registerPlugin("myplugin", MyPlugin);

AMP2: Custom plugins are not directly supported as they require integration at application level. Use player API events and methods for custom functionality.

360/180 VR playback

AMP uses A-Frame, a WebVR framework, as its primary player plugin for VR support.

AMP1 implementation:

config = {
       plugins: {
         aframe: {
           resources: [
             { src: "//aframe.io/releases/1.7.1/aframe.min.js", type: "text/javascript" },
             { src: "${paths.plugins}aframe/Aframe.min.js", type: "text/javascript"},
             { src: "${paths.plugins}aframe/Aframe.min.css", type: "text/css" }            
],
           rotation: "0 0 0",
           vrmode: true,
           native: true,
		 halfViewMode: false, //true for 180 degree playback
           components: {
             'vr-controls': {
               autoHide: 5,
               theme: {
                 foreground: "#FFF",
                 background: "#675f60",
                 window: "#675f60",
                 windowOpacity: 1,
                 backgroundOpacity: 0.5,
                 foregroundOpacity: 0.8
               }
             },
             'vr-dome': {
               src: 'https://cdn.aframe.io/360-image-gallery-boilerplate/img/city.jpg',
               crossorigin: 'anonymous'
             }
           }
       }
       },
       autoplay: false,
       playsinline: true,
       media: videos[1]
     };

AMP2 implementation:

Confirm options for 180 degree playback with a Bitmovin representative.

var conf = {
    key: 'YOUR KEY HERE',
    source: {
        title: "Bitmovin Player " + bitmovin.player.version,
        description: "VR/360° Example, contentType: single, startPosition: 0, initialRotation: true, initialRotateRate: 0.07",
        dash: '//bitmovin-a.akamaihd.net/content/vr-player/playhouse-vr/mpds/105560.mpd',
        hls: '//bitmovin-a.akamaihd.net/content/vr-player/playhouse-vr/m3u8s/105560.m3u8',
        progressive: '//bitmovin-a.akamaihd.net/content/vr-player/playhouse-vr/progressive.mp4',
        poster: '//bitmovin-a.akamaihd.net/content/vr-player/playhouse-vr/poster.jpg',
        vr: {
            startPosition: 0,
            contentType: 'single',
            initialRotation: 'true',
            initialRotateRate: 0.07
        }
    }
};

5. Migrate analytics

Review the table below for analytics provider migration details.

Analytics provider migration table

ProviderAMP1 implementationAMP2 implementationMigration steps
Chartbeat{ plugins: { chartbeat: {} } }Not integratedCustom implementation required
CMCD{ plugins: { cmcd: {} } }Integration module availableUse bitmovin-player-web-integration-cmcd
Comscore{ plugins: { comscorestreamsense: {} } }Integration moduleUse bitmovin-player-web-analytics-comscore
Conviva{ plugins: { conviva: {} } }Integration moduleUse bitmovin-player-web-analytics-conviva
Datazoom{ plugins: { datazoom: {} } }Third-party integrationFollow Datazoom documentation
Google Analytics{ plugins: { googleanalytics: {} } }App-level integrationIntegrate above player
MOAT{ plugins: { moat: {} } }Integration moduleUse bitmovin-player-web-analytics-moat
Mux{ plugins: { mux: {} } }Third-party integrationFollow Mux guide
Nielsen DCR/DTVR{ plugins: { nielsen: {} } }On roadmapWill be required by top tier customers
Adobe Analytics{ plugins: { omniture: {} } }Not directly integratedTypically through Adobe Analytics
Adobe Heartbeat{ plugins: { heartbeat: {} } }Integration moduleUse bitmovin-player-web-analytics-adobe
Segment{ plugins: { segment: {} } }Not integratedExplore per-customer basis

6. Migrate ad integration

Before you start, review the recommended ad integration approaches.

Use the IMA/Bitmovin Adapter (/ima) if:

  • You already have a VMAP-based ad delivery setup.
  • You prefer a simpler, lower complexity integration.
  • You only need standard pre-roll, mid-roll, or post-roll ad insertion.
  • You do not require special handling for companion ad.

Use the FreeWheel module (/module) if:

  • You require full FreeWheel SDK functionality.
  • You need direct access to and control over the FreeWheel ad context.
  • You must support advanced companion ad workflows.

Google IMA (VAST/VMAP)

AMP1 implementation:

{ 
  plugins: { 
    ima: {
      adTagUrl: "https://example.com/vast.xml"
    } 
  } 
}

AMP2 implementation:

advertising: {
  adBreaks: [{
    tag: {
      url: "https://example.com/vast.xml",
      type: 'vast'
    }
  }]
}

FreeWheel (VMAP/SDK)

AMP1: Integrates FreeWheel ads by using the FreeWheel Ad Manager as an official player plugin. Customers can adjust the following configuration parameters based on their ad setup.

{ 
  plugins: { 
    freewheel: {
    resources: [
      {src: "http://adm.fwmrm.net/libs/adm/6.28.0/AdManager.js", type: "text/javascript"},
      {src: "${paths.plugins}amp-freewheel/Freewheel.min.js", debug: "${paths.plugins}amp-freewheel/Freewheel.js", type: "text/javascript"}
    ],
    networkId: 96749,
    serverUrl: "//demo.v.fwmrm.net/ad/g/1",
    profileId: "global-js",
    siteSectionId: "DemoSiteGroup.01",
    videoAssetId: "DemoVideoGroup.01",
    prerollSlotId: "Preroll_1",
    midrollSlotId: "Midroll_1",
    postrollSlotId: "Postroll_1",
    creativeParameters: [
      "type",
      "param2",
      "param3"
    ],
    parameters: [
      {
        key: "translator.vast.loadWithCookie",
        value: true
      }
    ]
  }
  } 
}

AMP2: You can integrate FreeWheel ads in one of two ways:

  • Using the Bitmovin’s Ads Module (BAM) and playing FreeWheel ads as VMAP output.

Prerequisites
freewheel.js: FreeWheel VMAP URL generator that contains the initFreewheel() helper.

const freewheelConfig = {
  networkId: YOUR_NETWORK_ID,
  serverUrl: 'https://serverurl.com',
  profileId: 'YOUR_NETWORK_ID:PROFILE_NAME',
  siteSectionId: 'YOUR_SITE_SECTION',
  videoAssetId: 'YOUR_VIDEO_ASSET_ID',

  // Global parameters
  // See: https://hub.freewheel.tv/display/MUG/HTTP+GET+Ad+Request%3A+Global+Parameters
  globalParams: {
    flag: ['+sltp', '+qtcb', '+emcr', '+slcb', '+sync', '+cmpn', '+play', '+scpv'],
  },

  // Key-value targeting
  // See: https://hub.freewheel.tv/display/MUG/HTTP+GET+Ad+Request+-+Key+Values
  keyValues: {
    // custom: 'value'
  },

  // Ad slots
  // See: https://hub.freewheel.tv/display/MUG/HTTP+GET+Ad+Request%3A+Slots
  adSlots: [
    {
      slid: 'Preroll_1',      // Slot ID
      tpcl: 'PREROLL',        // Time position class
      ptgt: 'a',              // Player target (a = audio/video)
      slau: 'preroll',        // Slot audience
    },
    {
      slid: 'Midroll_1',
      tpcl: 'MIDROLL',
      tpos: 120,              // Time position in seconds
      ptgt: 'a',
      slau: 'midroll',
    },
    {
      slid: 'Postroll_1',
      tpcl: 'POSTROLL',
      ptgt: 'a',
      slau: 'postroll',
    },
  ]
}

// Initialize player and creates freewheel HTTP VMAP url 
const player = new bitmovin.player.Player(document.getElementById('player'), conf);
initFreewheel(player, freewheelConfig)

player.load(source)
  • Using an unofficial Bitmovin’s FreeWheel module along with FreeWheel SDK.

Prerequisites
bitmovinplayer-advertising-freewheel.js: FreeWheel module for the Bitmovin player.

const conf = {
  key: 'PLAYER_KEY',
  playback: {
    autoplay: false,
    muted: false,
  },
  advertising: {
    freewheel: {
      // --- Required FreeWheel configuration ---
      sdkUrl: 'http://adm.fwmrm.net/libs/adm/6.28.0/AdManager.js',
      serverUrl: 'http://demo.v.fwmrm.net/ad/g/1',
      networkId: 96749,
      profileId: 'global-js',
      siteSectionId: 'DemoSiteGroup.01',
      videoAssetId: 'DemoVideoGroup.01',

      // Default ad slot IDs
      prerollSlotId: 'Preroll_1',
      midrollSlotId: 'Midroll_1',
      postrollSlotId: 'Postroll_1',

      // --- Optional request/session configuration ---
      subsessionToken: '12345678',
      synchronizeMultipleRequests: true,

      // Optional creative parameters
      creativeParameters: ['type', 'param2', 'param3'],

      // Optional additional parameters
      parameters: [
        { key: 'translator.vast.loadWithCookie', value: true },
 { key: 'PARAM_NAME', value: 'value', level: tv.freewheel.SDK.PARAMETER_LEVEL_GLOBAL }
      ],

      // Optional visitor info
      visitor: {
        customId: 'test',
        address: '10.0.0.1',
      },

      // --- Optional midroll cue points ---
      // Option 1: Simple array of time positions in seconds (uses midrollSlotId)
      // midrollCuePoints: [30, 60, 90],

      // Option 2: Custom slot ID per cue point
      // midrollCuePoints: [
      //   { time: 30, slotId: 'midroll_30' },
      //   { time: 60, slotId: 'midroll_60' },
      //   { time: 90, slotId: 'midroll_90' },
      // ],

      // --- Optional targeting key-values ---
      keyValues: {
        customTargetingKey: 'JSAMDemoPlayer',
      },

      // --- Callbacks ---

      // Called when the FreeWheel context is available.
      // Use this to add or modify key-values before the ad request.
      onContextAvailable: function (context) {
        // Example:
        // context.addKeyValue('dynamicKey', 'dynamicValue');
      },

      // Called just before the ad request is submitted.
      // Use this to schedule additional temporal slots (e.g., custom midrolls).
      onBeforeAdRequest: function (context) {
        // Example: add a midroll at 180 seconds (3 minutes)
        // context.addTemporalSlot(
        //   'custom_midroll_180',
        //   tv.freewheel.SDK.ADUNIT_MIDROLL,
        //   180
        // );
      },
    },
  },
};


// Registers FW module and initializes Bitmovin player 
bitmovin.player.Player.addModule(window.bitmovin.player['advertising-freewheel'].default);
const player = new bitmovin.player.Player(document.getElementById('player'), conf);
player.load(source)

Server-Side Ad Insertion (SSAI)

ProviderAMP1 supportAMP2 supportMigration notes
IMA DAIPlugin SupportedDirect migration path
YospacePlugin IntegrationUse bitmovin-player-web-integrations-yospace
AWS MediaTailorVia manifest SupportedWorks with HLS/DASH

Google IMA DAI (SSAI)

AMP1 implementation:

var config = {
  media: {
    src: "http://storage.googleapis.com/testtopbox-public/video_content/bbb/master.m3u8",
    type: "application/x-mpegURL"
    temporalType: "live",
    assetKey: "sN_IYUG8STe1ZzhIIE_ksA"
  },
  plugins: {
    imadai: {
      resources: [
        {src: "//imasdk.googleapis.com/js/sdkloader/ima3_dai.js", type: "text/javascript", async: true},
        {src: "${paths.plugins}imadai/Imadai.js", type: "text/javascript", async: true}
      ]
    }
  },
};
akamai.amp.AMP.create("amp", config);

AMP2 implementation:

As of the time this migration guide was written, no prominent DAI integration example had been identified, while DAI is listed as an available integration. Check with a Bitmovin representative for SSAI guidance with Google’s IMA DAI SDK.

Yospace (SSAI)

AMP1 implementation:

var config = {
  plugins: {
    yospace: {
        debug: true,
        resources: [
          {src: "yo-ad-management.min.js", type: "text/javascript"},
          {src: "../akamai/amp/amp-yospace/Yospace.js", type: "text/javascript"}
        ]
      }
    }
  }
};

akamai.amp.AMP.create("amp", config);

AMP2 implementation:

const yospaceConfig: YospaceConfiguration = {
debug: true,
};

const bitmovinYospacePlayer = new BitmovinYospacePlayer(Player, playerContainer, conf, yospaceConfig);

7. Migrate DRM configuration

AMP1 implementation:

var config = {
    media: {
        source: [{
            src: "https://example.com/stream.mpd",
            type: "application/dash+xml",
        }, {
            src: "https://example.com/stream.m3u8",
            type: "application/x-mpegURL",
        }],
        keys: {
            "com.widevine.alpha": {
                "serverURL": "https://license-server.com/widevine"
            },
            "com.microsoft.playready": {
                "serverURL": "https://license-server.com/playready",
                "httpRequestHeaders": {
                    "http-header-CustomData": "eyJ1c2VySWQiOiIxM..."
                }
            },
            "com.apple.fps.1_0": {
                "serverURL": "https://license-server.com/fairplay",
                "cert": "https://example.com/certificate.cer"
            }
        }
    }
}

AMP2 implementation:

{
  source: {
    dash: "https://example.com/stream.mpd",
    drm: {
      widevine: {
        LA_URL: "https://license-server.com/widevine",
        headers: {
          "X-Custom-Header": "value"
        }
      },
      playready: {
        LA_URL: "https://license-server.com/playready"
      },
      fairplay: {
        LA_URL: "https://license-server.com/fairplay",
        certificateURL: "https://example.com/certificate.der"
      }
    }
  }
}

8. Migrate UI customization

You can migrate UI customization through theme configuration API and pseudo CSS style rules.

AMP1 implementation:

  • React UI Theme setting
{
  plugins: {
    react: {
      theme: {
          text: "#746A3C",
          foreground: "#C2B49B",
          background: "#2E3D33"
        },
    }
  }
}
  • React UI CSS style
<style>
  .amp-icon:hover {
    color: #B98853;
  }
  .amp-playpause {
    color: #B18742
  }
</style>

AMP2 implementation:

  • UI framework
// Bitmovin UI - open source framework
const uiConfig = {
  variant: 'custom',
  customCss: 'path/to/custom.css'
};
const player = new Player(container, {
  ui: uiConfig
});
<style>
#player .bmpui-ui-controlbar {
  background: rgba(10,10,12,0.8);
  height: 48px;
}

#player .bmpui-ui-playbacktogglebutton {
  border-radius: 9999px;
  width: 40px; height: 40px;
}

</style>

📘

Version 4 of Bitmovin Player UI will become the default UI of Bitmovin Player on all platforms from the end of January 2026. For more information, see What's new in Bitmovin Player UI v4.