Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Customer Insights - Journeys forum

Simplify or replace default CAPTCHA

(1) ShareShare
ReportReport
Posted on by 180

HI

Does anyone know if you can change the default CAPTCHA used in Dynamics Marketing to be simpler. The 8 characters is too long and not easy to read.

Or how easy or difficult is it to use another CAPTCH for example from Google?

Brad

  • BAStephie Profile Picture
    BAStephie 10 on at
    RE: Simplify or replace default CAPTCHA

    SGee 

    No worries!  The class is on the opening <form> tag in Dynamics.  I've included a screen shot for clarity but I'll type it out as well in case the image breaks:

    Navigate to your form, click edit and then click "HTML" to look at the raw code.

    At the very top, you should some <meta> tags, then the opening <form> tag.

    Note: I formatted my HTML with line breaks to I could read it more easily and removed all the embedded styles.  Your form may have crazy horizontal scrolling and things jammed together.  In this case, CTRL F is your friend, search "<form" to find it.

    
    

    pastedimage1646923435803v1.png

    Another note, I am not using the iframe to embed! 

    In step 1 on the screenshot, you'll notice there's a menu item labeled "Form Hosting".  (This goes away when you're in the HTML editor, so you may need to navigate back to the form editor to bring it back)

    Note that I have "I want to host it as a script" selected, not the iframe one.  You cannot execute scripts on iframes (it's a security risk to modify third party embeds so browsers will block it)

    pastedimage1646925251245v2.png

    So ensure your embed starts with a <div> tag, not an <iframe> tag.

    Please let me know if you have any further questions

  • SGee Profile Picture
    SGee 15 on at
    RE: Simplify or replace default CAPTCHA

    Dear Stephanie,

    We are trying to implement your version of the original guide. Please note we are NOT developers... So hopefully my question doesn't come off as silly or stupid :)

    We noticed you mention the following in your code: "// NOTE: I added a class of "dynamics-form" on the HTML so I could target it"

    --> On what exact element are you putting this class? The code doesn't seem to run without it.

    I get the following error message, no matter where I put the extra class :(

    Uncaught TypeError: Cannot read properties of null (reading 'requestSubmit')
       at HTMLButtonElement. ((index):154:18)
       at HTMLButtonElement.patchedCallback (:132:45)

    Because I don't have the class on the specific element i'm assuming. Could you please tell us exactly which element? (website or html on Dynamics 365 itself?)

    Thank you so much for the extra information! I feel we are very close to a final solution!

  • BAStephie Profile Picture
    BAStephie 10 on at
    RE: Simplify or replace default CAPTCHA

    I just had this issue today and did the following.
    From Ron Peters answer, Step 5 (JavaScript), change to:

    function validateRecaptcha() {
    	var response = grecaptcha.getResponse();
    	if (response.length === 0) {
    		console.log("Please check reCaptcha"); // Provide better user experience in production
    		return false;
    	} else {
    		console.log("validated"); // Remove this in production
    		return true;
    	}
    }
    
    
    var onloadCallback = function() {
        setTimeout(function(){
    		grecaptcha.render('html_element', {
    	        'sitekey' : 'your_site_key'
            });
            // NOTE: I added a class of "dynamics-form" on the HTML so I could target it
            let form_element = document.querySelector('.dynamics-form'); 
            // Your button selector may vary
            let submit_button =  document.querySelector('.lp-form-button.lp-form-fieldInput');
            
            // Bind to button click and prevent default
            submit_button.addEventListener("click", function(event) {
    		    event.preventDefault();
    			let captcha_valid = validateRecaptcha();
    			if ( captcha_valid ) {
    				form_element.requestSubmit();
    			} else {
    			    // Show feedback requesting user input
    			}
    		}, true);
    	}, 3000);
    }; 

    EDIT: For those who are interested in something more robust - This adds a Google Recaptcha, and prevents submission unless it's valid, including programmatic submissions.
    Note that I gave the empty div that will hold the captcha an ID of "future_captcha" rather than "html_element" as Ron Peters did in step 2.


    ( function() { // Wrap everything in an IIFE as a good general practice.
    	/**
    	 * For the form that integrates with Microsoft Dynamics.
    	 *
    	 * Renders a Google Recaptcha to prevent the form from being submitted.
    	 */
    
    	/** @var {number} - Unique ID to prevent conflict between other instances of reCaptcha. */
    	let dynamicsCaptchaId;
    
    	/** @var {number} - ID to keep track of interval (Used to render form). */
    	let intervalId;
    
    	/** @var {number} - How many times the we've checked to see if form has rendered. */
    	let intervals = 0;
    
    	/** @constant {number} - How many times to try before showing error message. */
    	const MAX_ATTEMPTS = 10; // Attempt for ~5.5s
    
    	/** @var {Object} - Will hold Google Captcha / `grecaptcha`. */
    	let ourCaptcha;
    
    	/**
    	 * When everything is valid, attach a spinner to the button on submission
    	 * as the process may take a few seconds.
    	 */
    	function showLoading() {
    		const submitButton = document.querySelector( '.lp-form-button.lp-form-fieldInput' );
    		const spinner = document.createElement( 'div' );
    
    		spinner.classList.add( 'spinner' );
    		submitButton.innerHTML = 'Submitting... ';
    		submitButton.appendChild( spinner );
    		submitButton.classList.add( 'button--loading' );
    	}
    
    	/**
    	 * Show the user an error message if script doesn't initialze.
    	 * (Used when `intervals` exceeds `MAX_ATTEMPTS`)
    	 */
    	function renderFormError() {
    		let errorMsg = document.querySelector( '.d365-mkt-config' );
    		errorMsg.innerHTML = 'Something went wrong...'  
    		'
    The {newsletter signup / whatever (UPDATE TO YOUR CASE)} form is unavailable at this time, ' 'please try again later.
    We apologize for the inconvenience.'; const dynamicsFormId = '00x0000x-x000-xx00-0x00-00000000000x'; // <-- UPDATE TO YOUR ID. From the code embed. const dynamicsForm = document.querySelector( '[data-form-block-id="' dynamicsFormId '"]' ); if ( dynamicsForm !== null ) { // Remove the Dynamics parent form container on failure. dynamicsForm.parentNode.removeChild( dynamicsForm ); } errorMsg.style.border = '1px solid'; errorMsg.style.padding = '15px'; errorMsg.style.borderRadius = '5px'; errorMsg.style.display = 'block'; } /** * Check to see if captcha is validated. Add a message if the captcha is invalid. * * @param {Element} capElem - Rendered Captcha element. * @param {Element} captchaMsgEl -
    tag to show captcha status to the user. * @return {boolean} Captcha status. */ function validateRecaptcha( capElem, captchaMsgEl ) { // `dynamicsCaptchaId` & `ourCaptcha` is a global, set when the Captcha renders. const response = ourCaptcha.getResponse( dynamicsCaptchaId ); if ( response.length === 0 ) { captchaMsgEl.innerHTML = 'The reCAPTCHA was invalid. Please try checking the checkbox.'; capElem.classList.add( 'error-shake' ); // Shake the reCaptcha to get the user's attention. captchaMsgEl.classList.add( 'flash' ); // Small animation to show message. setTimeout( function() { // Remove animation classes so we can reanimate if needed. capElem.classList.remove( 'error-shake' ); captchaMsgEl.classList.remove( 'flash' ); }, 1000 ); return false; } // Otherwise, captcha is good. captchaMsgEl.innerHTML = ''; // Clear our error message (if set). return true; } /** * Attempt to submit the form if valid. * * @param {Event} evt - The event being fired. * @param {Element} formElement - element to be submitted. * @param {Element} capElem - Rendered Captcha element. * @param {Element} captchaMsgEl -
    tag to show captcha status to the user. */ function attemptFormSubmission( evt, formElement, capElem, captchaMsgEl ) { const formValid = formElement.reportValidity(); // Redundant / not technically required. const captchaValid = validateRecaptcha( capElem, captchaMsgEl ); if ( ! captchaValid || ! formValid ) { evt.preventDefault(); } else { formElement.requestSubmit(); // Redundant / not technically required. showLoading(); } } /** * Attach Event listeners to form. */ function prepareSubForm() { // Check to see if form ID is available in DOM. if ( ! document.getElementById( 'future_captcha' ) || ! window.hasOwnProperty( 'grecaptcha' ) ) { return; // Bail out - Form isn't ready yet. } clearInterval( intervalId ); // Clear interval since this code will now execute. ourCaptcha = window.grecaptcha; // Add Captcha to global (IIFE) scope. // Get a reference to Dynamics JS API. // See: https://docs.microsoft.com/en-us/dynamics365/marketing/developer/marketing-form-client-side-extensibility const DYNAMICSFORM = window.MsCrmMkt.MsCrmFormLoader; const captchaMsg = document.createElement( 'div' ); // Render the captcha and assign it an ID so we can validate without conflict. dynamicsCaptchaId = ourCaptcha.render( 'future_captcha', { sitekey: 'YOUR_SPECIAL_GOOGLE_RECAPTCHA_ID', // <-- REPLACE ME! callback() { captchaMsg.innerHTML = ''; // clear out error message if set. }, } ); const formElement = document.querySelector( '.dynamics-form' ); const populatedCaptcha = document.getElementById( 'future_captcha' ); captchaMsg.setAttribute( 'id', 'captcha-message' ); // Insert the captcha message holder after the rendered reCaptcha. populatedCaptcha.parentNode.insertBefore( captchaMsg, populatedCaptcha.nextSibling ); /** * By doing this vs. adding an event listener means we can intercept form submissions, * even those submitted programatically. * E.g. running `document.querySelector('.dynamics-form').requestSubmit();` from console. */ DYNAMICSFORM.on( 'formSubmit', function( evt ) { attemptFormSubmission( evt, formElement, populatedCaptcha, captchaMsg ); } ); /** * This isn't technically required. It's just to show the captcha error * a bit sooner rather than having all other elements valid excluding the * captcha to show. */ const submitButton = document.querySelector( '.lp-form-button.lp-form-fieldInput' ); submitButton.addEventListener( 'click', function( evt ) { attemptFormSubmission( evt, formElement, populatedCaptcha, captchaMsg ); }, true ); } /** * Callback for GoogleRecaptcha. * * Check DOM every 500ms, when ready clear interval and attach event handlers. */ window.onloadCallback = function() { intervalId = setInterval( function() { intervals ; if ( intervals > MAX_ATTEMPTS ) { clearInterval( intervalId ); renderFormError(); } else { prepareSubForm(); } }, 500 ); }; }() ); // END IIFE.


    Add the CSS:
    .error-shake {
    	animation-name: error-shake;
    	animation-duration: 0.5s;
    	animation-delay: 0.25s;
    }
    
    
    @keyframes flash {
    
    	from,
    	to {
    		opacity: 1;
    	}
    
    	50% {
    		opacity: 0.5;
    	}
    }
    
    .flash {
    	animation-name: flash;
    	animation-duration: 0.5s;
    }
    
    /* ANIMATION: ReCaptcha error shake. */
    @keyframes error-shake {
    
    	0% {
    		transform: translateX(0);
    		animation-timing-function: ease-in;
    	}
    
    	37% {
    		transform: translateX(5px);
    		animation-timing-function: ease-out;
    	}
    
    	55% {
    		transform: translateX(-5px);
    		animation-timing-function: ease-in;
    	}
    
    	73% {
    		transform: translateX(4px);
    		animation-timing-function: ease-out;
    	}
    
    	82% {
    		transform: translateX(-4px);
    		animation-timing-function: ease-in;
    	}
    
    	91% {
    		transform: translateX(2px);
    		animation-timing-function: ease-out;
    	}
    
    	96% {
    		transform: translateX(-2px);
    		animation-timing-function: ease-in;
    	}
    
    	100% {
    		transform: translateX(0);
    		animation-timing-function: ease-in;
    	}
    }
    
    .spinner {
    	position: relative;
    	display: inline-block;
    	width: 16px;
    	height: 16px;
    }
    
    button.lp-form-button.lp-form-fieldInput.button--loading {
    	background: transparent;
    	border: 1px solid;
    	color: #fff;
    }
    
    .spinner::after {
    	content: "";
    	position: absolute;
    	width: 16px;
    	height: 16px;
    	top: 0;
    	left: 0;
    	right: 0;
    	bottom: 0;
    	margin: auto;
    	border: 4px solid rgb(255 255 255 / 36%);
    	border-top-color: #fff;
    	border-radius: 50%;
    	animation: button-loading-spinner 1s ease infinite;
    }
    
    @keyframes button-loading-spinner {
    
    	from {
    		transform: rotate(0turn);
    	}
    
    	to {
    		transform: rotate(1turn);
    	}
    }

  • Jenni221 Profile Picture
    Jenni221 140 on at
    RE: Simplify or replace default CAPTCHA

    Do you have more information how you handled the answer of google recaptcha?

    Only make it possible to submit the form when google recaptcha was succesful?

    Thank you!

  • RonPeters Profile Picture
    RonPeters 90 on at
    RE: Simplify or replace default CAPTCHA

    D365 Marketing Forms offer CAPTCHA functionality. However, this may not be the best option to use if you’d like to implement CAPTCHA.

    pastedimage1567171651852v1.png

    Downsides of OOB CAPTCHA are:

    • Hard to read letters
    • Audio is hard to understand
    • I thought I typed the letters correctly, but it still wouldn’t accept it

    pastedimage1567171651853v2.png

    We’d like a CAPTCHA functionality that is easy to use, easy to understand and quick to complete

    Google reCAPTCHA is a good substitute as they have different options for CAPTCHA, it is easy to use, and it is free! You just need a google account to set up the site keys. The different options are:

    • reCAPTCHA v2 – checkbox
    • reCAPTCHA v2 – Invisible
    • reCAPTCHA v2 – Android
    • reCAPTCHA v3

    For this form, we decided to use reCAPTCHA v2 – checkbox. To add, follow the steps below:

    1. Setup your reCAPTCHA settings from Google reCAPTCHA Admin site. Save the site key as this will be needed in code.

    pastedimage1567171651853v3.png

    Also, add the website domain where you will be adding the reCAPTCHA element. Add this under the ‘Domains’ section on the admin site.

    2. On your D365 marketing form, add the below code where you want the CAPTCHA to appear.

    <div id="html_element"></div>

    Note that we do not add the javascript that renders the CAPTCHA into the marketing form. For some reason, the form blocks the reCAPTCHA scripts to function properly. We need to add the reCAPTCHA scripts where you would embed the form.

    For this example, we want the reCAPTCHA to appear before the Message input element and the Submit button.

    pastedimage1567171651859v4.png

    Code behind of this form is:

    pastedimage1567171651860v5.png

    3. Change the status of your form to ‘Go Live’. Then go to Form Hosting tab. First, add a new Form Page to generate the embed code for your form.

    pastedimage1567171651867v6.png

    Fill out the required fields. Once saved, the embed code will be auto generated.

    pastedimage1567171651871v7.png

    4. Next, make sure the website where you would embed the form is whitelisted. Add a new Form Whitelist record and enter the domain of the website on the Name field.

    pastedimage1567171651882v8.png

    5. On the web page where you would embed the D365 Marketing form, add the script below either within the head element (<head></head>) or before the embedded form. It is important to add this script before the embed form to ensure that the onloadCallback method has already been loaded before it gets called by another script. The script below has a timeout of 3 seconds before calling the function that would render the reCaptcha element. This is to ensure that the embedded form has already been loaded prior to calling the reCatpcha render method.

    <script type="text/javascript">
         
    var onloadCallback = function() {
            setTimeout(function(){grecaptcha.render(
    'html_element', {
             
    'sitekey' : 'your_site_key'
            });},3000);
          };

     
    </script>

    6. Still on the same html page, add this script below the D365 marketing form, or just before the closing body tag. This will load the google reCAPTCHA.

    <script src="">www.google.com/.../api.js async defer></script>

    For this example, the complete code that we would insert into the website is below:

    7. Reload the page where you’ve embedded the form with the reCaptcha element. It should show the D365 Marketing form with the reCaptcha tickbox as below.

  • Suggested answer
    megcda Profile Picture
    megcda 2,192 on at
    RE: Simplify or replace default CAPTCHA

    Hi Brad,

    This isn't available today in the product.  There is an item in the backlog to allow customization  I suggest that you visit the Dynamics 365 for Marketing Ideas portal and add this as a feature request.  Upvoting from the community can help to get this prioritized.

    Thanks,

    Megan

    Please mark as Verified if this answers your question!

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

November Spotlight Star - Khushbu Rajvi

Congratulations to a top community star!

Forum Structure Changes Coming on 11/8!

In our never-ending quest to help the Dynamics 365 Community members get answers faster …

Dynamics 365 Community Platform update – Oct 28

Welcome to the next edition of the Community Platform Update. This is a status …

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 292,516 Super User 2025 Season 1

#2
Martin Dráb Profile Picture

Martin Dráb 231,432 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Featured topics

Product updates

Dynamics 365 release plans