How to Create a CloudPage in Salesforce Marketing Cloud
A CloudPage in Salesforce Marketing Cloud is a web landing page you can build, publish, and host directly within the platform — no external web server required. CloudPages serve as the foundation for subscription center forms, preference pages, event registration, and data capture throughout your SFMC ecosystem. In this guide, you'll learn the complete workflow for creating, building, testing, and publishing a CloudPage, including how to add dynamic AMPscript and Server-Side JavaScript (SSJS) logic.
What is a CloudPage?
A CloudPage is a Marketing Cloud-hosted web page accessible via a unique URL in the format https://<tenant>.cloudpages.com/<page-id>. Unlike legacy Microsites, CloudPages are created and managed through Content Builder, giving you a unified interface for assets, images, and page layouts. CloudPages can function as public-facing landing pages or as authenticated pages that read subscriber context from URL parameters or cookies.
Prerequisites
Before creating a CloudPage, ensure you have:
- Salesforce Marketing Cloud account with the CloudPages feature enabled
- Content Builder access (requires the Content Builder permission set)
- Publication rights to the Business Unit where you intend to publish
- Basic familiarity with HTML and either AMPscript or SSJS for dynamic content
Step-by-Step: Creating Your First CloudPage
Accessing Content Builder
- Log in to Marketing Cloud and navigate to Cloudpages (found under the Web Studio tab in the top navigation).
- Click the Folder you want to store your cloudpage in on the left sidebar.
- Select Landing Pgae from the dropdown menu in the top right called Add Content.
- Fill out the popup form and click next. For this tutorial, select Blank Layout.
Content Builder opens the page editor with a drag-and-drop interface. You can add text blocks, images, forms, and code elements from the component palette on the left.
Naming and Configuring the Page
Before adding content, configure the page properties:
- Click the Settings gear icon (⚙️) on the right sidebar.
- Set a descriptive Page Name (e.g., "Newsletter Subscription Center").
- Set the Page ID slug — this becomes part of your public URL.
- Choose Public or Secure access. Secure pages require authentication context from Email Studio.
- Click Save.
Building the CloudPage Content
Adding Static HTML Content
Drag an HTML component from the palette onto the page canvas. Double-click to edit the HTML source. A basic subscription form looks like this:
<div class="subscription-form">
<h2>Subscribe to Our Newsletter</h2>
<form action="https://pages.example.com/submit" method="POST">
<label for="email">Email Address:</label>
<input type="email" id="email" name="email" required>
<input type="submit" value="Subscribe">
</form>
</div>
Adding AMPscript for Dynamic Content
AMPscript executes server-side when the page loads, before the HTML renders. Use AMPscript to personalize content, retrieve subscriber data, or handle form submissions.
Personalizing with AMPscript
Insert an AMPscript block at the top of your page (above the HTML):
%%[
VAR @subscriberKey, @email, @firstName, @status
/* Retrieve query string parameters */
SET @subscriberKey = RequestParameter("subkey")
SET @email = RequestParameter("email")
/* If no subscriber key provided, default to guest view */
IF EMPTY(@subscriberKey) THEN
SET @firstName = "Guest"
SET @status = "unknown"
ELSE
/* Look up subscriber attributes from Data Extension */
SET @firstName = Lookup("SubscriberAttributes", "FirstName", "SubscriberKey", @subscriberKey)
SET @status = Lookup("SubscriberAttributes", "Status", "SubscriberKey", @subscriberKey)
/* Handle missing data gracefully */
IF EMPTY(@firstName) THEN
SET @firstName = "Subscriber"
ENDIF
ENDIF
]%%
Then reference these variables in your HTML:
<h1>Welcome, %%=v(@firstName)=%%!</h1>
<p>Your current status: %%=v(@status)=%%</p>
Handling Form Submissions
Use AMPscript to process form data and write to a Data Extension:
%%[
/* Only process on POST */
IF RequestParameter("submit") != "" THEN
VAR @email, @firstName, @source, @insertResult
SET @email = RequestParameter("email")
SET @firstName = RequestParameter("firstname")
SET @source = "CloudPage Signup"
/* Validate email format */
IF EMPTY(@email) OR NOT EMPTY(IndexOf(@email, "@")) == false THEN
SET @errorMessage = "Please provide a valid email address."
ELSE
/* Upsert into Data Extension */
SET @insertResult = UpsertData(
"NewsletterSubscribers",
1,
"EmailAddress", @email,
"FirstName", @firstName,
"Source", @source,
"SignupDate", NOW()
)
IF @insertResult == 1 THEN
SET @successMessage = "Thank you for subscribing!"
ELSE
SET @errorMessage = "There was an error processing your request."
ENDIF
ENDIF
ENDIF
]%%
Adding Server-Side JavaScript (SSJS)
SSJS provides more complex logic and access to the SFMC API. Use it when you need loops, try-catch error handling, or external API calls.
Basic SSJS Structure
<script runat="server">
Platform.Load("core", "1");
var subscriberKey = Request.GetQueryStringParameter("subkey");
var email = Request.GetQueryStringParameter("email");
// Initialize Data Extension
var DE = DataExtension.Init("NewsletterSubscribers");
// Perform lookup
var results = DE.Rows.Retrieve({
Property: "EmailAddress",
SimpleOperator: "equals",
Value: email
});
if (results && results.length > 0) {
// Store data for use in AMPscript via Platform.SetValue
Platform.SetValue("sub_firstName", results[0].FirstName);
Platform.SetValue("sub_status", results[0].Status);
}
</script>
Error Handling in SSJS
<script runat="server">
Platform.Load("core", "1");
try {
var apiClient = new Script.Util.WSProxy();
var props = { Name: "TestDE" };
var data = apiClient.Retrieve(props);
// Process results
if (data && data.Results) {
for (var i = 0; i < data.Results.length; i++) {
Platform.Debug.Write(data.Results[i].Name);
}
}
} catch (e) {
// Log error without exposing details to user
Platform.Variable.SetValue("errorMessage", "An error occurred. Please try again.");
Platform.Debug.Log("SSJS Error: " + String(e));
}
</script>
Testing Your CloudPage
Preview Mode
Content Builder provides a Preview tab that renders the page with sample data. You can inject test values for query parameters:
Preview URL: ?subkey=test123&email=test@example.com
Testing Form Submissions
- Click Preview in the top-right corner.
- Select Open in new tab to interact with the live preview.
- Fill out the form and submit.
- Verify the data was written to your target Data Extension by querying it directly in Automation Studio or via SQL Query Activity.
Common Data Extension Query for Verification
SELECT TOP 100
EmailAddress,
FirstName,
Source,
SignupDate
FROM NewsletterSubscribers
WHERE Source = 'CloudPage Signup'
ORDER BY SignupDate DESC
Publishing Your CloudPage
Once testing is complete:
- Click Publish in the top-right corner of Content Builder.
- Marketing Cloud validates the page and assigns a public URL.
- The URL follows the format:
https://<tenant>.cloudpages.com/<page-id> - Copy this URL for use in emails, SMS messages, or external campaigns.
Important: Publishing updates are immediate. If you modify a published page, click Publish again to push changes live.
Common Pitfalls
1. Missing RequestParameter Validation
Always validate query string parameters before using them in lookups. Unsanitized input can cause errors or expose unintended data:
/* WRONG - Direct lookup without validation */
SET @email = RequestParameter("email")
SET @subscriberKey = RequestParameter("subkey")
SET @name = Lookup("Subscribers", "Name", "SubscriberKey", @subscriberKey)
/* CORRECT - Validate first */
SET @subscriberKey = RequestParameter("subkey")
IF NOT EMPTY(@subscriberKey) AND Length(@subscriberKey) <= 50 THEN
SET @name = Lookup("Subscribers", "Name", "SubscriberKey", @subscriberKey)
ELSE
SET @name = "Unknown"
ENDIF
2. SELECT * in Automation Studio Queries
CloudPages often write to Data Extensions that feed Automation Studio reports. Never use SELECT * in your Query Activities — it violates the 30-minute execution timeout and can cause unexpected failures:
/* WRONG */
SELECT * FROM NewsletterSubscribers
/* CORRECT - Specify columns explicitly */
SELECT
EmailAddress,
FirstName,
Source,
SignupDate
FROM NewsletterSubscribers
WHERE SignupDate >= DATEADD(day, -1, GETDATE())
3. Hardcoding Business Unit MID
When writing AMPscript that references Data Extensions, avoid hardcoding the Business Unit MID. Use MemberID() to retrieve the current context dynamically:
%%[
SET @currentMID = MemberID()
SET @subscriberData = LookupOrderedRows(
"SubscriberAttributes",
1,
"SignupDate DESC",
"SubscriberKey", @subscriberKey,
"MID", @currentMID
)
]%%
4. Forgetting to Publish After Edits
Unlike code repositories, CloudPage edits do not auto-deploy. Forgetting to click Publish after changes is a common cause of support tickets where stakeholders see stale content.
5. Blocking CloudPages in Sender Profiles
If your CloudPage form submits to an email address via a mailto: link or external form handler, ensure your Sender Profile doesn't block the domain. Test the full submission flow end-to-end before campaign launch.
FAQ
How do I pass subscriber data from an email to a CloudPage?
Use AMPscript's CloudPagesURL() function when constructing links in your emails. This function automatically appends the subscriber key and other tracking parameters:
<a href="%%=CloudPagesURL(1234)=%%">Update Preferences</a>
On the CloudPage, retrieve these values with RequestParameter("SubscriberKey") or RequestParameter("jobid").
Can CloudPages access data from data views like _Sent, _Open, or _Click?
Yes, but only from the parent Business Unit, and only if your account has the appropriate data view permissions. Standard data views are read-only and include _Sent, _Open, _Click, _Bounce, and _Unsubscribe. You cannot write to these views:
SELECT
s.SubscriberKey,
s.JobID,
o.IsUnique,
o.EventDate
FROM _Sent s
INNER JOIN _Open o ON s.JobID = o.JobID AND s.SubscriberKey = o.SubscriberKey
WHERE s.JobID = @jobID
How do I add CAPTCHA or bot protection to a CloudPage?
Marketing Cloud does not include built-in CAPTCHA functionality. For bot protection, integrate a third-party solution like Google reCAPTCHA v2. Load the reCAPTCHA script in an HTML block and validate the token server-side using AMPscript or SSJS before processing form submissions.
What is the difference between a CloudPage and a Microsite?
CloudPages are the modern replacement for legacy Microsites. CloudPages are created in Content Builder, support responsive design, and integrate with the SFMC publishing workflow. Microsites (deprecated) used a separate interface and are no longer recommended for new implementations.