## Prerequisites

To integrate and test the PAL SDK for Cast, you need the following:

- A [receiver app](https://developers.google.com/cast/docs/web_receiver/basic) to generate a nonce using
  [message
  interception](https://developers.google.com/cast/docs/web_receiver/core_features#message_interception).

- A [sender app](https://developers.google.com/cast/docs/web_sender) to trigger the receiver to load
  content containing an ad request.

Since you only need to update your receiver app to integrate the PAL SDK, you
can use the [Cast Command and Control (CAC) Tool](https://developers.google.com/cast/docs/debugging/cac_tool)
as a web sender to test your receiver.

You can run the sample at the end of each step by first [launching your web
receiver app](https://developers.google.com/cast/docs/debugging/cac_tool#launch_web_receiver_app) in the CAC
Tool, then making any [load request](https://developers.google.com/cast/docs/debugging/cac_tool#load_media).

## Generate nonce

A "nonce" is a single encrypted string generated by PAL through the
[`NonceManager`](https://developers.google.com/ad-manager/pal/cast/reference/js/NonceManager). The
`NonceManager` is generated by the
[`loadNonceManager`](https://developers.google.com/ad-manager/pal/cast/reference/js/NonceLoader#loadNonceManager)
method of the [`NonceLoader`](https://developers.google.com/ad-manager/pal/cast/reference/js/NonceLoader),
based on settings passed in a
[`NonceRequest`](https://developers.google.com/ad-manager/pal/cast/reference/js/NonceRequest). To see a
sample app that uses PAL to generate a nonce, download the Cast example from
[GitHub](https://github.com/googleads/googleads-pal).

Each new stream request requires a new nonce. Multiple ad requests within the
same stream can use the same nonce. To generate a nonce using the PAL SDK, first
create a [customized web receiver
app](https://developers.google.com/cast/docs/web_receiver/core_features#creating_a_customized_web_receiver_app)
and add the following code:

### receiver.html

    <!DOCTYPE html>
    <html>
    <head>
      <script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
      <script src="//imasdk.googleapis.com/pal/sdkloader/cast_pal.js"></script>
    </head>
    <body>
      <cast-media-player></cast-media-player>
      <footer>
        <script src="js/receiver.js" type="module"></script>
      </footer>
    </body>
    </html>

The `<cast-media-player>` element represents the built-in player UI provided by
the Cast Web Receiver API. Depending on the stream type, the actual player used
can vary. You can find the exact versions of these players in the Google Cast
SDK [release notes](https://developers.google.com/cast/docs/release-notes).

Next, add the following code to intercept [LOAD
events](https://developers.google.com/cast/docs/reference/web_receiver/cast.framework.events.LoadEvent)
and generate a nonce each time the receiver loads a new
[`MediaInformation`](https://developers.google.com/cast/docs/reference/web_receiver/cast.framework.messages.MediaInformation)
object:

### js/receiver.js

    const castContext = cast.framework.CastReceiverContext.getInstance();
    const playerManager = castContext.getPlayerManager();

    const consentSettings = new goog.cast.pal.ConsentSettings();
    // For the correct usage of the allowStorage property, See
    // developers.google.com/ad-manager/pal/cast/reference/js/ConsentSettings#allowStorage.
    consentSettings.allowStorage = true;

    // You need a nonce loader to request your stream's nonceManager. The
    // nonceManager provides your nonce. You should reuse the same nonce loader for
    // the entire lifecycle of the receiver.
    const nonceLoader = new goog.cast.pal.NonceLoader(consentSettings);

    // You need a reference to the NonceManager to track when an ad is shown or
    // clicked.
    let nonceManager;

    /**
     * Sends a debug message to the CAF sender.
     *
     * @param {String} message - The message to send
     */
    const log = (message) => {
      // Use CastDebugLogger to log a message to the sender. See
      // https://developers.google.com/cast/docs/debugging/cast_debug_logger.
    }

    /**
     * Stores the nonce manager in the outer scoped variable and retrieves a nonce,
     * so it can be used to build your ad request URL
     *
     * @param {NonceManager} loadedNonceManager - The loaded nonce manager
     */
    const buildAdRequest = (loadedNonceManager) => {
      nonceManager = loadedNonceManager;

      const nonce = nonceManager.getNonce();
      log('received nonce:' + nonce);

      // TODO: Set this nonce as the value for the `givn` parameter of your ad
      // request URL. For example:
      // const adRequestURL = 'https://myadserver.com/ads?givn=' + nonce;
    }

    /**
     * Configures a new nonce request, then requests a nonce.
     *
     * @param {LoadRequestData} loadRequestData - the load request object,
     * which contains the MediaInformation object from the sender. See
     * developers.google.com/cast/docs/reference/web_receiver/cast.framework.messages.LoadRequestData
     * @return {(Promise<LoadRequestData>)} - A Promise to build an ad request.
     */
    const handleLoadRequest = (loadRequestData) => {
      // Clear any old nonceManager before loading new media.
      nonceManager = null;

      // See developers.google.com/ad-manager/pal/cast/reference/js/NonceRequest
      // for details about each property. The NonceRequest parameters set here are
      // example parameters. You should set your parameters based on your own app
      // characteristics.
      const nonceRequest = new goog.cast.pal.NonceRequest();
      nonceRequest.adWillAutoPlay = true;
      // A URL describing the video stream.
      nonceRequest.descriptionUrl = 'https://example.com';
      nonceRequest.iconsSupported = true;
      nonceRequest.ppid = 'Sample PPID';
      nonceRequest.sessionId = 'Sample SID';
      nonceRequest.url = loadRequestData.media.contentUrl;
      // The height of the player in physical pixels.
      // For a fullscreen player on a 1080p screen, the video height would be 1080.
      nonceRequest.videoHeight = window.devicePixelRatio * window.screen.height;
      // The width of the player in physical pixels.
      // For a fullscreen player on a 1080p screen, the video width would be 1920.
      nonceRequest.videoWidth = window.devicePixelRatio * window.screen.width;

      return nonceLoader.loadNonceManager(nonceRequest)
        .then(buildAdRequest)
        .catch((e) => {
          log("Error: " + e.message);
        });
    };

    // Set up the event handler for the LOAD event type.
    playerManager.setMessageInterceptor(cast.framework.messages.MessageType.LOAD, handleLoadRequest);

    castContext.start();

When making your direct VAST call (DVC), set this nonce as the value on the
`givn` parameter. The nonce is URL safe; you don't need to URL-encode it.

> [!CAUTION]
> **Caution:** If you previously provided a nonce using the `paln` parameter, it is strongly recommended to migrate to `givn` and stop sending `paln`. If both parameters are included, it is undefined behavior regarding which nonce one is used.

If you are requesting and rendering ads from Google, you must render
the [AdChoices](https://support.google.com/My-Ad-Center-Help/answer/12155764) icon and overlay.
For details about parsing the VAST response and rendering icons, see
[AdChoices icon and overlay](https://developers.google.com/ad-manager/pal/cast/wta).

## Track video interactions

In addition to generating a nonce, the PAL SDK needs to be notified on certain
video interactions. To track interactions with the Cast receiver, add the
following code to your custom receiver:

### js/receiver.js

    const castContext = cast.framework.CastReceiverContext.getInstance();
    const playerManager = castContext.getPlayerManager();

    const consentSettings = new goog.cast.pal.ConsentSettings();
    // For the correct usage of the allowStorage property, See
    // developers.google.com/ad-manager/pal/cast/reference/js/ConsentSettings#allowStorage.
    consentSettings.allowStorage = true;

    // You need a nonce loader to request your stream's nonceManager. The
    // nonceManager provides your nonce. You should reuse the same nonce loader for
    // the entire lifecycle of the receiver.
    const nonceLoader = new goog.cast.pal.NonceLoader(consentSettings);

    // You need a reference to the NonceManager for sending ad events.
    let nonceManager;

    // Track playback status.
    let playbackDidStart = false;

    ...

    // Register the start of playback.
    playerManager.addEventListener(cast.framework.events.EventType.PLAYING, () =\> {
    if (playbackDidStart) return;
    playbackDidStart = true;
    if (nonceManager) {
    log('Registered playback start');
    nonceManager.sendPlaybackStart();
    } else {
    log("Error: There is no nonce manager for this media.");
    }
    });
    // Register any interactions with the player.
    const interactionEvents = \[
    cast.framework.events.EventType.REQUEST_SEEK,
    cast.framework.events.EventType.REQUEST_STOP,
    cast.framework.events.EventType.REQUEST_PAUSE,
    cast.framework.events.EventType.REQUEST_PLAY,
    cast.framework.events.EventType.REQUEST_SKIP_AD,
    cast.framework.events.EventType.REQUEST_PLAY_AGAIN,
    cast.framework.events.EventType.REQUEST_PLAYBACK_RATE_CHANGE,
    cast.framework.events.EventType.REQUEST_VOLUME_CHANGE,
    cast.framework.events.EventType.REQUEST_USER_ACTION,
    cast.framework.events.EventType.REQUEST_FOCUS_STATE,
    \];
    playerManager.addEventListener(interactionEvents, (interactionEvent) =\> {
    if (nonceManager) {
    log('Registered interaction: ' + interactionEvent);
    nonceManager.sendAdTouch(interactionEvent);
    } else {
    log("Error: There is no nonce manager for this media.");
    }
    });
    // Register the end of playback.
    playerManager.addEventListener(cast.framework.events.EventType.MEDIA_FINISHED, () =\> {
    playbackDidStart = false;
    if (nonceManager) {
    log('Registered playback end');
    nonceManager.sendPlaybackEnd();
    } else {
    log("Error: There is no nonce manager for this media.");
    }
    });
    castContext.start();

## (Optional) Send Google Ad Manager signals through third-party ad servers

Configure the third-party ad server's request for Ad Manager. After you
complete the following steps, the nonce parameter propagates from the PAL SDK,
through your intermediary servers, and then to Google Ad Manager. This enables
better monetization through Google Ad Manager.

> [!NOTE]
> **Note:** If you use multiple third-party solutions, for example, a third-party SSAI server calling another third-party ad server, you need to make sure the PAL SDK's encrypted nonce is forwarded to each third party.

Configure your third-party ad server to include the nonce in the server's
request to Ad Manager. Here's an example of an ad tag configured inside of the
third-party ad server:

    'https://pubads.serverside.net/gampad/ads?givn=%%custom_key_for_google_nonce%%&...'

For more details, see the [Google Ad Manager Server-side implementation
guide](https://support.google.com/admanager/answer/10668760).

Ad Manager looks for `givn=` to identify the nonce value. The third-party ad
server needs to support some macro of its own, such as
`%%custom_key_for_google_nonce%%`, and replace it with the nonce query parameter
you provided in the previous step. More information on how to accomplish this
should be available in the third-party ad server's documentation.