*** NOTE: ALL INFORMATION IS ACCURATE AT DATE OF PUBLISHING ***
You might have several different forms that allow someone to opt in to specific Topics in Realtime Marketing. Perhaps you even have some of those Topics hidden and are opting people in automatically when the form is submitted. What if you want to have the person go through a Journey and send them a thank you email once opted in to a specific Topic but don’t want to have a separate Journey per form just to achieve that? How about a trigger that fires when someone is opted in to a specific Topic? This post will show you how to achieve that.
First thing we need to do is create a trigger. You might need two if you are capturing information for Leads and Contacts, one for each, as a trigger can only fire for one type of audience member. In my example I am going to do this for Leads. Give your trigger a name and make sure you have the second action selected. Click Create.
Now we need to add our attributes which is going to be very simple. I will pick Lead for the customer type, and then add an attribute that I am calling Consent Record, which has the data type of Entity Reference. Then I am selecting the Contact Point Consent table.
Publish the trigger, then when you get to this part, click the link to go to the code snippet as we will need some information from here. The next steps of this post are thanks to a wonderful post from Amey Holden which you can check out here. She wrote a great article that explains how to use the entity reference type in a trigger and get it to run correctly via Power Automate. Thanks Amey!
When you open the code snippet, you will need the two bits that are highlighted so keep that window open or copy and paste the information so you have it shortly.
Ok so next you will need to create a flow in Power Automate using the Dataverse connector as the starting Trigger. It will fire on Added or Modified on the Contact Point Consents table.
We are now going do add a condition check to make sure the Contact Point Consent record created or updated is the type we are interested in. There are five things we are going to check. They aren’t named all that well to be obvious what is what, so I’ve added some extra information so it’s clear what we are doing. Database field name first then the field label, then what you are checking with the option label along with the option value. We only want to do something when the Contact Point Consent record is for a Topic, for Email, updated or created via a Realtime Marketing Form (meaning the person changed it themselves), it was Opted In and make sure the Topic does contain a value.
- msdynmkt_contactpointconsenttype – Consent Type = Topic – 534120001
- msdynmkt_contactpointtype – Channel = Email – 534120000
- msdynmkt_source – Source = Realtime Marketing Form – 534120005
- msdynmkt_value – Consent Status = Opted In – 534120001
- msdynmkt_topicid – Topic – not equal to NULL
If all of those conditions are met, we then want to do a List rows step and find the Lead (or Contact) that matches the Contact point value (email address) from the Contact Point Consent record. We can filter the rows using emailaddress1 eq ‘@{triggerOutputs()?[‘body/msdynmkt_contactpointvalue’]}’. You might have multiple Leads that match, so adding in a sort by modifiedon desc and row count of 1, we will get the most recent updated Lead.
emailaddress1 eq '@{triggerOutputs()?['body/msdynmkt_contactpointvalue']}'
Add in another condition and use the expression of length(body(‘Find_Related_Lead’)?[‘value’]), then is equal to 1. This is counting the number of Leads brought back in the step above and if equal to 1 we can take the Lead and put them in a Journey. If it’s not, that means there is no Lead with that email address found so we do nothing. In theory, that shouldn’t happen, but just in case, there is no one to put in to a Journey so the flow stops.
length(body('Find_Related_Lead')?['value'])
On the yes path, add a Get row by ID action step and set it to the Leads (or Contacts) table. The row id will be passed using the expression below. This gets the first Lead found in the List rows step and passes the lead id specifically. Using this approach means we don’t end up with a bunch of Apply to each steps which we want to avoid. We can also add leadid to the select columns option as that is the only thing we need. No
first(outputs('Find_Related_Lead')?['body/value'])['leadid']
Once we have gathered all of that information, we are now ready to compose the information needed to get the trigger to fire. Add in a Compose step, then paste in the following. Remember the step at the start after the trigger was created and you had access to the code snippet? The first line below where it starts with msdynmkt_consentrecord, the consentrecord part is whatever you have in the code snippet above the bindingid section. If you have copied my post exactly, it should be the same. If you named the Contact Point Consent Entity Reference something different to Consent Record, you will need to use that. We are then passing through the current date/time for some timestamps the trigger needs, and then passing through the lead id that is needed by the trigger also.
{ "msdynmkt_consentrecord": "msdynmkt_contactpointconsent4s/@{triggerOutputs()?['body/msdynmkt_contactpointconsent4id']}", "msdynmkt_signalingestiontimestamp": "@{utcnow()}", "msdynmkt_signaltimestamp": "@{utcnow()}", "msdynmkt_signaluserauthid": "@{outputs('Get_Lead')?['body/leadid']}", "msdynmkt_profileid": "@{outputs('Get_Lead')?['body/leadid']}" }
The last step of the trigger is to use the action of HTTP with Microsoft Entra ID (preauthorized). You will need the URL of your D365 environment when connecting to this, putting it in to the Base Resource URL field and the Azure AD Resource URI field. Once connected, use the Invoke an HTTP request action. Now we need a couple of things to create a string that will be used to push the information created in the Compose step above and push it in to the trigger to fire your Journey.
I’ve shared what the request URI looks like for me, but when generating the URL dynamically, I always go back to this post from MVP Joe Griffin where he shows how to get the URL from a previous get a row by ID step (we will use the Get Lead step). The end of the URI is the name of the trigger which you will find in the code snippet after you created the trigger. So don’t just copy that part, use your own as the numbers at the end will be different!
https://@{uriHost(outputs('Get_Lead')?['body/@odata.id'])}/api/data/v9.2/msdynmkt_topicconsentoptedin_lead_124144140
That’s it with the flow, save it and make sure it’s turned on. Next you will need to make sure you have a form that contains one or more of your topics. After adding the topic checkbox, update the text that shows next to the box, and then make sure you edit the topic to link to the right compliance profile and topic.
Assuming you’ve created the email you want to send when someone opts in, you can create your Journey from the new trigger you made. Here’s the brilliant part because we set this up to use the Contact Point Consent table as the entity reference, we can add some filtering criteria to this Journey. Open up the trigger and then click on Consent Record (or whatever you named the value in the trigger).
From there, you can find the Purpose and click on that, then click on the blue line where it says ‘Condition on Purpose). That gives you a lookup so you can make sure the Contact Point Consent record is linked to a specific Purpose only.
Then you can do the same thing again, and this time go in to the Topic and find the exact one you want to make sure is used to start the Journey. Note that if you don’t add any conditions, the Journey will fire for every single Contact Point Consent record that is for any Topic.
Now add in the Email for your Journey, and also make sure you don’t apply quiet times so the email can go whenever someone has actually opted in.
You might also want to check for frequency caps and turn those off too so that all emails go through as intended.
Now you can create different Journeys using the same trigger, but make sure to add in your filtering conditions so that it only fires when someone opts in to a specific Topic. Hope this helps!
Check out the latest post:
Auto Assign Leads Without Code Using Lead Scoring & Work Assignment
This is just 1 of 477 articles. You can browse through all of them by going to the main blog page, or navigate through different categories to find more content you are interested in. You can also subscribe and get new blog posts emailed to you directly.
Hi Megan,
I was just trying to find a solution for this, so thanks for always posting great articles!!
I have a question – you wrote in the beginning of the article that it is possible to hide topic fields in real time marketing forms. Can you explain how? It seems to me that you can only hide contact attribute fields and not topics? I have created a flow to opt people in to topics, but it would be easier if they could be checked by default and hidden.
Thanks!!
Hi Megan! It’s not something with an out of the box control but you can go in to the HTML and add a hidden attribute to the Topics. Check out this post for how to do it: https://meganvwalker.com/creating-newsletter-sign-up-for-your-website/
I have a client that is asking about this capability and I wasn’t sure if it was possible.
Your article is amazing, not only because it highlights that it can be done but also the added detail and explanation that you add.
Thank you so much for the great article 🙂
Hi Corry, you are very welcome! Glad it helped!
Is there a way to do this in a journey that’s on a contact? I’m trying to branch a journey based on what consent they opted into, so if they tick yes for transaction they go down one branch, and if they tick no for commercial then the journey ends. And I cannot find a way to get at the contact consent point.
Hi Milla, yes. One of the first things the blog states is that you might need two flows, one for Contacts and one for Leads. I just did the blog using Leads as an example. If you are wanting to do it based on Purpose (Commercial or Transactional) then your flow would need to be checking for that rather than Topic as I used in my example.