Hadn't even heard of Appointlet until the other day, but when user SS mentioned he was trying to use the REST API to integrate an Appointlet widget with Marketo, I knew there had to be a better way. (There's almost always a more reliable + scalable alternative to server-to-server API calls for what should be browser-side integrations, Unbounce being another example.)
In line with services like ChiliPiper, TimeTrade, Calendly, et al. Appointlet is a service I wish I'd thought of because I'd be rich right now dedicated to scheduling. It interacts with a cloud calendar — O365 or Google calendar in this case — in real time to check availability, alerts reps of new bookings, and sends periodic reminders. (Again, no endorsement intended, just describing the published features... only spent 1/2 hr figuring out the API, so perhaps the platform might turn out to have humongous bugs, but it definitely looks useful enough so far!)
The Appointlet embed code gives you a button, which when clicked brings up the rep's availability:
And then a place for the lead to enter their personal info (more fields can be added but these are the defaults):
Naturally, when you're offering an Appointlet Book Now instead of a full Marketo form, the questions are:
The best answers are definitely not found in the Marketo REST API. Appointlet does offer outbound HTTP callbacks (accurately called webhooks, but they must not be in any way confused with Marketo's outbound 'hooks). So yes, you could set up your own gateway to receive said callbacks, and you could map them to the Marketo REST API endpoints (plural) that sort-of-maybe emulate a Marketo form post. But that means raw coding labor, new servers to maintain, and Denial of Service exposure. And no upside.
Instead the answer, as usual, is to simply post a Marketo form in the background, relaying the lead info from the Appointlet UI.
To do this reliably, Appointlet needs to have a client-side JS API. And indeed they do!
The Appointlet widget itself is rendered in an IFRAME, and like other sophisticated IFRAME-based embeds (the YouTube player, for example) the widget sends standard browser events to the parent document (that is, to the outer Landing Page) that include interesting info from the widget. We just have to listen for those events, add corresponding values to a Marketo form, and submit. Then we'll get a standard Filled Out Form activity in the Marketo Activity Log, which you can trigger and filter on like any other, and past + future Visited Web Page and Clicked Link on Web Page activities from that browser get merged in, too.
So first, set up a form that'll catch submissions from your Appointlet widget. (You can set up more than one form if you want to see cosmetically different Filled Out Form names for different pages, but it's not necessary and you don't want to create complexity.)
It doesn't need any fields at all, since we'll be populating the fields via API, but you can leave the default 3 fields in place. Just don't make any of them Required.
Inline style="display:none;" is easiest. With the embed code:
<form style="display:none;" id="mktoForm_787" class="mktoForm"></form>
With a Guided Marketo LP:
<div class="mktoForm" id="appointletForm" mktoName="Appointlet Hidden Form" style="display:none;"></div>
Or you can put it in a separate <style> which is more professional I suppose.
This is of course the meat of the solution.
MktoForms2.whenReady(function(mktoForm) {
var appointletUserConfig = {
allowedOrigins : ["https://teknkl.appointlet.com"],
formFields : [
{
appointletName : "first-name",
marketoName : "FirstName"
},
{
appointletName : "last-name",
marketoName : "LastName"
}
]
};
/* NO NEED TO TOUCH BELOW THIS LINE! */
window.addEventListener("message", function(message) {
var appointletGlobalConfig = {
messageType : {
TYPE_BOOKING_CREATED : "booking:created"
},
pattern : {
RE_AL_POSTMSG : /^appointlet:/
},
err : {
ERROR_NON_ORIGIN : "Message received from non-Appointlet origin",
ERROR_BAD_JSON : "Message received from Appointlet API but could not be parsed"
}
};
var appointletEvent,
isAlOrigin,
isAlBookingCreated,
mktoFieldsObj = {};
isAlOrigin = appointletUserConfig.allowedOrigins.some(function(origin){ return origin == message.origin; });
if (!isAlOrigin) {
return;
}
try {
appointletEvent = JSON.parse(message.data.replace(appointletGlobalConfig.pattern.RE_AL_POSTMSG, ""));
} catch (err) {
return console.log(appointletGlobalConfig.err.ERR_BAD_JSON);
}
if (appointletEvent.type == appointletGlobalConfig.messageType.TYPE_BOOKING_CREATED) {
mktoFieldsObj["Email"] = appointletEvent.data.email;
appointletUserConfig.formFields.forEach(function(fieldDesc){
mktoFieldsObj[fieldDesc.marketoName] = appointletEvent.data.fields.filter(function(alField){
return alField.field.slug == fieldDesc.appointletName;
})[0].value;
})
mktoForm.addHiddenFields(mktoFieldsObj);
mktoForm.submit();
}
});
});
Most of the code is no-touch, but there's a short config area at the top where you put your company-specific variables. From your Appointlet settings, get your Booking Page URL. That goes in the allowedOrigins config property:
Then the formFields property is an array that maps each Appointlet field name to its corresponding Marketo field name. (You didn't think it would be so easy that the separate products would miraculously use the same names, didja?) I filled in the First Name and Last Name mappings for you. Names of additional custom fields can be found via browser inspection, the Appointlet » Form Fields UI, and the SOAP API Name column of a Marketo UI » Field Management CSV export.
And that's it! Now, any confirmed Appointlet booking will post the form to Marketo.
That's on you.☺ I found it very easy to set up an Appointlet account, link to a test Google Calendar, and grab the button code. But since I don't want to imply an outright endorsement, better to leave the rest of the product evaluation in your hands.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.