Multi-cloud preference center in SF marketing cloud

in  Marketing Automation, Salesforce Marketing Cloud
5 minutes read

With majority of the implementations the out of the box center is not sufficient for the client and we are tasked to build custom preference center for them. We can assume that the preference center is only applicable for known subscribers most likely coming from email communication. 

When we send email in salesforce marketing cloud, it automatically attaches personalization strings to every link in a safe way, so the link will not expose any private data. If you generate such link in email preview it will work only on subscribers we already sent some communication.

<a alias="click here" conversion="false" href="%%=redirectto(CloudPagesURL(253)=%%">Unsubscribe</a>

Link is leading to the cloud page under key 253. Here we can see that no additional information is need to pass on as marketing cloud is adding all necessary information we need to identify subscribers on the cloud pages. In case anything has to be added you can in form of additional arguments all query parameters will be encrypted by marketing cloud when email is sent.

CloudPagesURL(253, "param1",@param1Value,"param2",@param2value)

Subscriber lands on the cloud page from the email click. We can directly access his _subscriberkey.

Define redirect page, error page on the top along with the request parameter that we will explain later. We also can use IP address of visitor for any purposes that client requires.

<script runat="server">
    Platform.Load("core","1.1.1");
    Variable.SetValue('@ip', Platform.Request.ClientIP);
    Variable.SetValue('@request', Platform.Request.Method);
</script>
SET @errorPage = 222
SET @redirectPage = 223

If we do not have _subscriberkey we simply can tell somebody accessed the page accidentally and  navigate them to the error page.

%%[ IF EMPY(_subscriberkey) THEN Redirect(CloudPagesURL(@errorPage)) ENDIF ]%%

Next we add section to collect data from form submissions

SET @submit = RequestParameter("submit")
SET @field1 = RequestParameter("field1")
SET @field2 = RequestParameter("field2")
SET @field3 = RequestParameter("field3")
SET @field4 = RequestParameter("field4")

We also want to display data on the form that are perhaps loaded directly from sales cloud. To do that we would need to get account from contact id from either the salesforce tables or you can create one data extension that holds all the data from account and contact in one row. We will use one data extension that contain row where we can see account id and contact id. We will populate form data after we process the when someone submits the form.

SET @accountId = Lookup("MASTER_TABLE", "AccountId", "ContactId", _subscriberkey)

Check in service cloud the account by the account id we got from the mapping data extension above.

SET @accounts = RetrieveSalesforceObjects("Account", "Salutation, FirstName, LastName, PersonBirthdate, PersonEmail, NLBranch__pc", "Id", "=", @accountId)

Now we want to process data only when the form has been submitted via the POST request. Now it is time to reuse above mentioned variable @request

%%[
  
  IF NOT EMPTY(@submit) AND @request == "POST" THEN 
     /*Check if _subscriberkey has match in the sales cloud*/
     IF RowCount(@accounts) THEN
        SET @account = Row(@accounts, 1)
        /* bring any fields from SC that you may need */
        SET @field1 =  Field(@account, "field1")
    ELSE
        /*redirect to error error page */
        Redirect(CloudPagesURL(@errorPage)
    ENDIF
                 
]%%

In case of error we can also do not want to show customer 500 page but instead we want to handle any error that may happen during the update object in sales cloud. For example we can redirect customer to the same  to the same page showing a banner at the top of the page or redirect them to our own custom error page that displays contact for support.

/*try catch block so sales cloud will not suprise customer with 500 */
<script runat="server">
  try{
</script>
 %%[
  /*now the main program of todays event is to update sales cloud :) */
   UpdateSingleSalesforceObject("Account", @accountId, "Field1", @field1, "Field2", @field2, "Field3", @field3, "Field4", @field4)
]%%
 <script runat="server">
  catch(e){
   /*Load core library as the functions are no vosible in this ode block*/
   Platform.Load("core","1.1.1");
   Variable.SetValue("@error","True") /*maybe try with boolean but for me it did not work at the first time*/
   
  }
</script>
               
          
%%[
  
IF @error == "True" THEN  Redirect(CloudPagesURL(@errorPage) ENDIF 

*/
  
ENDIF ]%%

Sometimes may happen that customer will remove data from form this may cause issues when saving the field as you cannot save null values to sales cloud. Instead we need to append additional arguments to the UpdateSingleSalesforceObject()

UpdateSingleSalesforceObject("Account", @accountId, "Field1", @field1, "Field2", @field2, "Field3", @field3, "Field4", @field4,"fieldsToNull", "field3")

Problem here is you can only null one field at a time. You will need to send as many update calls with all the empty fields that were set to the form. Maybe if you have to set null 10 fields is better to select another approach. As to do 10 calls to null fields and then 1 call to update object might be sometimes very resource consuming and customer could wait couple seconds for page to process. You can share in comments your thoughts.

Also for future enhancements we might think of adding field values validation.

Also you might ask yourself why we do not update marketing cloud data extension. It is because updates in sales cloud will be synchronized back to marketing cloud from where automation is set to update our MASTER_TABLE data extension and set to run every hour

In case we want to redirect customers to the same page we can add some additional information to the URL so we tell the cloud page to display specific message to the customer

/* we can also redirect to the same page and show banner at the top of the page */

Redirect(CloudPagesURL(@self,"m", "e")) 

Define the alert message based on the query parameter we used in redirect. Do not worry it is all encrypted in the URL bar, nobody will fiddle with that. (hope). 

SET @m = RequestParameter("m")
IF NOT EMPTY(@m) THEN
    IF @m == "s" THEN
        SET @alertMessage = "Data saved successfully!"
        SET @alertType = "success"
    ELSEIF @m == "e" THEN
        SET @alertMessage = "Oops something happened. Please try again later."
        SET @alertType = "danger"
    ENDIF
ENDIF

Display the alert banner on page. I do use bootstrap as CSS library.

%%[ IF NOT EMPTY(@alertType) THEN ]%%
   <div class="alert alert-%%=v(@alertType)=%% my-4" role="alert">
       %%=v(@alertMessage)=%%
   </div>
%%[ENDIF]%%

Last but not least we need to add form and possibly prepopulate it with the data coming from sales cloud. It is good to add as many field validations already in html (and JavaScript) so we can stop customer submit invalid fields already on client side and also on the back end side to have second layer of validation as more is better. Because when eg. you will submit field that is out of the limits in sales cloud or another type we will get infamous 500 back

<form action="%%=RequestParameter("PAGEURL")=%%" method="POST">
  <input type="text" name="field1" maxlength="40"  value="%%=v(@field1)=%%" />
  <input type="date" name="field2" format="...."  value="%%=v(@field2)=%%" />
   <input type="submit" name="submit"/>
</form>
in  Adobe Campaign, Marketing Automation

Adobe campaign all about the schemas and more

4 minutes read

I want to gather as much information I have and have it at one place for my future reference and for others to learn what can be possible with the custom schemas. If you work with adobe campaign for some time you might figured out that almost any client’s sane or insane requirement can be […]

Continue reading
in  Marketing Automation, Salesforce Marketing Cloud, SFMC Tips & Tricks

SMFC TIP – Form submission handling

1 minute read

On many occasions when handling any form submission single cloud page application is used. This is great as all of error handling, form submission and processing is on one page so it is actually simpler to implement. But here are some thing you need to take into consideration. Handle GET form submissions I have seen […]

Continue reading