DARK SIDE OF THE FORMS: YouTube driven events (Basic)

Robb_Barrett
Marketo Employee
Marketo Employee

Hi All -

Many of you saw my Summit 2017 presentation on Dark Side of the Forms.  If you haven't, it's available here:

https://events.marketo.com/summit/2018/2017-recordings/learn-the-dark-side-of-the-forms-seduce-your-...

Video Link : 2110

I was recently asked by a colleague to write up the section I did on how to fire events from YouTube videos, so since I had already written it up I thought I'd share it here on a blog post in case anyone else is interested. This is the very basic version of that presentation, there are a lot of other items on the sample I provided that I'm not including here but will in the future.

Please Note: this requires some knowledge of JavaScript. I can't help you write out everything you need, but if you ask and I have some code, I'm happy to help you.

Also Note: I trimmed a lot of extra script out of here. If you find that something isn't working, please reply and I'll update it when I can

How this works (Customer Facing):

You go to a landing page with a video that automatically starts playing.

Screen Shot 2017-10-25 at 12.24.26 PM.png

If you pause the video:

1. If you are anonymous or don't have complete info, a form pops up

Screen Shot 2017-10-25 at 12.24.35 PM.png

2. If you fill out the form the form disappear and the video resumes playing.

Now, what REALLY happens:

As soon as you hit the page, a hidden background form submission occurs.

  1. A hidden form is submitted in the background
  2. A workflow is triggered from the form fill (even if anonymous) to:
    1. Make you a member of the program
    2. Record the campaign ID to your record
    3. Add to the lead note that you've watched the video
  3. OPTIONAL: Time spent watching can be recorded

How it works:

I won't go into all of the HTML necessary to build out the page, but you start with a basic 3 row page with the middle section having two columns.  The left column shown above is sized to fit the form in it. There are some tokens needed for this program. The screen shot is not complete but shows the main ones:

Screen Shot 2017-10-25 at 11.55.30 AM.png

For the {{my.youtube-video-id}} token, you can get it from the URL in the "v=" parameter:

Screen Shot 2017-10-25 at 3.41.18 PM.png

What else you'll need:

  • A completely blank form. Absolutely no fields on it.: {{my.hidden-submit-form}} Add in a token with the form ID
  • A form with all of the information you'll want someone to fill out: {{my.update-info-form}}. Add in a token with the form ID

  • the Form IDs, which can be found in the URL for the form. I always include the form ID in the name of the form for precision selection:
    • Screen Shot 2017-10-25 at 12.42.35 PM.png
      • Create tokens using JUST the form ID number. I store these tokens in a folder and put all my programs under it. You'll code in <form id="mktoForm_{{my.update-info-form}}"></form>, which will make this template usable with any number of different forms for different programs.
        Screen Shot 2017-10-25 at 2.48.44 PM.png
        Also worth noting, I keep my Munchkin code as a token, and you'll see that below as {{my.Munchkin-Code}}. This makes it easier when developing on a DEV / UAT server and then migrating to PROD.

  • A workflow to handle the form fills. I always store my forms in the design studio and use one form for multiple programs, so you'll also need to add in the referrer page name. I like to do "contains" and then just put in the page name from the URL builder. Notice that I have several forms in here: you'll want the Hidden form and the Update Info form (I have others in there that are relics and should be cleaned out eventually). Don't worry too much about steps 2 and 3, we'll get into those later.
    • Screen Shot 2017-10-25 at 11.59.59 AM.png
    • Screen Shot 2017-10-25 at 12.00.10 PM.png



Now, for the code.  I'm not going to go into all of the HTML necessary but here are a few important pieces:
1. Initial Code:

     <meta name="viewport" content="width=device-width, initial-scale=1.0"> // Make this mobile friendly

     <meta http-equiv="X-UA-Compatible" content="IE=edge" />    // Make this IE friendly

     <link rel="shortcut icon" href="http://yourcompanywebsite/favicon.png" type="image/x-icon" /> 

     <title>COMPANY NAME | PRODUCT LINE | {{my.Asset-type}}</title>

     <meta charset="utf-8">

     <meta name="author" content="{{my.Metadata-Author}}">  // Optional, but best practice

     <meta name="keywords" content="{{my.Metadata-Keywords}}"> // Optional, but best practice

     <meta name="description" content="{{my.Metadata-Description}}">  // Optional, but best practice

     <link rel="stylesheet" type="text/css" media="all" href="https://nation.marketo.com/css/mktLPSupportCompat.css"> //Just because

Next, call the scripts under the head: (tokens highlighted in bold)

     <script src="//app-<your pod ID>.marketo.com/js/forms2/js/forms2.min.js"></script>
     <script type="text/html" id="form-html"><form id="mktoForm_{{my.update-info-form}}"></form></script>
     <script type="text/javascript"  src="https://app.marketo.com/js/public/jquery-latest.min.js"></script>

2. CSS is attached to this post. I removed URLs for images used.

3. This is the basic HTML structure for this template

<div id="column"> //Centers the DIVs in the middle

   <div id="middle"> //I've excluded the top and bottom but this is a basic three row design page

              <div id="rectangle"> // The rectangle is a DIV in the #middle that conforms to the #column and has a different colored background. It's made up of #body-left and #body-right

                      <div class="box" id="body-left"> // Holds the text describing the video, including speaker pics and bios. It's all token driven.

                           <div id="asset-type"><h3>{{my.Asset-type}}</h3></div> //Not necessary, but I have it on my page

                           <div id="headline"><h1>{{my.Body-headline}}</h1></div>

                           <div id="left-side-copy">{{my.Body-copy}}</div> // Rich Text token so a marketer can be fancy without needing to alter the template

                  </div><!--left-side-container-->

                  <div id="body-right" class="box"> // Holds the text video

                        <div id="preform-div" style="z-index: 100;">

                              <div id="player"></div> //This is where the video will play

                              </div> //Closes Preform DIV

                        <div id="form-div" class="form"></div> //We won't really use these two DIVs, but it doesn't hurt to keep them in

                        <div id="postform-div"></div>

                  </div><!---Body-Right Close-->

        </div><!--Rectangle-->

      </div><!--Middle Div-->

      </div><!--Column-->

     <div class="clear"></div> // Keeps everything looking nice

     <div class="mktoContent"></div>  //Because Marketo insists!

<!--This is the main form wrapper and form. It's not going to appear initially it's going to be invisible and will overlay everything else when visible -->

     <div id="mainFormWrapper" class="vertical-center">

          <div id="formContainer" class="vertical-center">

               <div style="cursor: pointer;" id="formClose">CLOSE</div>  //Not getting into this at this point, there's more for later

               <div id="formHeader"><h1>{{my.Modal Header}}</h1>  //This is text that you put in a token to appear at the top to the modal

                     <p>

                             {{my.Modal Text}}       //This is just test you want to appear above the form

                     </p>

                </div>

                <div id="spacer"></div> //Puts in some space, create your own CSS value for how much

                 <div id="verifyInfo" style="z-index: 40; padding: 20px;"> //Cutting out a lot on this part for later, but keep this in

                     <p>

                           If you'd like to be contacted by a Representative, please confirm your information below:

                     </p><br />

                    <form id="mktoForm_{{my.hidden-submit-form}}" style="display: none;"></form>

                 </div> <!--Verify Info -->

                <div id="mainFormDiv"></div>

               <div id="mainFormDivBottomSpace"></div>

     </div> //form Container

4. This script:

   <script type="text/javascript">

          $ja = jQuery.noConflict();

           var showAlert = 1; //Make sure the pop-up only shows once

           var showModalAgain = 1 //Turns the modal on

           var emailAddress = '{{lead.Email Address}}';

           var firstName = '{{lead.First Name}}';

           var state = '{{lead.State}}';

           var formSubmitted = 0;

           var addedToProgram = 0;

           document.getElementById("mainFormDiv").innerHTML = document.getElementById("form-html").innerHTML;

//This function shows the form, in a box, when called -->

          function showModal() {

                 if (showModalAgain != 0) {

                      document.getElementById("mainFormWrapper").style.display = 'block';

                      document.getElementById("mainFormWrapper").style.zIndex = '30';

                      document.getElementById("mainFormDiv").style.zIndex = '40';

                      showUpdateForm();

                      $ja("#verifyInfo").fadeOut();

                      $ja('#verifyInfo').replaceWith( '<div id="left-side-copy" style="padding-left: 20px;"><p>If you would like to learn more, please fill out the form below.</p></div>' );

                      $ja("#verifyInfo").fadeIn("slow");

                      $ja("#verifyInfo").append($ja("#mainFormDiv"));

                       document.getElementById("mainFormDiv").style.display = 'block';

                  }

            }

//This is the YouTube API -->

     var tag = document.createElement('script');

     tag.src = "https://www.youtube.com/iframe_api";

     var firstScriptTag = document.getElementsByTagName('script')[0];

     firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

     var player;

//Adjust the width and height as needed -->

     function onYouTubeIframeAPIReady() {

            player = new YT.Player('player', {

                 videoId: '{{my.youtube-video-id}}',

                 height: '390',

                 width: '640',

                 events: {

                     'onReady': onPlayerReady,

                     'onStateChange': onPlayerStateChange

                  }

            });

         }

//The API will call this function when the video player is ready. This starts playing the video. -->

     function onPlayerReady(event) {

       event.target.playVideo();

     }

//These are the recognized events / states -->

/** YouTube API

        -1 (unstarted)

        0 (ended)

        1 (playing)

        2 (paused)

        3 (buffering)

        5 (video cued)

**/

//Part 1: Immediately run a hidden form submit when the video is playing to trigger a workflow to add the person to the program -->

     function onPlayerStateChange(event) {

            if ((event.data === 1) && (addedToProgram === 0)) {  //event.data === 1 means the video has started playing

             addedToProgram = 1;  //this prevents this script from continuously running at starts and stops

         MktoForms2.loadForm("//app-XXX.marketo.com", "{{my.Munchkin-Code}}", {{my.hidden-submit-form}},

        function(form) {

               var myForm = MktoForms2.getForm({{my.hidden-submit-form}});

               myForm.addHiddenFields({ // Since the form you're using is absolutely blank, you'll need to add in any fields you want to post to it and any values.
                                                            //If you have custom dedupe fields, make sure you add them as well

                     "Email":"{{lead.Email Address}}",

                     "formProgramID":"{{program.name}}", //whichever field you use for Campaign IDs

          }); //Since we're not asking any questions, just the email address and Campaign ID are enough to update the record, but you do you.

        form.onSuccess(function(values, followUpUrl) {

             // Stop the form from refreshing the page

             return false;

         });

     myForm.submit();

          }

         );

     }

//At this point, you have an event that can trigger a workflow to add the person to the program. Information about a trigger campaign is mentioned above. -->

//Now we're going to pop up a REAL form is they hit Pause-->

  if ((event.data === 2) && (showModalAgain != 0)) {  //event.data === 2 means Paused

    showModal();

  }

}

//The showModal function above calls a script which calls this script -->

     function showUpdateForm() {

         MktoForms2.loadForm("//app-XXXX.marketo.com", "{{my.Munchkin-Code}}", {{my.update-info-form}},

      function(form) {  //First, prefill the form. I manually prefill embedded forms as it doesn't work if it's just enabled on the form. Make sure you add in any custom fields you use.

      form.vals({

                 "FirstName":"{{lead.First Name}}",

                 "LastName":"{{lead.Last Name}}",

                 "Company":"{{company.Company Name}}",

                 "Email":"{{lead.Email Address}}",

                 "State":"{{lead.State}}",

                 "Title":"{{lead.Job Title}}",

                 "formProgramID":"{{program.name}}",     //Same as Campaign ID in my world

                 "City":"{{lead.City}}",

                 "Address":"{{lead.Address}}",

                 "phone":"{{lead.Phone}}",

                 "PostalCode":"{{lead.Postal Code}}"

                });

           var formEl = form.getFormElem()[0];

      form.onSuccess(function() { //After the form is submitted, hide the form and resume playing the video

            form.getFormElem().hide();

             $ja("#mainFormWrapper").fadeOut("slow");

             document.getElementById("mainFormWrapper").style.zIndex='0'; //bury the form wrapper under everything else

            $ja("#left-side-copy").fadeOut();

             $ja("#left-side-copy").fadeIn("slow");

             document.getElementById("left-side-copy").innerHTML = '<p>Thank you for your interest.</p>';

             player.playVideo(); // This restarts the video

            showModalAgain = 0;  //Don't show again if the video is paused

             return false;

             formSubmitted = 1;

           }); //Close onSuccess

         }); //Close loadForm

     }  //close showUpdateForm function

</script>

-------EXPLANATION OF THE TOKENS ON THE MODAL-------

MODAL EXPLANATION.jpg

4087
3
3 Comments
Michael_Mason
Level 4

I know you said you could note how much time someone was watching, could you note if someone watches past, say 2:30 and iterate a lead score based on that?

Robb_Barrett
Marketo Employee

Sure, you'd put in a timer:

var videotime = 0;

var timeupdater = null;

Change section 3 in the above code to this:

// 3. The API will call this function when the video player is ready.

function onPlayerReady(event) {

  event.target.playVideo();

  //Records the amount of time played

  function updateTime() {

    var oldTime = videotime;

    if(player && player.getCurrentTime) {

      videotime = player.getCurrentTime();

    }

    if(videotime !== oldTime) {

      onProgress(videotime);

    }

  }

  timeupdater = setInterval(updateTime, 100); 

}

// when the time changes, this will be called.

function onProgress(currentTime) {

  if(currentTime > 150) {  //150 = 2:30

          MktoForms2.loadForm("//app-XXX.marketo.com", "123-XXX-456", {{my.hidden-submit-form}},

          function(form) {

          var myForm = MktoForms2.getForm({{my.hidden-submit-form}});

          myForm.addHiddenFields({

          "Email":"{{lead.Email Address}}",

          "Some-Scoring-Field":"Value to Update Score"

          });

     myForm.submit();

     

     form.onSuccess(function() {

            form.getFormElem().hide();

             player.playVideo();

             return false; 

     }) ;

     });

}

}

Michael_Mason
Level 4

Thanks Robb!! Much appreciated!