AWS Contact Center

Keep Your Contact Data Clean by Using Session Attributes in Amazon Connect

Using data to create dynamic experiences is a great way to enhance the customer journey with Amazon Connect. Sometimes though, managing that data across Amazon Connect contact flows or AWS Lambda functions can require a level of data persistence that can lead to unnecessary attributes in the Amazon Connect contact trace records(CTRs). Examples of such data can be text for dynamic text-to-speech (TTS) prompts, language settings, queue names, or functional parameters. This can lead to bloated or confusing data, requiring cleanup before adding to a larger data lake. It can also result in Personally Identifiable Information (PII) persisting in the CTR unintentionally.

By using AWS Lambda, along with the option to pass parameters without writing them to the contact trace record, you can make sure you have access to all of the information you need to ensure a dynamic customer experience without clouding the overall data.

In this article, I’ll go through the following steps to enable session attributes within Amazon Connect contact flows:

  • Modify existing AWS Lambda functions with the example code
  • Configure existing contact flows to pass data appropriately
  • Configure existing contact flows to reference the stored data correctly
  • Validate Lambda function
  • Validate contact trace records

Prerequisites

To complete the steps in this blog, you will need the following resources and permissions:

  • A fully configured Amazon Connect instance
  • An administrator login for Amazon Connect
  • An AWS account with permissions to create new Lambda functions

How this works

When calling an AWS Lambda function from an Amazon Connect contact flow, you have the option to pass along parameters. These parameters are in addition to the standard event data that is sent to Lambda, which includes all the existing contact attributes. The passed parameters are included in the incoming event in the ‘Details’ section, however, they are not written to the contact trace record.

When Lambda returns results, those results are stored in temporary attributes as “External” results. Each new successful execution of Lambda within the same contact flow will overwrite the existing “External” results. In common practice, this leads to users storing Lambda results that they may need later in the flow (but not as a part of the overall contact trace record) as Amazon Connect contact attributes.

This example simplifies the process by making it easy to continually pass along the results of previous Lambda functions and parameters as a consolidated value that is parsed by the Lambda function on execution. The example Lambda function includes logic to take all passed parameters, add them to the response, as well as consolidate both the passed parameters and the execution results into a single flat value that can be easily passed from one function to the next.

Modify existing Lambda functions to use the code example

The core of this solution is a sample Python code that can be added to any Lambda function (written in Python). It will process all incoming parameters as well as handle the processing of the consolidated parameters. You can easily add the code to existing functions or use it as a starting point for new functions. Let’s start with a new function. Here we assume you already have the code.

To use the sample with an existing function

  1. First you’ll need to download the example code.
  2. Once you have the sample code downloaded, open it with your preferred editor.
  3. Log in to your AWS account and open the AWS Lambda Console.
  4. Open the Lambda function that you want  to edit
  5. Scroll down to the Function code section.
  6. In this example, I am using a simple call to the SNS API to send a simple message to a customer from an Amazon Connect contact flow
    import boto3
    
    def lambda_handler(event, context):
        
        client = boto3.client('sns')
        useText = 'Order confirmed.'
        usePhone = event['Details']['ContactData']['CustomerEndpoint']['Address']
    
        try: 
            sns_response = client.publish(
                PhoneNumber=usePhone,
                Message=useText
            )
    
            return {'status':'message_sent'}
            
        except:
            return {'status':'message_fail'}
  7. Add/verify “import json” to the beginning of your function
    import boto3
    import json
    
    def lambda_handler(event, context):
  8. Immediately after the lambda_handler definition, add new line and paste “response = {}”. This creates an empty response object.
    import boto3
    import json
    
    def lambda_handler(event, context):
        
        #Create an empty response
        response = {}
  9. Modify your current response to update the response object. In this example, we return a simple status message. Instead of directly returning that message, add it to the response object.
        try: 
            sns_response = client.publish(
                PhoneNumber=usePhone,
                Message=useText
            )
    
            response.update({'status':'message_sent'})
            
        except:
    
            response.update({'status':'message_fail'})
  10. On a new line, paste: response.update(session_attributes_processor(event,response))
    This adds the results of the Lambda execution to the consolidated session attributes key.

    except:
            response.update({'status':'message_fail'})
            
        response.update(session_attributes_processor(event,response))
  11. On a new line, paste: return response
        except:
            response.update({'status':'message_fail'})
            
        response.update(session_attributes_processor(event,response))
        return response
  12. Now copy the sample code from “def session_attributes_processor(event):” to the end of the code.
  13. On a new line, paste the code
    This code takes the incoming event, parses out any passed parameters, appends them to the response object, then compiles the entire response object into the “session_attributes” key.

    def session_attributes_processor(event,response):
        
        #Establish a new session parameters var
        new_session_parameters = {}
        
        #Write the current response values to the new var
        for k,v in response.items():
            new_session_parameters.update({k : v})
        
        #If any exist, write the passed parameters from Connect to the new var
        if event['Details']['Parameters']:
            for k,v in event['Details']['Parameters'].items():
                new_session_parameters.update({k : v}) 
            
        #If any exist, write the previous session attributes from Connect to the new Var
        if 'session_attributes' in event['Details']['Parameters']:
            new_session_parameters.pop('session_attributes')
            passed_session_attributes = json.loads(event['Details']['Parameters']['session_attributes'].replace('/',''))
            for k,v in passed_session_attributes.items():
                new_session_parameters.update({k : v}) 
    
        #Create a new session attributes key with everything we have
        new_session_parameters.update({'session_attributes': json.dumps(new_session_parameters)})
    
        #Return everything back
        return new_session_parameters
  14. Save the function
  15. Now, when we execute the function and have passed parameters from amazon connect, the response looks like this:
    {
      "status": "message_sent",
      "passed_paramter1": "test value 1",
      "passed_parameter2": "test_value 2",
      "session_attributes": "{\"status\": \"message_sent\", \"passed_paramter1\": \"test value 1\", \"passed_parameter2\": \"test_value 2\"}"
    }
  16. Apply this change to all Lambda functions that will use this example.

Once you have this code in place, you may also want to modify your Lambda functions to use the passed data instead of looking at contact attributes, since you no longer need to store some of the data as attributes. For example, in a standard scenario you might store a retrieved product code to a contact attribute and then use that attribute as a reference to your subsequent lambda function. However, now you can simply reference that same product code from within the response object itself.

Once you have updated the Lambda functions, you will need to update your contact flows to use the session_attibutes value correctly.

Configure existing contact flows to use the New Parameter Feature

Now that your Lambda function can store and retrieve all of the attributes without writing them to the contact trace record, you will need to modify your contact flows to use this function. In any flow that will use this configuration, you will need to add a parameter to all Lambda invocations after the first. In the following example flow, all of the ‘Invoke AWS Lambda’ function blocks outlined in red would need to be modified. Note that the first instance of the Invoke AWS Lambda function is not highlighted.

To modify existing Amazon Connect contact flow Invoke AWS Lambda blocks

  1. Log in to Amazon Connect as an administrator
  2. Navigate to Routing, then choose Contact flows
  3. Select the contact flow that you want to edit
  4. Make sure that all Invoke AWS Lambda function blocks are referencing Lambda functions that have been modified with the code
  5. On all but the first Invoke AWS Lambda, edit the function to pass the following parameter:This will pass the consolidated session_attributes value to the Lambda function, which will process it accordingly.
  6. Save and publish your contact flow.

You have now configured your contact flow to pass the data appropriately. Finally, you will need to adapt your contact flow to use the data stored in the “External” results instead of Attributes.

Configure existing contact flows to Reference Data correctly

Now that your contact flows and Lambda functions are passing all data in the results returned to your Amazon Connect contact flow, you will need to change your flows to reference the data from the results and to remove any unwanted ‘Set contact attribute’ blocks that are no longer necessary. For example, if previously you were setting text for play prompts as contact attributesand then referencing the attribute in the play object, as shown below :

You can now remove the ‘Set contact attributes’ block and, regardless of when you need to reference the data in your flow, you can simply reference the appropriate key in the external results, since every Lambda function will return all previously collected data.

Essentially, anywhere that you were using the User attributes dropdown option to dynamically select data or where you were using $.Attributes.YOURATTRIBUTE, you can now choose the appropriate External attribute or $.External.YOURATTRIBUTE and remove any unwanted Set contact attribute blocks.

Publish the solution and test

Make sure that you have logging enabled for all of your modified contact flows. Save and publish them accordingly. Once you have completed this, you can validate function by calling into your contact flows then referencing the appropriate CloudWatch Logs to validate that the data is passing appropriately. Here is a sample contact flow log showing the successful second Lambda invocation and the associated data:

{
   "ContactId":"XXXXXXXXXXXXXXXXXXXXXXXXXX",
   "ContactFlowId":"arn:aws:connect:us-east-1:XXXXXXXXXX:instance/XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX/contact-flow/XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
   "ContactFlowModuleType":"InvokeExternalResource",
   "Timestamp":"2019-10-03T17:50:26.954Z",
   "ExternalResults":{
      "error_message":"There was an error",
      "random":"3",
      "execution2_result":"sample data 2",
      "execution3_result":"message sent",
      "func":"step1",
      "robot_name":"joanna",
      "country_of_origin":"Thailand",
      "execution1_result":"sample data 1",
      "session_attributes":"{\"country_of_origin\": \"Thailand\", \"func\": \"step1\", \"robot_name\": \"joanna\", \"random\": \"3\", \"birth_year\": \"1974\", \"execution1_result\": \"sample data 1\", \"execution2_result\": \"sample data 2\", \"error_message\": \"There was an error\", \"execution3_result\": \"message sent\"}",
      "birth_year":"1974"
   },
   "Parameters":{
      "FunctionArn":"arn:aws:lambda:us-east-1:XXXXXXXXXX:function:lambda_attribute_handler",
      "Parameters":{
         "func":"step3",
         "robot_name":"joanna",
         "country_of_origin":"Thailand",
         "session_attributes":"{\"country_of_origin\": \"Thailand\", \"func\": \"step1\", \"robot_name\": \"joanna\", \"random\": \"3\", \"birth_year\": \"1974\", \"execution1_result\": \"sample data 1\", \"execution2_result\": \"sample data 2\", \"error_message\": \"There was an error\", \"execution3_result\": \"message sent\"}"
      },
      "TimeLimit":"3000"
   }
}

However, if we look at the results in the contact search, we see that no attributes were written.

Conclusion

In this blog post, we demonstrated a way to continually pass Lambda parameters and results to subsequent Lambda calls from within an Amazon Connect contact flow, reducing the need to write temporary values as contact attributes simply to preserve them for later execution. This will result in fewer data elements written to the contact trace record, keeping your data clean.

Related links

To learn more about the technologies or features I used to build this solution, see the following: