Overview

January 26, 2026 · View on GitHub

Adding chat to your website is possible with a few easy steps. This solutions spins up an Amazon API Gateway endpoint that triggers an AWS Lambda function. This Lambda function invokes the Amazon Connect Service StartChatContact API and returns the result from that call. Once you have the StartChatContact API you can either pass that response to the prebuilt widget to get a quick implementation going or you can build your own customer chat experience by using the Amazon Connect Chat JS library.

⚠️ This sample code does not come with built in security. It is highly recommended to implement AWS WAF for the API Gateway.

"Diagram"

CloudFormation Deployment Steps

Pre-requisites

You need an Amazon Connect instance to deploy this CloudFormation template. You can use an existing one or create a new one by following our onboarding guide here.

If you are using an existing instance, you may need to make a few changes to your instance to enable Chat. Follow the steps here to see what changes you need to make.

Steps

RegionLaunch Button
us-east-1 (N. Virginia)Launch Stack
us-west-2 (Oregon)Launch Stack
ap-southeast-2 (Sydney)Launch Stack
ap-northeast-1 (Tokyo)Launch Stack
eu-central-1 (Frankfurt)Launch Stack
eu-west-2 (London)Launch Stack
ap-southeast-1 (Singapore)Launch Stack
ca-central-1 (Canada)Launch Stack
ap-northeast-2 (Seoul)Launch Stack
  1. Deploy the CloudFormation template from one of the links above.
    • Enter the Contact Flow id and Instance Id that you would like to test with. These are added as Lambda environment variables.
      • contactFlowId: You can find the contact flow id when viewing a contact flow. For example, if the arn for your flow is 'arn:aws:connect:us-west-2:123456789012:instance/11111111-1111-1111-1111-111111111111/contact-flow/22222222-2222-2222-2222-222222222222', the contact flow id is '22222222-2222-2222-2222-222222222222'
      • instanceId: This is the id of the instance you want to use. You can find this on the Amazon Connect console or when viewing the contact flow. For example, if the arn for your flow is 'arn:aws:connect:us-west-2:123456789012:instance/11111111-1111-1111-1111-111111111111/contact-flow/22222222-2222-2222-2222-222222222222', the instance id is '11111111-1111-1111-1111-111111111111'
  2. Once the stack has launched you can call the API from your website. Follow the steps below to see how you can call this API using our pre-built chat widget or by building out your own UX.

Prebuilt Chat Widget

If you want to add the customer chat widget (that is available in the Test Chat experience in the Amazon Connect website) to your website, here are the steps to do so. You can also refer to the widgetIndex.html file in this repo to see an example of how to use the widget.

Note: you will want to show the widget only when there is a conversation in progress. If the widget is visible when there is no conversation, you will just see a loading spinner.

  1. In your website's html code, import the 'amazon-connect-chat-interface.js' file from this repo. If you want to modify the code in the interface.js file, you can refer to this repo to see its source.

    <script src="amazon-connect-chat-interface.js"></script>
    
  2. Initialize the Chat Interface on page load. Note: you need to update this to include the root id of the div where the customer chat widget will live.

    $(document).ready((a) => {
      connect.ChatInterface.init({
        containerId: 'root', // This is the id of the container where you want the widget to reside
        headerConfig: {      // Use the optional headerConfig and footerConfig to customize your widget
          isHTML: true,
          render: () => {
            return (`<html code here/>`)
          }
        },
        footerConfig: {
          isHTML: true,
          render: () => {
            return (`<html code here/>`)
          }
        }
      });
    });
    
  3. Start the chat based on a user action. You will want to add fields for the customer name, username, and enableAttachments because those fields are used in the Lambda function that was created.

    Note: you need to update this to include the API Gateway endpoint that was created in the CloudFormation stack. To see examples of the success and failure handlers, refer to the example implementation.

    ⚠️ Authentication Notice: Please be aware that this API does not come with built-in authentication. By default, it is accessible to anyone with the API Gateway endpoint. It is imperative to assume responsibility for implementing the necessary authentication mechanisms to secure access to this API.

    connect.ChatInterface.initiateChat({
      name: customerName,
      username: username,
      region: ${region},
      apiGatewayEndpoint: "https://${apiId}.execute-api.${region}.amazonaws.com/Prod",
      contactAttributes: JSON.stringify({
        "customerName": customerName
      }),
      contactFlowId: "${contactFlowId}",
      instanceId: "${instanceId}",
      featurePermissions: {
        "ATTACHMENTS": enableAttachments==='true',  // this is the override flag from user for attachments
        }
    },successHandler, failureHandler)
    

Creating your own Chat UX

If you want to build your own Chat widget instead of using our prebuilt one, follow these step by step directions. If you want to see a complete example of how to use ChatJS, look at the customBuildIndex.html file.

  1. First, you need deploy the backend API as instructed above.
  2. Once your stack is deployed, go to the API Gateway console, select the API, go to the Stages menu item, and select the Prod stage. You will then see the Invoke URL. This is the URL you will invoke to start the chat. api gateway url diagram
  3. Gather the instance ID and contact flow ID you want to use. If you don't have a contact flow, use the Sample inbound flow one in your instance that is created by default. You can find these IDs when viewing a contact flow. For example, if the arn for your flow is arn:aws:connect:us-west-2:123456789012:instance/11111111-1111-1111-1111-111111111111/contact-flow/22222222-2222-2222-2222-222222222222, the instance ID is 11111111-1111-1111-1111-111111111111 and the contact flow ID is 22222222-2222-2222-2222-222222222222 contact flow ids diagram
  4. Download the compiled ChatJS source and save it locally.
  5. Create an index.html file in the same directory as the ChatJS source
  6. Set up your index.html file by importing ChatJS and creating the html elements you will use. These include an entry for the customer's name, a chat content input field, an area for the chat transcript to show up, and buttons to start the chat, get the transcript, send a typing event, and end the chat.
<!DOCTYPE html>
<html>

<head>
    <title></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script type="text/javascript" src="amazon-connect-chat.js"></script>
</head>
<body>
    <div>
        <section class="section-main" id="section-main">
            <header>
                <h1>Amazon Connect - Custom Implementation of Customer Chat</h1>
            </header>

            <form name="contactDetails" id="contactDetails" style="padding-top: 30px; padding: 5px;">
                <div>
                    <table>
                        <tbody>
                            <tr>
                                <td>
                                    <input name="firstName" type="text" id="firstName" placeholder="First Name"
                                        style="width:161px;">
                                </td>
                                <td style="padding-left: 10px;">
                                    <input type="submit" style="padding-left: 10px;" class="submit" id="startChat"
                                        value="Start Chat"></input>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </form>
            
            <div style="padding: 5px;"><textarea type="text" id="chatContent"></textarea></div>
            <div style="padding: 5px;"><input type="button" id="sendChat" value="Send chat"></div>
            <div style="padding-top: 10px; display: inline-flex">
                <div style="padding: 5px;"><input type="button" id="getTranscript" value="Get Transcript"></div>
                <div style="padding: 5px;"><input type="button" id="sendTyping" value="Send typing"></div>
                <div style="padding: 5px;"><input type="button" id="endChat" value="End chat"></div>
            </div>
            <div style="padding: 5px;"><textarea readonly id="chatTranscript"></textarea></div>
        </section>
    </div>

    <script>
    </script>
</body>
  1. Once you have the outline ready, the first step is to set up the chat session. Add the below code to set the global config in the <script> section of your index.html file. You are also creating a global variable, session, that will be initialized at a later step.
var session;

connect.ChatSession.setGlobalConfig({
    region: "us-east-1" // TODO: update with the region your Amazon Connect instance is in
});
  1. Next, you will call the StartChatContact API in the Amazon Connect Service. This call to StartChatContact is made through the API that was deployed by the stack. You need to fill in a few fields here: contact flow id, instance id, and the API Gateway endpoint. Add this code after the function to set the global config.
$(function () {
    $('#contactDetails').submit(function (e) {
        e.preventDefault();

        customerName = $('#firstName').val();
        if (!customerName) {
            alert('you must enter a name');
        } else {
            var contactFlowId = "12345678-1234-1234-1234-123456789012"; // TODO: Fill in
            var instanceId = "12345678-1234-1234-1234-123456789012"; // TODO: Fill in
            var apiGatewayEndpoint = "https://0123456789.execute-api.us-east-1.amazonaws.com/Prod"; // TODO: Fill in 
            
            document.getElementById("contactDetails").reset();

            var initiateChatRequest = {
                ParticipantDetails: {
                    DisplayName: customerName
                },
                ContactFlowId: contactFlowId,
                InstanceId: instanceId
            };

            $.ajax({
                url: apiGatewayEndpoint,
                type: "POST",
                async: false,
                data: JSON.stringify(initiateChatRequest),
                success: function(result) {
                    console.log("Success!");
                    console.log(JSON.stringify(result));
                },
                error: function(result) {
                    console.log("Error:");
                    console.log(result);
                }
            });
        }
    });
});
  1. At this point you can test your implementation by opening your index.html file, entering a name, and clicking Start Chat. If you inspect the console of your browser, you should see a success log.
  2. Now that you can successfully call ACS.StartChatContact(), you need to complete the chat initialization by making a call to ChatJS to establish the chat session. You will do this in the success function after your ajax call to start the chat. Pass the result from the call to start chat to ChatJS and ChatJS will handle the rest of the steps to establish the connection.
success: function(result) {
    console.log("Success!");
    console.log(JSON.stringify(result));
    session = connect.ChatSession.create({
        chatDetails: result.data.startChatResult,
        type: "CUSTOMER"
    });
},
  1. Once the session is created, you need to give function definitions for the APIs available in ChatJS that respond to events and messages. You can define the functions within the complete function after the ajax call. Your ajax call will now look like this:
$.ajax({
    url: apiGatewayEndpoint,
    type: "POST",
    async: false,
    data: JSON.stringify(initiateChatRequest),
    success: function(result) {
        console.log("Success!");
        console.log(JSON.stringify(result));
        session = connect.ChatSession.create({
            chatDetails: result.data.startChatResult,
            type: "CUSTOMER"
        });
    },
    error: function(result) {
        console.log("Error:");
        console.log(result);
    },
    complete: function(data) {
        session.connect().then((response) => {
            console.log("Successful connection: " + JSON.stringify(response));
            return response;
        }, (error) => {
            console.log("Unsuccessful connection " + JSON.stringify(error));
            return Promise.reject(error);
        });

        session.onConnectionEstablished((data) => {
            console.log("Established!");
        })

        session.onMessage((message) => {
            console.log("Received message: " + JSON.stringify(message));
        });

        session.onTyping((typingEvent) => {
            console.log("Received typing event: " + JSON.stringify(typingEvent));
        });

        session.onConnectionBroken((data) => {
            console.log("Connection broken.");
        });
    }
});
  1. Now that the reactive functions have definitions, the final step is to add definitions for all the APIs that can be triggered by the customer. Add this functions under the ajax call within the <script> section.
$(document).ready((a) => {
    $("#sendChat").click(() => { 
        sendChat();
    });

    $("#getTranscript").click(() => { 
        getTranscript();
    });

    $("#endChat").click(() => { 
        endChat();
    });

    $("#sendTyping").click(() => { 
        sendTypingEvent();
    });
});

function sendChat() {
    var message = document.getElementById("chatContent").value;
    console.log("Clicked with message " + message);

    session.controller.sendMessage({
        message: message,
        contentType: "text/plain"
    })
}

function getTranscript() {
    session.getTranscript({
        scanDirection: "BACKWARD",
        sortOrder: "ASCENDING",
        maxResults: 15
    }).then(response => {
        console.log("Current transcript: ");
        console.log(JSON.stringify(response.data.Transcript));
        $('#chatTranscript').text(JSON.stringify(response.data.Transcript));
    });
}

function endChat() {
    session.controller.disconnectParticipant();
}

function sendTypingEvent() {
    session.controller.sendEvent({
        contentType: "application/vnd.amazonaws.connect.event.typing"
    });
}
  1. That's it! Now if you test your index.html file all of the buttons should work and if you inspect the console you will see logs for the events being sent and received through ChatJs.

Enabling interactive messages

If you want to enable interactive messages for Amazon Connect Chat the customer chat widget (that is available in the Test Chat experience in the Amazon Connect website) to your website, read the blog on how to easily set up interactive messages for your Amazon Connect chatbot for detailed instructions.

What are interactive messages for Amazon Connect Chat?

Interactive messages are pre-configured responses that your users can select from, making it easy for your customers to quickly resolve their issues through chat. Interactive messages can be designed using the new Amazon Connect Chat templates, which include several different customer display options like list pickers, list pickers with images, and time pickers. These are sent by Amazon Connect Chat using Amazon Lex chatbots. Interactive messages configured through Lex will be validated in the Amazon Connect contact flow to ensure that they have been configured correctly.

Enabling attachments

If you want to enable sending attachments for Amazon Connect Chat the customer chat widget, follow the instructions in the documentation to enable your Amazon Connect instance for attachments. Once enabled, you can mark the ATTACHMENTS flag in connect.ChatInterface.initiateChat as true. Example below:

    connect.ChatInterface.initiateChat({
      name: customerName,
      username: username,
      region: ${region},
      apiGatewayEndpoint: "https://${apiId}.execute-api.${region}.amazonaws.com/Prod",
      contactAttributes: JSON.stringify({
        "customerName": customerName
      }),
      contactFlowId: "${contactFlowId}",
      instanceId: "${instanceId}",
      featurePermissions: {
        "ATTACHMENTS": true,  // this is the override flag from user for attachments
        }
    },successHandler, failureHandler)

Enabling rich messaging

Amazon Connect Chat now allows your agents and customers to use rich text formatting when composing a message, enabling them to quickly add emphasis and structure to messages, improving comprehension. The available formatting options include bold, italics, hyperlinks, bulleted lists, and numbered lists. Documentation

Using the Pre-built Chat Widget

To enable rich messaging with the pre-built widget, include supportedMessagingContentTypes when invoking initiateChat:

connect.ChatInterface.initiateChat({
  contactFlowId: "${contactFlowId}",
  instanceId: "${instanceId}",
  // ...
  supportedMessagingContentTypes: "text/plain,text/markdown", // include 'text/markdown' for rich messaging support
},successHandler, failureHandler)

Using Custom StartChat Implementation

If you're using a custom Lambda function to call the StartChatContact API (instead of the default CloudFormation template), your Lambda response should include featurePermissions to enable UI features:

1. Update your Lambda to return featurePermissions

function buildFeaturePermissions(body) {
    const featurePermissions = {};
    const supportedMessagingContentTypes = body["SupportedMessagingContentTypes"];
    
    if (supportedMessagingContentTypes && Array.isArray(supportedMessagingContentTypes)) {
        featurePermissions["MESSAGING_MARKDOWN"] = supportedMessagingContentTypes.includes("text/markdown");
    }
    
    // Note: Set ATTACHMENTS based on your Connect instance storage configuration
    // featurePermissions["ATTACHMENTS"] = true; // Uncomment if attachments are enabled
    
    return featurePermissions;
}

function buildSuccessfulResponse(result, featurePermissions) {
    const response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Origin": "*",
            'Content-Type': 'application/json',
            'Access-Control-Allow-Credentials': true,
            'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
        },
        body: JSON.stringify({
            data: {
                startChatResult: result,
                featurePermissions: featurePermissions  // Include featurePermissions in response
            }
        })
    };
    return response;
}

exports.handler = (event, context, callback) => {
    var body = JSON.parse(event["body"]);
    
    startChatContact(body).then((startChatResult) => {
        const featurePermissions = buildFeaturePermissions(body);
        callback(null, buildSuccessfulResponse(startChatResult, featurePermissions));
    }).catch((err) => {
        callback(null, buildResponseFailed(err));
    });
};

2. Ensure supportedMessagingContentTypes is passed to StartChatContact

function startChatContact(body) {
    return new Promise(function (resolve, reject) {
        var startChat = {
            // ...
            ...(!!body["SupportedMessagingContentTypes"] && { "SupportedMessagingContentTypes": body["SupportedMessagingContentTypes"] })
        };
    })
}

Feature Permissions Reference

FeatureDescription
MESSAGING_MARKDOWNEnables rich text formatting toolbar (bold, italic, lists, links, emoji)
ATTACHMENTSEnables file attachment upload/download (requires S3 storage configuration in Connect instance)

Note: If your Lambda doesn't return featurePermissions, rich messaging and attachment features will not be enabled in the widget UI, even if supportedMessagingContentTypes is configured in the snippet.

Enabling message receipts

Render and send read/delivered message receipts for customer chat-interface. Enable the feature in the admin console, and update chat-interface to generate latest webpack bundle.

To customize wait time before sending read/delivered receipt, set the throttle in global config:

connect.ChatSession.setGlobalConfig({
  // ...
  features: {
    messageReceipts: {
      shouldSendMessageReceipts: true,
      throttleTime: 5000 // default throttle time in ms - time to wait before sending 
    }
  }
});

Disable message receipts

By default, message receipts feature is enabled in ChatJs. Disable in chat-interface config and remove from the ChatJs config:

connect.ChatSession.setGlobalConfig({
  // ...
  features: {
    messageReceipts: {
      shouldSendMessageReceipts: false, // default: true
    }
  }
});

Enable persistent chat

Learn more about persistent chat: https://docs.aws.amazon.com/connect/latest/adminguide/chat-persistence.html

You can enable persistent chat in widgetIndex.html.

connect.ChatInterface.initiateChat({
    ...
    persistentChat: {
        rehydrationType: "", // TODO: ENTIRE_PAST_SESSION or FROM_SEGMENT
        // ENTIRE_PAST_SESSION: specify the first contact (initial contactId) of the past chat session as the SourceContactId attribute.
        // FROM_SEGMENT: specify any contactId of the past chat session as the SourceContactId attribute.
        sourceContactId: "" // TODO: Fill in contactId based on rehydrationType
    },
    ...
}, successHandler, failureHandler);

Custom chat duration

Learn more about chat duration: https://docs.aws.amazon.com/connect/latest/APIReference/API_StartChatContact.html#connect-StartChatContact-request-ChatDurationInMinutes

You can set custom chat duration in widgetIndex.html.

connect.ChatInterface.initiateChat({
    ...
    chatDurationInMinutes: 1500, // min 60, max 10080 - default 1500 (25 hours)
    ...
}, successHandler, failureHandler);

Passing Custom Attribute to Contact Flow

When initializing the chat with a StartChatContact request, you can pass custom attributes to the the contact flow.

flowchart LR
    START["Chat Widget
    StartChat Request"] --> B["Lambda (AWS-SDK)
    connect.startChatContact"];
    B --> C["Amazon Connect
    StartChatContact API"];
    C --> END["Amazon Connect
    Contact Flow"];

Reference

Configuration

  1. If using the GitHub AmazonConnectChatWidget, pass in custom contactAttributes to the ChatInterface.initiateChat() method. This will pass "Attributes" key in the request body
// https://github.com/amazon-connect/amazon-connect-chat-interface/blob/master/src/components/Chat/ChatInitiator.js

connect.ChatInterface.initiateChat({
  name: customerName,
  region: ${region},
  contactFlowId: "${contactFlowId}",
  instanceId: "${instanceId}",
  apiGatewayEndpoint: "${apiGatewayEndpoint}",
  contactAttributes: JSON.stringify({
    "customerName": customerName,
    "customAttribute": "myCustomAttribute". // <------ CUSTOM ATTRIBUTE HERE
  }),
  
},successHandler, failureHandler)
  1. Update the lambda making the StartChatContact call, make sure to forward body["Attributes"] to connect.startChatContact()
/*
  Example `startChatContactAPI` lambda making a call to the Amazon Connect public StartChatContact API
  
  LINK: https://github.com/amazon-connect/amazon-connect-chat-ui-examples/blob/master/cloudformationTemplates/startChatContactAPI/js/startChatContact.js

  1) Chat Widget will make request to this Lambda
  2) Lambda will forward the request to the Amazon Connect Backend
*/

var AWS = require('aws-sdk');
AWS.config.update({region: process.env.REGION});
var connect = new AWS.Connect();

exports.handler = (event, context, callback) => {
    console.log("Received event: " + JSON.stringify(event));
    var body = JSON.parse(event["body"]);

    startChatContact(body).then((startChatResult) => {
        callback(null, buildSuccessfulResponse(startChatResult));
    }).catch((err) => {
        console.log("caught error " + err);
        callback(null, buildResponseFailed(err));
    });
};

function startChatContact(body) {
	return new Promise(function (resolve, reject) {
        var startChat = {
            "InstanceId": body["InstanceId"],
            "ContactFlowId": body["contactFlowId"],
            "Attributes": {
                "customerName": body["ParticipantDetails"]["DisplayName"],
                // ...
                ...body["Attributes"] // <------ CUSTOM ATTRIBUTE HERE
            },
            "ParticipantDetails": {
                "DisplayName": body["ParticipantDetails"]["DisplayName"]
            },
        };
        
        // https://docs.aws.amazon.com/connect/latest/APIReference/API_StartChatContact.html
        connect.startChatContact(startChat, function(err, data) {
            if (err) {
                console.log("Error starting the chat.", err);
                reject(err);
            } else {
                console.log("Start chat succeeded with the response: " + JSON.stringify(data));
                resolve(data);
            }
        });
    });
}
  1. Consume the new attribute in the contact flow. Refer to the Admin Guide - "Use Amazon Connect contact attributes"