True story… my career really took off over a decade ago when I started a position as an Integration Consultant for ExactTarget (now Salesforce Marketing Cloud). My job took me all over the world assisting companies in developing deep integrations with the platform and I built up so much institutional knowledge of the platform that I was promoted to Product Manager.
The challenges of Product Manager for an organization that was previously developer-owned eventually led me to move on. It was a great organization, but I never truly owned the product. So, while my peers in support, sales, and product marketing looked to me to make a real change… the reality was that the development team often implemented a different solution and I'd find out days before the release.
One of my last projects was working on an internal scripting platform that would enable our customers to add script to their emails. I worked with another Product Manager and we did a ton of research… eventually deciding to develop a JQuery-style approach with our own functions, but including the ability to pass and consume arrays, utilize JSON, etc. It was going to be quite the solution… until it hit development. Early in the product cycle, my library was scrapped and a senior developer replaced it with AMPscript.
Years later, the Salesforce Partner company I am a partner in is now doing complex, enterprise integrations, and I find myself mired in AMPscript on a daily basis – either enhancing email content logic or rolling out Cloud Pages. Of course, the frustration of working day in and day out with AMPscript ensures me that the wrong decision was made back in those days… my solution would have been far more elegant. I feel like I'm back to programming a TRS-80 in BASIC.
The editor that you use for Cloud Pages is unforgiving. It doesn't catch simple issues like declaring variables or syntax errors with your code. In fact, you can actually publish a page that will simply generate a 500 server error. There are also two naming fields for your pages… don't ask me why.
Pro-tip: If a Cloud Pages never returns sample data when you're about to publish and it looks like it's processing forever… you're going to throw an error. If you publish anyways, you're probably going to have to delete the Cloud Page altogether and start over. My guess is that the infrastructure that it's built on isn't intelligent enough to identify a code change and just keeps processing the cached code.
Aside from that, you'll be glad to know many of the documented code samples have their own syntax errors. Yay! It's a horrible experience… but you can still and should use it because it provides some amazing flexibility.
Side note: There is a new Cloud Page Experience… where it looks like they just re-skinned the page and it doesn't provide any additional information. I actually like the old version better for the multi-step publishing sequence.
While my company Highbridge builds out complex, Ajax-enabled solutions that integrate multiple systems and incorporating data extensions with AMPscript, SSJS, Cloud Pages, and email… I wanted to share a simple example of how you can get started simply using AMPscript to query your Salesforce instance and pull back data. In this case, a simple boolean field that retains a master unsubscribe flag. You can, of course, extend this code to build out an entire preference page or profile center that you can use.
Generate A Cloud-Page Link with Subscriber Data
If you view your Cloud Page details, you can acquire the unique page ID for the page that you can include in your emails.
The syntax is as follows:
<a href="%%=RedirectTo(CloudPagesURL(361))=%%">View My Preferences</a>
AMPscript for Salesforce Data via Cloud Pages via Data Extensions
The first step is building your AMPscript to declare variables and retrieve the data from Salesforce to use in your page. In this example, my Salesforce boolean field that holds the true or false is named OptedOut:
%%[ /* Declare EVERY variable */ VAR @contactKey,@agent,@referrer,@unsub VAR @rs,@updateRecord,@checked /* Request your ContactKey from the querystring */ Set @contactKey = Iif(Empty([_subscriberKey]),RequestParameter("contactKey"),[_subscriberKey]) /* Set unsub to false unless it is passed in the querystring */ SET @unsub = Iif(Not Empty(RequestParameter('unsub')),RequestParameter('unsub'),'false') /* If unsub, then update the Salesforce field OptedOut */ IF NOT Empty(@unsub) THEN SET @updateRecord = UpdateSingleSalesforceObject('contact',@contactKey,'OptedOut', @unsub) ENDIF /* Retrieve the Salesforce Contact record */ Set @rs = RetrieveSalesforceObjects('contact', 'FirstName,LastName,OptedOut', 'Id', '=', @contactKey); /* Get the fields from the record */ IF RowCount(@rs) == 1 then var @record, @firstName, @lastName, @optout set @record = Row(@rs, 1) set @firstName = Field(@record, "FirstName") set @lastName = Field(@record, "LastName") set @optout = Field(@record, "OptedOut") ENDIF /* Build a string for your checkbox to be checked or not set @checked = ''; IF (@optout == 'true') THEN set @checked = 'checked' ENDIF ]%%
Now you can build out your HTML and form that processes the request:
<!DOCTYPE html> <html> <title>Profile Center</title> <body> <h2>Your Profile:</h2> %%[ if RowCount(@rs) == 1 then ]%% <ul> <li><strong>First Name:</strong> %%=v(@firstName)=%%</li> <li><strong>Last Name:</strong> %%=v(@lastName)=%%</li> <li><strong>Unsubcribed:</strong> %%=v(@optout)=%%</li> </ul> <form method="get"> <div> <input type="hidden" id="contactKey" name="contactKey" value="%%=v(@contactKey)=%%"> <input type="checkbox" id="unsub" name="masterUnsub" value="true" %%=v(@checked)=%%> <label for="masterUnsub">Unsubscribe From All</label> </div> <div> <button type="submit">Update</button> </div> </form> %%[ else ]%% <p>You don't have a record.</p> %%[ endif ]%% </body> </html>
That's it… put it all together and you've got a preference page that's updated with your subscriber record and passes a request to update a boolean field (true/false) in Salesforce. Now you can build custom queries around that field to always ensure contacts that are opted out are not sent any email!
How to Enhance Your Preference Page or Profile Center
Of course, this is just a teaser of what's possible with a preference page. Enhancements you may wish to think about:
- Populate the actual text from another data extension so that your marketing team can update the content of the page whenever they'd like without touching the code.
- Populate a publication list data extension and loop through the publications to offer opt-in or opt-out on preferences in addition to a master unsubscribe.
- Populate a reason data extension to capture why your subscribers are master unsubscribing.
- Populate other profile information from the Salesforce record to provide additional profile information.
- Process the page with Ajax so that you can seamlessly populate it.
- Offer a means of registration so that your user can access their personal profile center at any time.
Additional Resources for AMPscript
If you're seeking some additional assistance for learning and deploying AMPscript, here are som great resources:
- AMPscript Guide – organized by some Salesforce employees, this is a pretty complete database of AMPscript syntax, although the examples are really light. If it was more robust, it might be worth the investment.
- Trailhead AMPscript – Salesforce's Trailhead is a free learning resource and can walk you through the basics of the language with both AMPscript, SSJS, and how the two can interact.
- Stack Exchange for Salesforce – a great online community for requesting assistance with a ton of AMPscript code samples.
There's a ton of opportunity in integrating your Cloud Pages with Salesforce to provide a superior user experience. And if your company is struggling, you can always contact us to assist!