diff --git a/lti_consumer/static/js/xblock_lti_consumer.js b/lti_consumer/static/js/xblock_lti_consumer.js
index db835be4f4995022507c72b2ae97ce4e1be4b578..1a38d644bb7135a8f78c027d84c2e88a0d01cc62 100644
--- a/lti_consumer/static/js/xblock_lti_consumer.js
+++ b/lti_consumer/static/js/xblock_lti_consumer.js
@@ -8,51 +8,51 @@ function LtiConsumerXBlock(runtime, element) {
             iframeModal: function (options) {
                 var $trigger = $(this);
                 var modal_id = $trigger.data("target");
-                var defaults = {top: 100, overlay: 0.5, closeButton: null};
+                var defaults = { top: 100, overlay: 0.5, closeButton: null };
                 var overlay_id = (modal_id + '_lean-overlay').replace('#', '');
                 var overlay = $("<div id='" + overlay_id + "' class='lean-overlay'></div>");
                 $("body").append(overlay);
                 options = $.extend(defaults, options);
                 return this.each(function () {
                     var o = options;
-                    $(this).click(function (e) {
-                        var $modal = $(modal_id);
-                        // If we are already in an iframe, skip creation of the modal, since
-                        // it won't look good, anyway. Instead, we post a message to the parent
-                        // window, requesting creation of a modal there.
-                        // This is used by the courseware microfrontend.
-                        if (window !== window.parent) {
-                            window.parent.postMessage(
-                                {
-                                    'type': 'plugin.modal',
-                                    'payload': {
-                                        'url': window.location.origin + $modal.data('launch-url'),
-                                        'title': $modal.find('iframe').attr('title'),
-                                        'width': $modal.data('width')
-                                    }
-                                },
-                                document.referrer
-                            );
-                            return;
-                        }
-                        // Set iframe src attribute to launch LTI provider
-                        $modal.find('iframe').attr('src', $modal.data('launch-url'));
-                        $("#" + overlay_id).click(function () {
-                            close_modal(modal_id)
-                        });
-                        $(o.closeButton).click(function () {
-                            close_modal(modal_id)
-                        });
-                        var modal_height = $(modal_id).outerHeight();
-                        var modal_width = $(modal_id).outerWidth();
-                        $("#" + overlay_id).css({"display": "block", opacity: 0});
-                        $("#" + overlay_id).fadeTo(200, o.overlay);
-                        $(modal_id).css({
-                            "display": "block"
-                        });
-                        $(modal_id).fadeTo(200, 1);
-                        $(modal_id).attr('aria-hidden', false);
-                        $('body').css('overflow', 'hidden');
+
+                    var $modal = $(modal_id);
+                    // If we are already in an iframe, skip creation of the modal, since
+                    // it won't look good, anyway. Instead, we post a message to the parent
+                    // window, requesting creation of a modal there.
+                    // This is used by the courseware microfrontend.
+                    if (window !== window.parent) {
+                        window.parent.postMessage(
+                            {
+                                'type': 'plugin.modal',
+                                'payload': {
+                                    'url': window.location.origin + $modal.data('launch-url'),
+                                    'title': $modal.find('iframe').attr('title'),
+                                    'width': $modal.data('width')
+                                }
+                            },
+                            document.referrer
+                        );
+                        return;
+                    }
+                    // Set iframe src attribute to launch LTI provider
+                    $modal.find('iframe').attr('src', $modal.data('launch-url'));
+                    $("#" + overlay_id).click(function () {
+                        close_modal(modal_id)
+                    });
+                    $(o.closeButton).click(function () {
+                        close_modal(modal_id)
+                    });
+                    var modal_height = $(modal_id).outerHeight();
+                    var modal_width = $(modal_id).outerWidth();
+                    $("#" + overlay_id).css({ "display": "block", opacity: 0 });
+                    $("#" + overlay_id).fadeTo(200, o.overlay);
+                    $(modal_id).css({
+                        "display": "block"
+                    });
+                    $(modal_id).fadeTo(200, 1);
+                    $(modal_id).attr('aria-hidden', false);
+                    $('body').css('overflow', 'hidden');
 
                         e.preventDefault();
 
@@ -71,19 +71,19 @@ function LtiConsumerXBlock(runtime, element) {
                            }
                         });
 
-                        /* Redirect non-iframe tab to close button */
-                        var $inputs = $('select, input, textarea, button, a').filter(':visible').not(o.closeButton);
-                        $inputs.on('focus', function(e) {
-                            e.preventDefault();
-                            $(options.closeButton).focus();
-                        });
+                    /* Redirect non-iframe tab to close button */
+                    var $inputs = $('select, input, textarea, button, a').filter(':visible').not(o.closeButton);
+                    $inputs.on('focus', function (e) {
+                        e.preventDefault();
+                        $(options.closeButton).focus();
                     });
+
                 });
                 function close_modal(modal_id) {
                     var $modal = $(modal_id);
                     $('select, input, textarea, button, a').off('focus');
                     $("#" + overlay_id).fadeOut(200);
-                    $modal.css({"display": "none"});
+                    $modal.css({ "display": "none" });
                     $modal.attr('aria-hidden', true);
                     $modal.find('iframe').attr('src', '');
                     $('body').css('overflow', 'auto');
@@ -92,68 +92,98 @@ function LtiConsumerXBlock(runtime, element) {
             }
         });
 
+        function confirmDialog(message, triggerElement, showCancelButton) {
+            var def = $.Deferred();
+            // Hide the button that triggered the event, i.e. the launch button.
+            triggerElement.hide();
+
+            $('<div id="dialog-container"></div>').insertAfter(triggerElement) // TODO: this will need some cute styling. It looks like trash but it works.
+                .append('<p>' + message + '</p>')
+            if (showCancelButton) {
+                $('#dialog-container')
+                .append('<button style="margin-right:1rem" id="cancel-button">Cancel</button>');
+            }
+            $('#dialog-container').append('<button id="confirm-button">OK</button>');
+
+            // When a learner clicks "OK" or "Cancel" in the consent dialog, remove the consent dialog, show the launch
+            // button, and resolve the promise.
+            $('#confirm-button').click(function () {
+                // Show the button that triggered the event, i.e. the launch button.
+                triggerElement.show();
+                $("#dialog-container").remove()
+                $('body').append('<h1>Confirm Dialog Result: <i>Yes</i></h1>');
+                def.resolve("OK");
+            })
+            $('#cancel-button').click(function () {
+                // Hide the button that triggered the event, i.e. the launch button.
+                triggerElement.show()
+                $("#dialog-container").remove()
+                $('body').append('<h1>Confirm Dialog Result: <i>No</i></h1>');
+                def.resolve("Cancel");
+            })
+            return def.promise();
+        };
+
         var $element = $(element);
         var $ltiContainer = $element.find('.lti-consumer-container');
         var askToSendUsername = $ltiContainer.data('ask-to-send-username') == 'True';
         var askToSendEmail = $ltiContainer.data('ask-to-send-email') == 'True';
 
-        // Apply click handler to modal launch button
-        $element.find('.btn-lti-modal').iframeModal({top: 200, closeButton: '.close-modal'});
-
-        // Apply click handler to new window launch button
-        $element.find('.btn-lti-new-window').click(function(){
-
-            // If this instance is configured to require username and/or email, ask user if it is okay to send them
-            // Do not launch if it is not okay
-            var destination = $(this).data('target')
-
-            function confirmDialog(message) {
-                var def = $.Deferred();
-                $('<div></div>').appendTo('body') // TODO: this will need some cute styling. It looks like trash but it works.
-                  .html('<div><p>' + message + '</p></div>')
-                  .dialog({
-                    modal: true,
-                    title: 'Confirm',
-                    zIndex: 10000,
-                    autoOpen: true,
-                    width: 'auto',
-                    resizable: false,
-                    dialogClass: 'confirm-dialog',
-                    buttons: {
-                      OK: function() {
-                        $('body').append('<h1>Confirm Dialog Result: <i>Yes</i></h1>');
-                        def.resolve("OK");
-                        $(this).dialog("close");
-                      },
-                      Cancel: function() {
-                        $('body').append('<h1>Confirm Dialog Result: <i>No</i></h1>');
-                        def.resolve("Cancel");
-                        $(this).dialog("close");
-                      }
-                    },
-                    close: function(event, ui) {
-                      $(this).remove();
-                    }
-                  }).prev().css('background', 'white').css('color', '#000').css('border-color', 'transparent');
-                return def.promise();
-              };
-
-            if(askToSendUsername && askToSendEmail) {
+        function renderPIIConsentPromptIfRequired(onSuccess, showCancelButton=true) {
+            if (askToSendUsername && askToSendEmail) {
                 msg = gettext("Click OK to have your username and e-mail address sent to a 3rd party application.\n\nClick Cancel to return to this page without sending your information.");
             } else if (askToSendUsername) {
                 msg = gettext("Click OK to have your username sent to a 3rd party application.\n\nClick Cancel to return to this page without sending your information.");
             } else if (askToSendEmail) {
                 msg = gettext("Click OK to have your e-mail address sent to a 3rd party application.\n\nClick Cancel to return to this page without sending your information.");
             } else {
-                window.open(destination);
+                onSuccess("OK");
+                return;
             }
-            $.when(confirmDialog(msg)).then(
-                function(status) {
+            $.when(confirmDialog(msg, $(this), showCancelButton)).then(onSuccess);
+        }
+
+        // Render consent dialog for inline elements immediately.
+        var $ltiIframeContainerElement = $element.find('#lti-iframe-container');
+        $ltiIframeContainerElement.each(function () {
+            var ltiIframeTarget = $ltiIframeContainerElement.data('target')
+            renderPIIConsentPromptIfRequired.apply(this, [
+                function (status) {
+                    if (status === 'OK') {
+                        // After getting consent to share PII, set the src attribute of the iframe to start the launch.
+                        $ltiIframeContainerElement.find('iframe').attr('src', ltiIframeTarget);
+                    }
+                },
+                false
+            ]);
+        })
+
+        // Apply click handler to modal launch button.
+        var $ltiModalButton = $element.find('.btn-lti-modal');
+        $ltiModalButton.click(function () {
+            renderPIIConsentPromptIfRequired.apply(this, [
+                function (status) {
+                    if (status === 'OK') {
+                        $ltiModalButton.iframeModal({
+                            top: 200, closeButton: '.close-modal'
+                        })
+                    }
+                }
+            ]);
+        });
+
+        // Apply click handler to new window launch button.
+        var $ltiNewWindowButton = $element.find('.btn-lti-new-window');
+        $ltiNewWindowButton.click(function () {
+            renderPIIConsentPromptIfRequired.apply(this, [
+                function (status) {
                     if (status == "OK") {
-                        window.open(destination);
+                        window.open(
+                            $ltiNewWindowButton.data('target')
+                        );
                     }
                 }
-            );
+            ]);
         });
     });
 }
diff --git a/lti_consumer/templates/html/student.html b/lti_consumer/templates/html/student.html
index bd14c773c8c6e0d1441a2c51cf452d7a084a8187..05afb6a6f6b1c7ab0988ef2176c6fc49f2d3c9fb 100644
--- a/lti_consumer/templates/html/student.html
+++ b/lti_consumer/templates/html/student.html
@@ -68,9 +68,11 @@
         </section>
     % endif
     % if launch_target == 'iframe':
-        <div style="height:${inline_height}px;">
+        <div id="lti-iframe-container" data-target="${form_url}" style="height:${inline_height}px;">
             ## The result of the LTI launch form submit will be rendered here.
-            <%include file="templates/html/lti_iframe.html" args="initial_launch_url=form_url"/>
+            ## Don't pass in the initial_launch_url. Let the Javascript set the src, so we can get PII sharing consent
+            ## before the launch occurs, if needed.
+            <%include file="templates/html/lti_iframe.html" args="initial_launch_url=''"/>
         </div>
     % endif
 % elif not hide_launch: