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.

Pay me a coffee

Want to say thanks? Pay me a coffee! Remember, I turn coffee into code.

  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?

Leave a Reply

Your email address will not be published. Required fields are marked *

email
Up Next:

How to send an email with AMPscript

How to send an email with AMPscript