Revolutionizing Distributed Marketing: Custom App Solutions for Seamless Data Extension Creation in Salesforce Marketing Cloud

Revolutionizing Distributed Marketing: Custom App Solutions for Seamless Data Extension Creation in Salesforce Marketing Cloud
Home Page

Revolutionizing Distributed Marketing: Custom App Solutions for Seamless Data Extension Creation in Salesforce Marketing Cloud

Introduction:

In the dynamic realm of Distributed Marketing, the ability to create and manage template-based data extensions efficiently is paramount. These extensions serve as the foundation for personalized campaigns, ensuring brand consistency while empowering local marketers with the autonomy to tailor their messages to specific audiences. However, the process of creating these data extensions can often be cumbersome and prone to errors without the right tools in place. In this blog post, we'll explore how custom app solutions within Salesforce Marketing Cloud (SFMC) can streamline the creation of template-based data extensions for Distributed Marketing, enabling organizations to enhance their campaign effectiveness and drive meaningful engagement.

Challenges in Data Extension Creation for Distributed Marketing:

Traditionally, marketers tasked with creating template-based data extensions for Distributed Marketing campaigns have had to navigate through SFMC's native interfaces, which may lack the flexibility and user-friendliness required for efficient data modeling. This process often involves manually defining fields, setting up relationships, and configuring various properties, leading to potential inconsistencies and delays in campaign execution. Additionally, ensuring adherence to corporate branding guidelines and data governance policies further complicates the data extension creation process.

Name FieldType MaxLength IsRequired
greeting Text 255
id Text 254 true
email EmailAddress true
sfCampaignId Text 255
sfCampaignMemberId Text 255
sfQuickSendId Text 255
sendFromName Text 255
sendFromEmail Text 255
firstName Text 50
lastName Text 50
sfUserId Text 255 true
mobilePhone Phone
journeyID Text 50 true
sfOrgId Text 50 true
smsValue Text 160
EntryObjectId Text 255

Custom App Solutions: Empowering Marketers with Efficiency and Control:

  1. Streamlined User Interface:

    Custom CloudPages provide marketers with user-friendly interfaces that simplify the process of defining data extension attributes and configurations. Interactive forms and guided workflows streamline the data modeling process, allowing marketers to specify field types, relationships, and other properties effortlessly. Real-time validation and feedback mechanisms help prevent errors and ensure data integrity, reducing the need for manual corrections and troubleshooting.

    HTML Form

                                
    <form id="data-extension-form" action="%%=RequestParameter('PAGEURL')=%%" method="post">
            <div class="form-group">
              <label for="dataExtensionName">Data Extension Name</label>
              <input type="text" id="dataExtensionName" name="dataExtensionName" required>
            </div>
            <div class="form-group">
              <label for="folderName">Folder Name</label>
              <input type="text" id="folderName" name="folderName" required>
            </div>
            <div class="form-group">
              <input type="submit" value="Create Data Extension">
            </div>
    </form>                              
                                
                            

    Client Side Scripting

                                
    <script>
          document.getElementById('data-extension-form').addEventListener('submit',consentSubmit);
          function consentSubmit(e){
            try{
              e.preventDefault();
              var formData=new FormData(document.getElementById('data-extension-form'));
              var xhr = new XMLHttpRequest();
              xhr.open('POST', 'https://cloud.domain/distributedMarketing', true);
              xhr.onload = () => {
                if (xhr.readyState === xhr.DONE) {
                  if (xhr.status === 200) {
                    // Check against the numeric status code
                    console.log(xhr.response);
                    console.log(xhr.responseText);
                    // Reset the form fields after successful submission
                    document.getElementById('data-extension-form').reset();
                    document.getElementById('success-message').style.display = 'block';
                    // Hide the success message after 3 seconds (3000 milliseconds)
                    setTimeout(hideSuccessMessage, 3000);
                  }
                }
              };
              xhr.onerror = function(){
                console.log("** An error occurred during the submission");
              }
              xhr.send(formData);
            }
            catch(ex)
            {
              alert(ex.message);
            }
          }
          function hideSuccessMessage() {
            document.getElementById('success-message').style.display = 'none';
          }
    </script>
                                
                            

    Full HTML

    
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Create Distributed Marketing Data Extension
        </title>
        <link rel="stylesheet"
              href="https://cdnjs.cloudflare.com/ajax/libs/lightning-design-system/2.14.4/styles/salesforce-lightning-design-system.min.css">
        <style>
          body {
            font-family: 'Arial', sans-serif;
            background-color: #f4f6f9;
          }
          .container {
            max-width: 500px;
            margin: 50px auto;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
            background-color: #ffffff;
            position: relative;
            /* Required for logo positioning */
          }
          .title {
            text-align: center;
            font-size: 24px;
            margin-bottom: 20px;
            color: #333333;
          }
          .form-group {
            margin-bottom: 20px;
          }
          label {
            font-weight: bold;
            display: block;
            margin-bottom: 5px;
            color: #666666;
          }
          input[type="text"],
          select {
            width: calc(100% - 12px);
            padding: 10px;
            border: 1px solid #cccccc;
            border-radius: 5px;
            box-sizing: border-box;
            font-size: 16px;
          }
          select {
            cursor: pointer;
          }
          input[type="submit"] {
            background-color: #0070d2;
            color: #ffffff;
            padding: 12px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            transition: background-color 0.3s;
            width: 100%;
            display: block;
          }
          input[type="submit"]:hover {
            background-color: #005fb2;
          }
          .logo {
            position: absolute;
            top: 10px;
            left: 10px;
            width: 150px;
            height: auto;
          }
          .success-message {
            background-color: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
            border-radius: 5px;
            padding: 10px;
            margin-top: 20px;
            display: none;
          }
        </style>
      </head>
      <body>
        <div class="container">
          <img class="logo" src="https://www.salesforce.com/news/wp-content/uploads/sites/3/2021/05/Salesforce-logo.jpg"
               alt="Salesforce Logo">
          <h2 class="title">Create Distributed Marketing Data Extension
          </h2>
          <form id="data-extension-form" action="%%=RequestParameter('PAGEURL')=%%" method="post">
            <div class="form-group">
              <label for="dataExtensionName">Data Extension Name</label>
              <input type="text" id="dataExtensionName" name="dataExtensionName" required>
            </div>
            <div class="form-group">
              <label for="folderName">Folder Name</label>
              <input type="text" id="folderName" name="folderName" required>
            </div>
            <div class="form-group">
              <input type="submit" value="Create Data Extension">
            </div>
          </form>
          <div class="success-message" id="success-message">
            Data Extension created successfully!
          </div>
        </div>
        <script>
          document.getElementById('data-extension-form').addEventListener('submit',consentSubmit);
          function consentSubmit(e){
            try{
              e.preventDefault();
              var formData=new FormData(document.getElementById('data-extension-form'));
              var xhr = new XMLHttpRequest();
              xhr.open('POST', 'https://cloud.domain/distributedMarketing', true);
              xhr.onload = () => {
                if (xhr.readyState === xhr.DONE) {
                  if (xhr.status === 200) {
                    // Check against the numeric status code
                    console.log(xhr.response);
                    console.log(xhr.responseText);
                    // Reset the form fields after successful submission
                    document.getElementById('data-extension-form').reset();
                    document.getElementById('success-message').style.display = 'block';
                    // Hide the success message after 3 seconds (3000 milliseconds)
                    setTimeout(hideSuccessMessage, 3000);
                  }
                }
              };
              xhr.onerror = function(){
                console.log("** An error occurred during the submission");
              }
              xhr.send(formData);
            }
            catch(ex)
            {
              alert(ex.message);
            }
          }
          function hideSuccessMessage() {
            document.getElementById('success-message').style.display = 'none';
          }
        </script>
      </body>
    </html>
                            
  2. Automated Backend Logic:

    Leveraging Code Resources, organizations can automate the creation of template-based data extensions using predefined configurations and best practices. Custom logic orchestrates the generation of data extensions based on user input, automating tasks such as field creation, primary key assignment, and relationship establishment. Error handling and validation routines detect and resolve issues proactively, minimizing disruptions and ensuring consistent data extension structures across campaigns.

    Request Parameters capture

                                    
    %%[
    /*-----Start Initialize the variables----------------*/
    set @folderName=RequestParameter('folderName')
    set @dataExtensionName=RequestParameter('dataExtensionName')
    /*---------------------End-----------------------------*/
    ]%%
                                    
                                

    Folder ID Retrieve

                                    
    // Function to retrieve folder ID by name
        function RetrieveFolderID(folderName) {
            var filter = {
                Property: "Name",
                SimpleOperator: "equals",
                Value: folderName
            };
            var results = Folder.Retrieve(filter);
            return results[0].ID; // Return the ID of the first folder found
        }
                                    
                                

    Folder Creation

    
    
        // Function to create a Data Extension folder
        function createDataExtensionFolder(api, folderName) {
            // Retrieve parent folder ID
            var req = api.retrieve("DataFolder", ["ID"], {
                Property: "Name",
                SimpleOperator: "equals",
                Value: "Data Extensions"
            });
    
            var parentFolderId = req.Results[0].ID;
    
            // Define folder configuration
            var config = {
                "Name": folderName,
                "Description": "API Created Folder",
                "ParentFolder": {
                    ID: parentFolderId,
                    IDSpecified: true
                },
                "IsActive": true,
                "IsEditable": true,
                "AllowChildren": true,
                "ContentType": "dataextension"
            };
    
            // Create the folder and return the result
            var result = api.createItem("DataFolder", config);
            return result;
        }
                                

    Data Extension Creation

    
        // Function to create a Data Extension
        function createDataExtension(api, dataExtensionName, folderId) {
            // Set the client ID
            api.setClientId({ "ID": Platform.Function.AuthenticatedMemberID() });
    
            // Define Data Extension configuration
            var config = {
                "CustomerKey": dataExtensionName,
                "Name": dataExtensionName,
                "CategoryID": folderId,
                "Fields": [
                    // Define Data Extension fields
                    { "Name": "greeting", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "id", "FieldType": "Text", "MaxLength": 254, "IsRequired": true },
                    { "Name": "email", "FieldType": "EmailAddress", "IsRequired": true },
                    { "Name": "sfCampaignId", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "sfCampaignMemberId", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "sfQuickSendId", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "sendFromName", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "sendFromEmail", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "firstName", "FieldType": "Text", "MaxLength": 50 },
                    { "Name": "lastName", "FieldType": "Text", "MaxLength": 50 },
                    { "Name": "sfUserId", "FieldType": "Text", "MaxLength": 255, "IsRequired": true },
                    { "Name": "mobilePhone", "FieldType": "Phone" },
                    { "Name": "journeyID", "FieldType": "Text", "MaxLength": 50, "IsRequired": true },
                    { "Name": "sfOrgId", "FieldType": "Text", "MaxLength": 50, "IsRequired": true },
                    { "Name": "smsValue", "FieldType": "Text", "MaxLength": 160 },
                    { "Name": "EntryObjectId", "FieldType": "Text", "MaxLength": 255 }
                ],
                // Data retention settings
                "DataRetentionPeriodLength": 105,
                "RowBasedRetention": false,
                "ResetRetentionPeriodOnImport": true,
                "DeleteAtEndOfRetentionPeriod": false,
                "DataRetentionPeriod": "Weeks",
                "SendableDataExtensionField": {
                    "Name": "id",
                    "FieldType": "Text"
                },
                "SendableSubscriberField": {
                    "Name": "Subscriber Key"
                },
                "IsSendable": true,
                "IsTestable": true
            };
    
            // Create the Data Extension and return the result
            var result = api.createItem("DataExtension", config);
            return result;
        };                                
                                

    Full JSON Code Reosuce

    
    %%[
    /*-----Start Initialize the variables----------------*/
    set @folderName=RequestParameter('folderName')
    set @dataExtensionName=RequestParameter('dataExtensionName')
    /*---------------------End-----------------------------*/
    ]%%
    
    <script runat="server">
        // Load necessary libraries
        Platform.Load("core", "1");
    
        try {
            // Instantiate WSProxy object
            var api = new Script.Util.WSProxy();
    
            // Get folder and data extension names
            var folderName = Variable.GetValue("@folderName") || "Test";
            var dataExtensionName = Variable.GetValue("@dataExtensionName") || "Test";
    
            // Retrieve folder ID or create a new one if not found
            var folderId = RetrieveFolderID(folderName);
            var result;
            if (!folderId) {
                result = createDataExtensionFolder(api, folderName);
                folderId = RetrieveFolderID(folderName);
                result = createDataExtension(api, dataExtensionName, folderId);
            } else {
                result = createDataExtension(api, dataExtensionName, folderId);
            }
           
            Variable.SetValue("@status",result.Status);
            Variable.SetValue("@ErrorCode","000");
            Variable.SetValue("@StatusMessage","Success");
        } catch (ex) {
            // Catch and log any errors that occur
            var APIExceptionDE = DataExtension.Init("APIException");
            APIExceptionDE.Rows.Add({
                Message: ex.message,
                Description: ex.description,
                InnerException: ex.jintException,
                FunctionName: "DataExtensionRowsRetrieve"
            });
            Variable.SetValue("@status","Error");
            Variable.SetValue("@ErrorCode","000");
            Variable.SetValue("@StatusMessage",ex.message);
        }
    
        // Function to retrieve folder ID by name
        function RetrieveFolderID(folderName) {
            var filter = {
                Property: "Name",
                SimpleOperator: "equals",
                Value: folderName
            };
            var results = Folder.Retrieve(filter);
            return results[0].ID; // Return the ID of the first folder found
        }
    
        // Function to create a Data Extension
        function createDataExtension(api, dataExtensionName, folderId) {
            // Set the client ID
            api.setClientId({ "ID": Platform.Function.AuthenticatedMemberID() });
    
            // Define Data Extension configuration
            var config = {
                "CustomerKey": dataExtensionName,
                "Name": dataExtensionName,
                "CategoryID": folderId,
                "Fields": [
                    // Define Data Extension fields
                    { "Name": "greeting", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "id", "FieldType": "Text", "MaxLength": 254, "IsRequired": true },
                    { "Name": "email", "FieldType": "EmailAddress", "IsRequired": true },
                    { "Name": "sfCampaignId", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "sfCampaignMemberId", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "sfQuickSendId", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "sendFromName", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "sendFromEmail", "FieldType": "Text", "MaxLength": 255 },
                    { "Name": "firstName", "FieldType": "Text", "MaxLength": 50 },
                    { "Name": "lastName", "FieldType": "Text", "MaxLength": 50 },
                    { "Name": "sfUserId", "FieldType": "Text", "MaxLength": 255, "IsRequired": true },
                    { "Name": "mobilePhone", "FieldType": "Phone" },
                    { "Name": "journeyID", "FieldType": "Text", "MaxLength": 50, "IsRequired": true },
                    { "Name": "sfOrgId", "FieldType": "Text", "MaxLength": 50, "IsRequired": true },
                    { "Name": "smsValue", "FieldType": "Text", "MaxLength": 160 },
                    { "Name": "EntryObjectId", "FieldType": "Text", "MaxLength": 255 }
                ],
                // Data retention settings
                "DataRetentionPeriodLength": 105,
                "RowBasedRetention": false,
                "ResetRetentionPeriodOnImport": true,
                "DeleteAtEndOfRetentionPeriod": false,
                "DataRetentionPeriod": "Weeks",
                "SendableDataExtensionField": {
                    "Name": "id",
                    "FieldType": "Text"
                },
                "SendableSubscriberField": {
                    "Name": "Subscriber Key"
                },
                "IsSendable": true,
                "IsTestable": true
            };
    
            // Create the Data Extension and return the result
            var result = api.createItem("DataExtension", config);
            return result;
        };
    
        // Function to retrieve Data Extension by external key
        function RetrieveDataExtension(externalKey) {
            var api = new Script.Util.WSProxy();
            var req = api.retrieve("DataExtension", ["ObjectID"], {
                Property: "DataExtension.CustomerKey",
                SimpleOperator: "equals",
                Value: externalKey
            });
            return req.Results[0].ObjectID;
        }
    
        // Function to create a Data Extension folder
        function createDataExtensionFolder(api, folderName) {
            // Retrieve parent folder ID
            var req = api.retrieve("DataFolder", ["ID"], {
                Property: "Name",
                SimpleOperator: "equals",
                Value: "Data Extensions"
            });
    
            var parentFolderId = req.Results[0].ID;
    
            // Define folder configuration
            var config = {
                "Name": folderName,
                "Description": "API Created Folder",
                "ParentFolder": {
                    ID: parentFolderId,
                    IDSpecified: true
                },
                "IsActive": true,
                "IsEditable": true,
                "AllowChildren": true,
                "ContentType": "dataextension"
            };
    
            // Create the folder and return the result
            var result = api.createItem("DataFolder", config);
            return result;
        }
    </script>
    {
        "status": "%%=v(@status)=%%",
        "ErrorCode": "%%=v(@ErrorCode)=%%",
        "StatusMessage": "%%=v(@StatusMessage)=%%"
    }                                
                                
  3. Integration with Corporate Guidelines:

    Custom app solutions can be designed to enforce corporate branding guidelines and data governance policies during the data extension creation process. Built-in validation rules and compliance checks ensure that data extensions adhere to predefined standards, mitigating the risk of non-compliance and brand dilution.

  4. Grant User Access to the Custom App through the Install Package

    After configuring the custom app using the install package, the next crucial step is to provide access to designated users or business units within your organization. Access control ensures that only authorized individuals can utilize the functionalities offered by the app, maintaining security and governance.

    Access provisioning typically involves defining user roles, permissions, and privileges within the Salesforce Marketing Cloud (SFMC) environment. Administrators can tailor access levels based on the specific requirements and responsibilities of each user or group.

Conclusion:

Custom app solutions represent a game-changing approach to data extension creation for Distributed Marketing campaigns within Salesforce Marketing Cloud. By combining intuitive user interfaces with automated backend logic, these solutions enable organizations to streamline their campaign workflows, enhance data integrity, and maintain brand consistency with unparalleled efficiency and control. As organizations continue to embrace the power of customization in SFMC, custom app solutions stand poised to revolutionize the way Distributed Marketing campaigns are executed, driving greater impact and ROI in the ever-evolving landscape of modern marketing.

TOP


Comments

Most Viewed

CLOUD PAGE ENABLEMENT - PART 1

EMAIL NOT SENT IN JOURNEY BUILDER

CONSIDERATIONS FOR JOURNEY BUILDER

Understanding Transactional Messaging

Preference Center Demystified


Knowledge Article

Popular Posts

CLOUD PAGE ENABLEMENT - PART 1

EMAIL NOT SENT IN JOURNEY BUILDER

CONSIDERATIONS FOR JOURNEY BUILDER

Understanding Transactional Messaging

Preference Center Demystified

Journey Builder REST API Documentation

Share with Friends

Disclaimer:

The information provided on this technical blog is for general informational purposes only. As a SFMC (Salesforce Marketing Cloud) Technical Architect, I strive to offer accurate and up-to-date content related to SFMC and its associated technologies. However, please note that technology is constantly evolving, and the information provided may become outdated or inaccurate over time.

The content published on this blog represents my personal views and experiences as a SFMC Technical Architect and does not necessarily reflect the official views or opinions of any organization or employer I may be affiliated with.

While I make every effort to ensure the accuracy and reliability of the information presented, I cannot guarantee its completeness, suitability, or applicability to your specific circumstances. Therefore, it is essential to verify any information provided and make your own independent assessments or seek professional advice if needed.

Furthermore, any actions taken based on the information provided on this blog are at your own risk. I shall not be held liable for any damages, losses, or inconveniences arising from the use of the information presented here.

Please keep in mind that SFMC and its associated technologies are complex and require technical expertise for proper implementation and management. It is recommended to consult with qualified professionals or official SFMC documentation for comprehensive guidance.

Finally, please note that any product or company names mentioned on this blog are trademarks or registered trademarks of their respective owners. The mention of these trademarks or registered trademarks does not imply any endorsement or affiliation with the blog.

By accessing and using this blog, you agree to the terms of this disclaimer. If you do not agree with any part of this disclaimer, please refrain from using this blog.