How to create a Form Handler and avoid Smart Capture

How to create a Form Handler and avoid Smart Capture

A Form Handler is a web page which sole purpose is to process the data sent from a web form and redirect back or to another page.

This technique allows us to avoid the flawed Smart Capture feature and grants the freedom to create any kind of forms and make them do various actions including creating multiple records and triggered emails.

How it works

  1. Web Form page sends a field value (Name) to the Form Handler page.
  2. Form Handler redirects back to the Web Form page with Name and Success parameters encoded in the URL.
  3. Web Form displays a success message due to the presence of Success parameter in the URL.

Now, let’s build it!

Web Form

For the purpose of this exercise the form is kept as simple as possible.

<form action="%%=CloudPagesURL(1977)=%%" method="post" class="form centered">
	<input name="Name" type="text" placeholder="Your name" required>
	<button>Send</button>
</form>

1977 is the Page ID of the Form Handler page.

Note that using CloudPagesURL method for generating the URLs is highly recommended as it automatically encodes the URL parameters.

Instead of creating a success page, we are going to replace the form by a success message if a parameter is present in the URL (in this case, the Form Handler is sending Success and Name parameters).

%%[
    
    VAR @Name

    SET @Name = RequestParameter("Name")
    SET @Success = RequestParameter("Success")
    
    IF @Success != 1 THEN
    
]%%

<form action="%%=CloudPagesURL(1977)=%%" method="post" class="form centered">
	<input name="Name" type="text" placeholder="Your name" required>
	<button>Send</button>
</form>

%%[ ELSE ]%%

<div>
	<p>Thank you %%=v(@Name)=%%!</p>
</div>

%%[ ENDIF ]%%

And for the finishing touches, let’s add some styling and Javascript validation rules to make the form more appealing and foolproof.

<!DOCTYPE html>
<html>
<head>
    <title>Form</title>
    <style>
        * {
            box-sizing: border-box;
            font-family: sans-serif;
        }
        body {
            background-color: #F4F6F9;
        }
        form,
        div {
            border-radius: 8px;
            padding: 20px;
            border: 1px solid #D8DDE6;
            color: #16325c;
            background-color: #fff;
            font-size: 16px;
            width: 340px;
            position: absolute;
            margin-left: calc(-340px / 2);
            margin-top: calc(-136px / 2);
            left: 50%;
            top: 50%;
            text-align: center;
        }
        input, button {
            line-height: 100%;
            border-radius: 4px;
            height: 42px;
        }
        input {
            width: 100%;
            border: 1px solid #d8dde6;
            padding: 0 14px;
            font-size: 14px;
        }
        button {
            border: 0;
            margin: 0;
            display: block;
            width: 100%;
            margin-top: 10px;
            background-color: #215ca0;
            text-transform: uppercase;
            color: white;
            padding: 0 24px;
            font-size: 14px;
            cursor: pointer;
        }
    </style>
</head>
<body>

    <form action="%%=CloudPagesURL(1977)=%%" method="post" class="form centered">
        <input name="Name" type="text" placeholder="Your name" required>
        <button>Send</button>
    </form>

    <script>
        var form = document.querySelector('.form');
        if (!!form) {
            form.addEventListener("submit",function(e){
                e.preventDefault();
                if(this.checkValidity()) {
                    this.submit();
                }
            });
        } 
    </script>

</body>
</html>

Form Handler

Our goal is to capture the data sent from the Web Form and redirect back to the origin page with a couple of parameters that would allow us to replace the form with a success message.

<!DOCTYPE html>
<html>
<body>
%%[

	VAR @Name    
	SET @Name = RequestParameter("Name")

	IF NOT EMPTY(@Name) THEN
		Redirect(CONCAT(CloudPagesURL(1970,'Success',1,'Name',@Name)))
	ENDIF

]%%
</body>

1970 is the Page ID of the Web Form page.

Now, it is important to add the security measures, so no other domain or bots could send data to our Form Handler.

<!DOCTYPE html>
<html>
<head>
  <meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
</head>
<body>
%%[
    SET @origin = HTTPRequestHeader("Referer")
    SET @pattern = "^(https:\/\/(.*\.)?((example)\.com))($|\/)"
    SET @match = RegExMatch(@origin, @pattern, 1)
]%%
<script runat=server>
    Platform.Load("core","1");
    var MATCH = Variable.GetValue("@match");
    if (!MATCH) { MATCH = null }
    HTTPHeader.SetValue("Access-Control-Allow-Methods","POST");
    HTTPHeader.SetValue("Access-Control-Allow-Origin",MATCH);
    Platform.Response.SetResponseHeader("Strict-Transport-Security","max-age=200"); 
	Platform.Response.SetResponseHeader("X-XSS-Protection","1; mode=block"); 
	Platform.Response.SetResponseHeader("X-Frame-Options","Deny"); 
	Platform.Response.SetResponseHeader("X-Content-Type-Options","nosniff"); 
	Platform.Response.SetResponseHeader("Referrer-Policy","strict-origin-when-cross-origin"); 
	Platform.Response.SetResponseHeader("Content-Security-Policy","default-src 'self'");
</script>
%%[

VAR @Name    

IF LENGTH(@match) > 0 THEN  

    SET @Name = RequestParameter("Name")

    IF NOT EMPTY(@Name) THEN
        Redirect(CONCAT(CloudPagesURL(1970,'Success',1,'Name',@Name)))
    ENDIF

ENDIF

]%%

</body>

That’s it!

Nothing more, nothing less.

You can obviously enhance your Form Handler to write in the Data Extensions, send Emails, retrieve data from SalesForce and so on.

Final code

<!DOCTYPE html>
<html>
<head>
    <title>Form</title>
    <style>
        * {
            box-sizing: border-box;
            font-family: sans-serif;
        }
        body {
            background-color: #F4F6F9;
        }
        form,
        div {
            border-radius: 8px;
            padding: 20px;
            border: 1px solid #D8DDE6;
            color: #16325c;
            background-color: #fff;
            font-size: 16px;
            width: 340px;
            position: absolute;
            margin-left: calc(-340px / 2);
            margin-top: calc(-136px / 2);
            left: 50%;
            top: 50%;
            text-align: center;
        }
        input, button {
            line-height: 100%;
            border-radius: 4px;
            height: 42px;
        }
        input {
            width: 100%;
            border: 1px solid #d8dde6;
            padding: 0 14px;
            font-size: 14px;
        }
        button {
            border: 0;
            margin: 0;
            display: block;
            width: 100%;
            margin-top: 10px;
            background-color: #215ca0;
            text-transform: uppercase;
            color: white;
            padding: 0 24px;
            font-size: 14px;
            cursor: pointer;
        }
    </style>
</head>
<body>

    %%[
    
    VAR @Name

    SET @Name = RequestParameter("Name")
    SET @Success = RequestParameter("Success")
    
    IF @Success != 1 THEN
    
    ]%%

    <form action="%%=CloudPagesURL(1977)=%%" method="post" class="form centered">
        <input name="Name" type="text" placeholder="Your name" required>
        <button>Send</button>
    </form>

    %%[ ELSE ]%%

        <div>
            <p>Thank you %%=v(@Name)=%%!</p>
        </div>

    %%[ ENDIF ]%%

    <script>

        var form = document.querySelector('.form');
        
        if (!!form) {

            form.addEventListener("submit",function(e){

                e.preventDefault();

                if(this.checkValidity()) {

                    this.submit();

                }


            });

        } 
    
    </script>

</body>
</html>
<!DOCTYPE html>
<html>
<head>
  <meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
</head>
<body>
%%[
    SET @origin = HTTPRequestHeader("Referer")
    SET @pattern = "^(https:\/\/(.*\.)?((example)\.com))($|\/)"
    SET @match = RegExMatch(@origin, @pattern, 1)
]%%
<script runat=server>
    Platform.Load("core","1");
    var MATCH = Variable.GetValue("@match");
    if (!MATCH) { MATCH = null }
    HTTPHeader.SetValue("Access-Control-Allow-Methods","POST");
    HTTPHeader.SetValue("Access-Control-Allow-Origin",MATCH);
    Platform.Response.SetResponseHeader("Strict-Transport-Security","max-age=200"); 
	Platform.Response.SetResponseHeader("X-XSS-Protection","1; mode=block"); 
	Platform.Response.SetResponseHeader("X-Frame-Options","Deny"); 
	Platform.Response.SetResponseHeader("X-Content-Type-Options","nosniff"); 
	Platform.Response.SetResponseHeader("Referrer-Policy","strict-origin-when-cross-origin"); 
	Platform.Response.SetResponseHeader("Content-Security-Policy","default-src 'self'");
</script>
%%[

VAR @Name    

IF LENGTH(@match) > 0 THEN  

    SET @Name = RequestParameter("Name")

    IF NOT EMPTY(@Name) THEN

        Redirect(CONCAT(CloudPagesURL(1970,'Success',1,'Name',@Name)))

    ENDIF

ENDIF

]%%

</body>

Have I missed anything?

Please poke me with a sharp comment below or use the contact form.

  1. Thank you for this!

    Just to clarify – the actual form is hosted on the website (e.g. WordPress), and the form handler is actually a Cloudpage?

  2. I tried copying the code into SFMC cloud pages (create landing page > classic editor, one page for form and one for handler). The only change I made to code is changing Page IDs, but on both pages I get the error “500 – Internal server error. There is a problem with the resource you are looking for, and it cannot be displayed.”
    Am I doing something wrong?

  3. It seems to me that the IDs you are giving are incorrect. Where do you get them from? They should be from the same Business Unit as the page.

  4. I did have the wrong page ID in the form page code. I fixed it and form page displays and submits, but I am still getting 500 error for handler page. I get page ID from each landing page details info. Both pages are in the same business unit.
    (I did add to bottom of handler page even though it wasn’t in the code example)

  5. Could you please tell me what exactly did you add to the code of Form Handler?

    Note that, if you don’t use CONCAT in REDIRECT function, it will give Error 500.

  6. Also, did you modify the REGEX at the top? This one: “^(https:\/\/(.*\.)?((example)\.com))($|\/)”

    Instead of example.com it should be the domain you are using for Marketing Cloud.

  7. Hi Ivan,

    Thanks for the tutorial.

    Do I create a cloud pages for the handler ? I tried that but it does not allows me to publish the page handler.

    Appreciate your help.

  8. Ivan,

    Looks like this failed and stopping me from publishing the form handler.

    HTTPHeader.SetValue(“Access-Control-Allow-Origin”, MATCH);

  9. Hi Ivan!

    Nice tutorial! Congratulations!

    I have a little problem with a implementation that I did. I created a form and a form handler, used my form handler as an action for form, and it worked, but after submission always pops up a error message from MC that says something like “Unable to send data. Please try again”. Perhaps all the processes of the form handler works perfectly. Could you help me fix this problem?

    Tks

  10. Dennis, could you please give me the exact error message and tell me where do you see this error message in MC?

  11. The message is: “pub.s4.exacttarget.com says: Unable to send your data. Please, try again”

    Apears a pop up message with this text after click in submission button

  12. Seems like a JavaScript error that appears using “alert”.

  13. Hello Ivan,
    I am having an issue implementing the code as well. It is giving me a 500 Error every time I try to view the form handler after publishing.

  14. That’s normal, the form handler is not for viewing. Did you change the id of the page in CloudPagesUrl function?

Comments are closed.

email
Up Next:

How to send an email with AMPscript

How to send an email with AMPscript