Part 4: Deploy & Customize Webchat

This final part will walk through how to deploy your agent to a website and do advanced customization to the webchat widget!

Skills Gained

  • Adding custom CSS
  • Adding custom forms & Extensions

Deploy a Voiceflow Agent to a Website (5 min)

Part 4.1 will show you how to add your Voiceflow agent to a website. We use Webflow in this example but this will work with any website builder you are using (including custom code)


Add Proactive Message Bubbles (4 min)

Part 4.2 will walk you through how to add proactive message bubbles to your widget. This helps increasing engagement on your agent.

Full documentation is in Embed and Customize Styling

<script type="text/javascript">
  (function(d, t) {
      var v = d.createElement(t), s = d.getElementsByTagName(t)[0];
      v.onload = function() {
        window.voiceflow.chat.load({
          verify: { projectID: 'PROJECT_ID' },
          url: 'https://general-runtime.voiceflow.com',
          versionID: 'production'
        }).then(() => {
          window.voiceflow.chat.proactive.clear(); // clear all previous messages
          window.voiceflow.chat.proactive.push({ 
            type: 'text', 
            payload: { message: 'Are you interested in some 🔥🔥🔥 sneakers?' }
          }, { 
            type: 'text', 
            payload: { message: 'Click on the chat to learn more!' }
          });
        });
      };
      v.src = "https://cdn.voiceflow.com/widget/bundle.mjs"; 
      v.type = "text/javascript"; 
      s.parentNode.insertBefore(v, s);
  })(document, 'script');
</script>

Use Custom CSS to match your branding (3 min)

Part 4.3 goes over how you can use custom CSS to fully customize everything in your Webchat to have it fully match your brand.

Full documentation is in Embed and Customize Styling

<script type="text/javascript">
  (function(d, t) {
      var v = d.createElement(t), s = d.getElementsByTagName(t)[0];
      v.onload = function() {
        window.voiceflow.chat.load({
          verify: { projectID: 'PROJECT_ID' },
          url: 'https://general-runtime.voiceflow.com',
          versionID: 'production',
          assistant: {
            stylesheet: "data:text/css;base64,LnZmcmMtc3lzdGVtLXJlc3BvbnNlIC52ZnJjLW1lc3NhZ2UgeyBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwMDAwOyBjb2xvcjogI0ZGRkZGRjsgfQ==" // link to your self-hosted stylesheet
          }
        });
      };
      v.src = "https://cdn.voiceflow.com/widget/bundle.mjs"; 
      v.type = "text/javascript"; 
      s.parentNode.insertBefore(v, s);
  })(document, 'script');
</script>

Add a Custom Form to your agent with Extensions (11 min)

Part 4.4 walks you through the most powerful feature we have for Webchat - extensions. This lets you render any custom items like forms, file upload, calendar pickers, authentication, logins, etc natively in your agent.

You can find a more advanced example where we make a seat picker for an airline agent here.

Full documentation is in Custom Forms and Extensions

You will need to add the extension before the webchat widget code in your website body. An overview is below:

<script>
  	//Extension
</script>

<script
	//Webchat widget
</script>

Here is the full example

//First add the extension code, ensure that it is wrapped in <script> so it will render in the website.
//Alternatively you can add it in a JS file and just import it
<script>
const FormExtension = {
  name: 'Forms',
  type: 'response',
  match: ({ trace }) =>
    trace.type === 'Custom_Form' || trace.payload.name === 'Custom_Form',
  render: ({ trace, element }) => {
    const formContainer = document.createElement('form');

    formContainer.innerHTML = `
      <style>
        label {
          font-size: 0.8em;
          color: #888;
        }
        input[type="text"], input[type="email"], input[type="tel"] {
          width: 100%;
          border: none;
          border-bottom: 0.5px solid rgba(0, 0, 0, 0.1);
          background: transparent;
          margin: 5px 0;
          outline: none;
          padding: 8px 0; /* Added some padding for better UX */
        }
        .phone {
          width: 150px;
        }
        .invalid {
          border-color: red;
        }
        .submit {
          background: linear-gradient(to right, #2e6ee1, #2e7ff1);
          border: none;
          color: white;
          padding: 10px;
          border-radius: 5px;
          width: 100%;
          cursor: pointer;
        }
      </style>

      <label for="name">Name</label>
      <input type="text" class="name" name="name" required><br><br>

      <label for="email">Email</label>
      <input type="email" class="email" name="email" required pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$" title="Invalid email address"><br><br>

      <label for="phone">Phone Number</label>
      <input type="tel" class="phone" name="phone" required pattern="\\d+" title="Invalid phone number, please enter only numbers"><br><br>

      <input type="submit" class="submit" value="Submit">
    `;

    formContainer.addEventListener('input', function () {
      // Remove 'invalid' class when input becomes valid
      const name = formContainer.querySelector('.name');
      const email = formContainer.querySelector('.email');
      const phone = formContainer.querySelector('.phone');

      if (name.checkValidity()) name.classList.remove('invalid');
      if (email.checkValidity()) email.classList.remove('invalid');
      if (phone.checkValidity()) phone.classList.remove('invalid');
    });

    formContainer.addEventListener('submit', function (event) {
      event.preventDefault();

      const name = formContainer.querySelector('.name');
      const email = formContainer.querySelector('.email');
      const phone = formContainer.querySelector('.phone');

      if (
        !name.checkValidity() ||
        !email.checkValidity() ||
        !phone.checkValidity()
      ) {
        name.classList.add('invalid');
        email.classList.add('invalid');
        phone.classList.add('invalid');
        return;
      }

      formContainer.querySelector('.submit').remove();

      window.voiceflow.chat.interact({
        type: 'complete',
        payload: { name: name.value, email: email.value, phone: phone.value },
      });
    });

    element.appendChild(formContainer);
  },
};
</script>

//After the widget you can add your widget code. Remember to add the add the assistant + extension section with the extension name
<script type="text/javascript">
  (function(d, t) {
      var v = d.createElement(t), s = d.getElementsByTagName(t)[0];
      v.onload = function() {
        window.voiceflow.chat.load({
          verify: { projectID: 'PROJECT_ID' },
          url: 'https://general-runtime.voiceflow.com',
          versionID: 'production',
          assistant: {
            //stylesheet: "data:text/css;base64,LnZmcmMtc3lzdGVtLXJlc3BvbnNlIC52ZnJjLW1lc3NhZ2UgeyBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwMDAwOyBjb2xvcjogI0ZGRkZGRjsgfQ==",// link to your self-hosted stylesheet
            extensions: [FormExtension]
          }
        }).then(() => {
          window.voiceflow.chat.proactive.clear(); // clear all previous messages
          window.voiceflow.chat.proactive.push({ 
            type: 'text', 
            payload: { message: 'Are you interested in some 🔥🔥🔥 sneakers?' }
          }, { 
            type: 'text', 
            payload: { message: 'Click on the chat to learn more!' }
          });

          // Open the chat after 1 second
          setTimeout(function () {
            window.voiceflow.chat.open();
          }, 1000);
        });
      };
      v.src = "https://cdn.voiceflow.com/widget/bundle.mjs"; 
      v.type = "text/javascript"; 
      s.parentNode.insertBefore(v, s);
  })(document, 'script');
</script>

Trigger the Agent to open automatically on a Website

This final part (4.5) explains how to trigger your agent to open automatically after a customer is on a page in your website for more than a few seconds. This capability is customizable so that you can open your agent at the time and place that will best help your customers.

Full documentation can be found in Custom Triggers

window.voiceflow.chat.load({
  verify: { projectID: "PROJECT_ID" },
  url: "https://general-runtime.voiceflow.com",
  versionID: "production"
}).then(() => {
  setTimeout(function () {
    window.voiceflow.chat.open();
  }, 1000)
});

Final Webchat Widget Code

Here is what the final version of our Webchat code in the last video looked like,

  1. CSS override to turn the buttons black and white
  2. Uses an extension for a custom form (the extension itself is above this script on the website)
  3. Adds two proactive message bubbles above the chat
  4. Opens automatically after the customer is on the page for more than 5 seconds
<script type="text/javascript">
  (function(d, t) {
      var v = d.createElement(t), s = d.getElementsByTagName(t)[0];
      v.onload = function() {
        window.voiceflow.chat.load({
          verify: { projectID: 'PROJECT_ID' },
          url: 'https://general-runtime.voiceflow.com',
          versionID: 'production',
          assistant: {
            stylesheet: "data:text/css;base64,LnZmcmMtc3lzdGVtLXJlc3BvbnNlIC52ZnJjLW1lc3NhZ2UgeyBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwMDAwOyBjb2xvcjogI0ZGRkZGRjsgfQ==",// link to your self-hosted stylesheet
            extensions: [FormExtension]
          }
        }).then(() => {
          window.voiceflow.chat.proactive.clear(); // clear all previous messages
          window.voiceflow.chat.proactive.push({ 
            type: 'text', 
            payload: { message: 'Are you interested in some 🔥🔥🔥 sneakers?' }
          }, { 
            type: 'text', 
            payload: { message: 'Click on the chat to learn more!' }
          });

          // Open the chat after 5 seconds
          setTimeout(function () {
            window.voiceflow.chat.open();
          }, 5000);
        });
      };
      v.src = "https://cdn.voiceflow.com/widget/bundle.mjs"; 
      v.type = "text/javascript"; 
      s.parentNode.insertBefore(v, s);
  })(document, 'script');
</script>

Get the template

You can download the template shown in the videos here!