Custom call handling logic with the Dynamics CRM USD generic listener

I was recently working on a Dynamics CRM Unified Service Desk project where I needed to populate a custom search form with call details instead of doing a direct search for a matching record in CRM. I didn't want to write my own CTI adapter, so I investigated using the USD generic listener adapter. Although the USD generic listener is designed to only search CRM records, I developed a workaround to route the inbound call values to a custom HTML web resource that could process them using JavaScript.

  1. Create an action to open a custom HTML web resource that reads values from a query string and processes them appropriately with JavaScript. Note that the query string here includes the output of a scriptlet, which is addressed in the following step.

  2. It's possible that the phone system might send special characters that could "break" a query string, so you should use a scriptlet like this to create a urlencoded string instead of passing them directly to your custom page. This scriptlet generates a query string containing the caller's Social Security number and phone number.

  3. Create a CTI navigation rule to execute a search just like usual.

  4. Make sure your search will never return a match. The search in this screenshot searches accounts for a phonenumber that starts with "nevermatch."

  5. In the "no matches" condition for your CTI navigation rule, set the decision to "Create Session then Do Action" or just "Do Action" and execute the action you created in step #1.

Finally, is here sample code from my HTML web resource to parse the query string and extract inbound call values. In this case I am just displaying the values to the user with jQuery, but this can be modified to address your specific use case.

<html>
<head>
	<script src="ClientGlobalContext.js.aspx" type="text/javascript"></script>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
	<script>
	function getParameterByName(name, url) {
		if (!url) url = window.location.href;
		name = name.replace(/[\[\]]/g, "\\__aSyNcId_<_bpCi_Hzj__amp;");
		var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
			results = regex.exec(url);
		if (!results) return null;
		if (!results[2]) return '';
		return decodeURIComponent(results[2].replace(/\+/g, " "));
	}

	function doPageLoad() {
		var ani = "";
		var ssn = "";
		var datavalue = getParameterByName('data');
		if(datavalue != null){
			var params = decodeURIComponent(datavalue).split("&");
			for (var i in params) {
				params[i] = params[i].replace(/\+/g, " ").split("=");
				if (params[i][0] == "ani") {
					ani = params[i][1];
				}
				if (params[i][0] == "ssn") {
					ssn = params[i][1];
				}
			}
		}
		$('#ani').text(ani);
		$('#ssn').text(ssn);
	}
	
	$().ready(function() {
		doPageLoad();
	});
	</script>
</head>
<body>
ANI: <span id='ani'></span><br />
SSN: <span id='ssn'></span><br />
</body>
</html>