Uniting Sales and Marketing – Integrating MS Bookings into Customer Insights Journeys

Guest edition, Author: Johannes Fleischhut

Foreword

I am delighted to be able to present another exciting guest article by Johannes Fleischhut today. Johannes is an experienced consultant in the field of Dynamics 365 Customer Insights and has presented an innovative approach to integrating MS Bookings into Customer Insights Journeys in his article. His creative approach clearly shows how important it is for sales and marketing to work together even more seamlessly. The method he describes of combining a low-threshold lead form with a binding appointment booking form is not only effective, but also extremely well thought-out. Johannes’ article illustrates how organisations can increase efficiency and improve customer service through smart integrations and proactive process design. I am delighted that he is sharing his knowledge and experience with us here.

Microsoft Bookings is great for allowing prospects to independently schedule an appointment with a staff member. There is nothing to be said against embedding MS Bookings forms directly on your website; the tool offers corresponding functionalities. However, booking an appointment requires a relatively high level of commitment, which may not be given at the moment of the first encounter by the interested party. As a result, the potential lead might drop off. In a client project, we therefore developed a small process that initially offers a non-binding lead form on the website. Prospects can enter basic data so that the lead can initially be created in the CRM. They then receive a confirmation email with a link to the MS Bookings page, from which they can optionally book an appointment directly. If they do not, a sales employee can contact them to arrange the appointment in this way. To minimize administrative work for the sales team, the associated journey should know whether a lead has scheduled an appointment or not and, if necessary, assign a corresponding task to sales.

Let’s get started!

The Customer Insights Form for the Website

First, we create a very simple form for leads in Dynamics Customer Insights, which includes the columns needed by sales (Name, Email Address, Phone, Company, Position). We also mandatorily request consent for transactional communication, so that we can later send the confirmation email without worries.

In my form, I have removed the labels from the HTML markup and only use placeholders. This leads to a somewhat more compact form, we wanted to get a quick overview of the form.

Otherwise, there’s nothing really exciting about this form, except maybe its own “matching rule” which checks the email address as well as the lead’s subject. This helps us prevent duplicate leads from being created through this specific form, but at the same time ensures that leads coming through different channels in the CRM will not be overwritten. In the Dynamics Customer Insights Settings section under the “Form matching strategy” tab, you can create your own matching rules. Just add the standard email column and the lead subject as columns to be checked and then select the new rule in the form.

Important: All columns used in the “matching rule” must also be included on the form. Therefore, I have integrated the “subject” column as a hidden formfield with the default value “Book Demo”. This overrides the standard behavior, which would use the name of the form as the lead subject.

The Bookings Page

Microsoft Bookings is designed to be user-friendly. I won’t delve too deeply into the details here. There are good instructions for creating MS Bookings pages, for example here: Customize and publish your MS Bookings page | Microsoft Learn

For our MS Bookings page, I have created two different services that have different durations. Otherwise, I have not made any changes to the configuration. The completed page looks like this:

The only thing that really needs to be taken into account here is that we have to define the user who will later run the flow as an administrator under Employees. This is a restriction in the Power Automate Connector. However, since the available employees can be selected individually for each service of the Bookings calendar, it should not be a problem to use a systemuser as administrator who is not part of the sales team and for whom no appointments can be booked later.

The Confirmation Email

Even with the confirmation email, there’s no real magic happening. We create a simple transactional email over Dynamics Customer Insights. For addressing, I have chosen the gender-neutral form “Hello First Name Last Name” to avoid complicated salutations.

In the email, a static button is inserted that contains the link to the MS Bookings page.

When the mail is finished, it could look like this or something similar:

Creating a Custom Trigger

If you have never created a trigger before, don’t worry. This trigger is super simple; we need it to later intervene in the journey through a Flow.

We thus create a new trigger of the type “When a customer interacts with a website/app.” In the first step, we can now add attributes. For our case, we need only the relationship to the lead. So, in the pre-filled attribute field, we select the Data type Lead instead of Contact. We don’t need any more fields.

We can completely skip the second step, as we do not want to run the trigger via code but via a Flow. We therefore click on “Next” and then on “Ready to use.”

The finished trigger then looks something like this:

The Magic happens in the Flow

Now we come to the essential part of our small process, the link between Bookings and Customer Insights: our Flow.

Power Automate offers an OOB Connector to Microsoft Bookings. We select the trigger “When an Appointment is Created” here. At the time of writing this blog, the connector to Microsoft Bookings is still in preview mode, is a bit buggy from time to time, but basically works and is perfectly adequate for our use case.

It is now important that we use the trigger via the same system user who is listed as an administrator on the MS Bookings page. Once the connection is established, a dropdown should actually display all the MS Bookings pages available for this user. At the time of the blog article, I had problems getting this list displayed, instead, I received a page-long error message, which was probably due to the preview status of the connector. But this need not hold us back, because fortunately, we can also insert custom values into the trigger, and these proved to be fully functional.

The value that we need to insert into the “MS Bookings page” field is the SMTP address of our MS Bookings page. This can be found, for example, in the URL of the page (highlighted in yellow here).

Once the custom value is inserted, the trigger should work.

I have gotten into the habit of initially doing a test with new triggers and flows and simply inserting a Compose step that contains the body of the trigger. This gives me a feel for the data contained therein and its structure. This then looks something like this:

When the flow has run for the first time, I have my data available and can reactivate the same run again and again later when testing, so that I don’t have to constantly fire the trigger again in real life (and end up with 100 test events in the calendar).

Finding the correct lead in the CRM

So that we can activate our Customer Insights trigger in the next step, we need to find out which lead in the CRM corresponds to our new MS Bookings entry. I do this based on the email address and the subject. To store the subject in the flow as a variable, you could insert sophisticated logic ranging from environment variables to your own queries from the Dataverse. For me, however, a simple variable that I give the same name as my subject form field from the lead form, namely “Book Demo”, is sufficient.

Then I can start a query using the Dataverse Action “List Rows” that returns the latest active lead to me which contains the email address from the Bookings event and the previously defined subject. There should generally be only one result from this combination, but I enforce this just to be sure by setting the “Row count” to 1.

The line for “Filter rows” reads (make sure to name your variable “Lead Subject”, if you copy this line):

statuscode eq 1 and emailaddress1 eq '@{triggerOutputs()?['body/CustomerEmail']}' and subject eq '@{variables('Lead Subject')}'

I then set my previously initiated variables for the lead ID and the owner ID. For the sake of simplicity, I accept the “Apply to each” loop that is automatically created here. If this is too confusing for you, you could also work with the first()-Function of Power FX, but this is just a hint.

Bonus Tip: Going the Extra Mile

We have not solved this in our form in this way, but it would also be conceivable – in order to offer interested parties an even faster experience – that after submitting the form, they are redirected to a new page on which the link to the booking page is already stored. In the event that an appointment is booked directly, it could happen that the lead has not yet been created in the Dataverse. To ensure that our flow can still do its work, we should repeat the search process until the lead is found (or cancel it after a certain time).

To do this, we use a “Do until” loop, which is repeated for an hour, for example, until the variable for our lead ID contains a value. Within the loop, we repeat the previously defined steps and always add a waiting time of one minute at the end. If the lead is found at some point, the loop is exited and we have the same result as if the lead had been found from the beginning.

Now that we have all the necessary data, we can trigger our custom trigger. For this, there is the Dataverse Action “Perform a background operation.”

As Catalog, we choose “Cxp” (Customer Experience), as Category “Custom,” and as Action name then the name we gave our trigger. We can then enter our information.

Column nameValue
msdynmkt_signalingestiontimestamp@{utcNow()}
msdynmkt_signaltimestamp@{utcNow()}
msdynmkt_signaluserauthid@{variables(‘Lead ID’)}
msdynmkt_profileid@{variables(‘Lead ID’)}

Die BindingID lassen wir leer, mit ihr könnten wir einzelne Journey-Läufe ansteuern, die denselben Lead enthalten. Ich gehe nicht davon aus, dass es in We leave the BindingID empty; with it, we could target individual Journey runs that contain the same lead. I don’t expect there to be frequently running Journeys for the same lead in our Journey (this would require the form to be filled out multiple times with the same data within a short time). But if that were to happen, we would still want all runs for the same lead to receive the information that an appointment was booked. If the “msdynmkt_bindingid” field remains empty, we achieve exactly this.

Finally, we can create an appointment in the CRM and attach it to the lead (Caution: If appointments are already synchronized from Outlook, this step is probably unnecessary). With the Dataverse Action “Create new Row,” we create an appointment and enter the most important information. In my case, these were:

Column NameValue
SubjectMicrosoft Bookings: @{triggerOutputs()?[‘body/ServiceName’]}
End time@{triggerOutputs()?[‘body/EndTime’]}
Start time@{triggerOutputs()?[‘body/StartTime’]}
Description Details via MS Bookings: Email address: @{triggerOutputs()?[‘body/CustomerEmail’]} Phonenumber: @{triggerOutputs()?[‘body/CustomerPhone’]} Customer Location: @{triggerOutputs()?[‘body/CustomerLocation/DisplayName’]}
Reference(Leads)leads(@{variables(‘Lead ID’)})
Activity Party Attribute Name – 1Organizer
Activity Party Attribute Value – 1systemusers(@{variables(‘Lead Owner’)})
Teilnahme-URL für Onlinebesprechung@{triggerOutputs()?[‘body/JoinWebURL’]}

Finally, the Journey

We need a trigger-based journey that responds to submissions from our initially created Customer Insights form. Thus, we select “Marketing Form Submitted” as the trigger and choose our form as the form reference.

Next, we send out the confirmation email via a simple Email Action.

We then add a “Wait for Trigger” condition, select “A trigger is activated”, and choose our custom trigger. The time limit can be anything that makes sense from a business perspective. We’ve opted for 4 hours. This means, at this point the journey will wait 4 hours for the trigger to be activated.

If the trigger is activated, it means that the flow has run, which in turn indicates that an appointment has been booked by the lead. Thus, our journey is complete at this point. No further steps are required in the Yes-Branch.

If the trigger is not activated within four hours, it means that no appointment has been booked. In this case, we should create a task for the sales team to contact the lead to arrange an appointment.

We have defined this task as follows:

Column NameValue
SubjectMake an appointment for a demo
Assign toLead owner
Due after1 day
Notes to assigneeLead filled out the webform for a free demo, but did not book an appointment afterwards. Contact lead for an appointment.

All in all, our journey ends up looking like this:

Limitations of the Process

I would have liked to have the ability to pre-fill the customer data, which we already know from the first form, on the Bookings page when it opens. Unfortunately, to my knowledge, MS Bookings does not offer the ability to place custom code on the Bookings page to achieve this. We might need to resort to other, more complex tools for this purpose.

I also wish that the Bookings connectors, and also the Outlook connectors from Power Automate, had options for acting beyond one mailbox. Many customers want cross-mailbox automation, which until now has only worked via workarounds or by copying the flow to other mailboxes.

What can you think of to expand or refine the process? Write it in the comments!

“I’m Johannes, and I’ve been advising clients from various industries on using Dynamics 365 Customer Insights, Power Apps, and Power Automate for several years. Previously, I also worked as a full-stack web developer. Currently, I am employed as Project Lead for Dynamics 365 Customer Insights at KC | KAISERSTADT CONSULTING GmbH & Co. KG in Aachen and primarily work from my home in Berlin. I love open knowledge exchange in the IT world, have learned a lot from bloggers around the globe in the past, and am excited to give something back through this medium.”

***Please be aware: The content is accurate at the time of creation. It may be that Microsoft has made changes in the meantime.***

Leave a Reply

Your email address will not be published. Required fields are marked *

Sharing is caring

Stay informed

WordPress Cookie Notice by Real Cookie Banner