Ui componentsJs snippet

Intelligent Form (JS)

Add an intelligent form UI directly on a dedicated page

Overview

The Intelligent Form component is designed to help deflect support tickets at creation time in a tasteful way.

If the AI is confident, it'll attempt to deflect the user's question prior to ticket creation.

If it's not confident - it can still be helpful by taking a user's input and prefilling other parts of the form. Useful for simplifying your form while extracting structured information needed by your ticketing platform.

How It Works

  1. Primary Screen: Users enter their initial information (name, email, question/details)
  2. AI Deflection: The AI assistant analyzes the user's input
    • If confident it can help: The user is shown an answer. They can continue to the secondary screen if it doesn't resolve their question.
    • If not confident: User proceeds directly to the secondary screen
  3. Secondary Screen: Contains additional fields to collect structured information
    • These fields can be automatically pre-filled by AI based on the user's initial input
    • User reviews and confirms the information
  4. Submission: When the user submits the form, your custom callback function is triggered
    • Your callback receives all form data and conversation context
    • You can connect this to your ticketing system, CRM, or other backend systems

This flow aims to reduce support tickets in an elegant way that also simplifies the end-user experience.

Quick start

Add the below <script> tag to the <head> or <body> of your website.

<script
  type="module"
  src="https://cdn.jsdelivr.net/npm/@inkeep/cxkit-js@0.5/dist/embed.js"
  defer
></script>

Define an element in your page that will be the "container" for the intelligent form.

<div style="display: flex; align-items: center; justify-content: center; height: calc(100vh - 16px);">
  <div style="height: 480px;">
    <div id="ikp-intelligent-form-target"></div>
  </div>
</div>

Insert the Intelligent Form by using the Inkeep.IntelligentForm() function.

<script type="module">
  const config = {
    baseSettings: {
      apiKey: "YOUR_API_KEY",
    },
    formSettings: {
      primary: {
        fields: [
          {
            label: "Name",
            name: "name",
            inputType: "text",
            isRequired: true,
          },
          {
            label: "Email",
            name: "email",
            inputType: "email",
            isRequired: true,
          },
          {
            label: "How can we help?",
            name: "additionalDetails",
            inputType: "textarea",
            placeholder:
              "Please provide any additional details that may be helpful.",
          },
        ],
      },
      secondary: {
        description: {
          default:
            "To finish submitting your request, please confirm the details below.",
          confident:
            "We found an answer that might help. Please confirm your details to continue.",
        },
        fields: [
          {
            label: "Subject",
            name: "subject",
            inputType: "text",
            isRequired: true,
            shouldPrefillWithAI: true, // Automatically populate based on user's query
          },
          {
            label: "Priority",
            name: "priority",
            inputType: "select",
            isRequired: true,
            shouldPrefillWithAI: true, // Automatically populate based on query context
            items: [
              { label: "High", value: "HIGH" },
              { label: "Medium", value: "MEDIUM" },
              { label: "Low", value: "LOW" },
            ],
          },
        ],
      },
      successView: {
        heading: "Thank you!",
        message: "We'll be in touch soon",
      },
      buttons: {
        submit: {
          label: "Submit",
          onSubmit: async ({ values, conversation }) => {
            // Process form data with your backend system
            console.log("Form submitted:", values, conversation?.id);
          },
        },
      },
    },
  };
 
  // Initialize the widget
  const widget = Inkeep.IntelligentForm("#ikp-intelligent-form-target", config);
</script>

Configuration

PropertyTypeRequiredDescription
baseSettingsobjectYesCore configuration settings. See Base Settings for details.
formSettingsobjectYesForm configuration settings. See below for details.

Form Settings

The formSettings object configures the behavior, layout, and functionality of the Intelligent Form widget. The form is divided into primary and secondary sections, with additional settings for success messages and submission handling.

Configuration Structure

interface IntelligentFormSettings {
  aiAssistantName?: string;
  primary: PrimarySection;
  secondary: SecondarySection;
  successView: IntelligentFormSuccessView;
  buttons: IntelligentFormButtons;
}

Assistant Name

An optional name that's displayed in the form header:

const formSettings = {
  aiAssistantName: "Support Agent",
};

Primary Section

The initial form fields that are always displayed to the user:

interface PrimarySection {
  fields: IntelligentFormField[];
  description?: string;
}
PropertyTypeRequiredDescription
fieldsIntelligentFormField[]YesArray of form fields to display initially
descriptionstringNoOptional description text shown above the fields

Example

{
  primary: {
    fields: [
      {
        label: 'Name',
        name: 'name',
        inputType: 'text',
        isRequired: true,
      },
      {
        label: 'Email',
        name: 'email',
        inputType: 'email',
        isRequired: true,
      },
      {
        label: 'How can we help?',  // This information is processed by the AI assistant
        name: 'additionalDetails',
        inputType: 'textarea',
        placeholder: 'Please provide any additional details that may be helpful.',
      },
    ],
  }
}

Secondary Section

Additional fields that can be conditionally shown, typically used for AI-enhanced form fields:

interface SecondarySection {
  fields: IntelligentFormField[];
  description?:
    | string
    | {
        default: string;  // Used when AI is not confident
        confident: string;  // Used when AI is confident it can help
      };
}
PropertyTypeRequiredDescription
fieldsIntelligentFormField[]YesArray of form fields to display in the secondary section
descriptionstring | DescriptionObjectNoDescription text or object with confidence-based messages

Example

{
  secondary: {
    description: {
      default: 'To finish submitting a support ticket, confirm the fields below and click Submit.',
      confident: 'Understood. Please confirm the below information:',
    },
    fields: [
      {
        label: 'Subject line',
        name: 'subject',
        inputType: 'text',
        isRequired: true,
        description: 'Overview of the issue',
        defaultValue: 'General Inquiry',
        shouldPrefillWithAI: true,  // This field will be automatically populated based on initial input
      },
      {
        label: 'Priority',
        name: 'priority',
        inputType: 'select',
        isRequired: true,
        items: [
          { label: 'Urgent', value: 'URGENT' },
          { label: 'High', value: 'HIGH' },
          { label: 'Medium', value: 'MEDIUM' },
          { label: 'Low', value: 'LOW' },
        ],
        placeholder: 'Select a priority',
        shouldPrefillWithAI: true,  // Priority will be suggested based on the query
      },
    ],
  }
}

Form Fields

All form fields share these common properties:

PropertyTypeRequiredDescription
namestringYesUnique identifier for the field
labelstringYesDisplay label for the field
isRequiredbooleanNoWhether the field is required
isHiddenbooleanNoWhether to hide the field
descriptionstringNoHelper text shown below the field
shouldPrefillWithAIbooleanNoDetermines if the field gets pre-generated by AI based on the user's initial query

Text Field

{
  name: 'name',
  label: 'Full Name',
  inputType: 'text',
  defaultValue?: string,
  placeholder?: string
}

Email Field

{
  name: 'email',
  label: 'Email Address',
  inputType: 'email',
  defaultValue?: string,
  placeholder?: string
}

Textarea Field

{
  name: 'description',
  label: 'Description',
  inputType: 'textarea',
  defaultValue?: string,
  placeholder?: string
}

Checkbox Field

{
  name: 'subscribe',
  label: 'Subscribe to newsletter',
  inputType: 'checkbox',
  defaultValue?: boolean
}

Select Field

{
  name: 'category',
  label: 'Category',
  inputType: 'select',
  items: [
    { label: 'Option 1', value: 'opt1' },
    { label: 'Option 2', value: 'opt2' }
  ],
  defaultValue?: string,
  placeholder?: string
}

File Field

{
  name: 'attachment',
  label: 'Attach File',
  inputType: 'file'
}

When using a file field in your form, you may need to convert the files to Base64 before sending to your backend or an external API, this can be done by using the following snippet.

function convertFilesToBase64(files: FileList) {
  const filesArray = Array.from(files);
  return Promise.all(
    filesArray.map((file) => {
      return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = (event) => {
          const result = (event.target as FileReader).result;
          const base64Data = result.replace(/^data:.+;base64,/, "");
          resolve({
            data: base64Data,
            fileName: file.name,
            mimeType: file.type,
          });
        };
        reader.onerror = (error) => reject(error);
        reader.readAsDataURL(file);
      });
    })
  );
}

Success View

Configuration for the view shown after successful form submission:

interface IntelligentFormSuccessView {
  heading: string;
  message: string;
  icon?: InkeepCustomIcon;
}
PropertyTypeRequiredDescription
headingstringYesSuccess message heading
messagestringYesDetailed success message
iconInkeepCustomIconNoCustom icon to display

Example

{
  successView: {
    heading: 'Thank you!',
    message: "We'll be in touch soon",
  }
}

Button Configuration

The buttons property configures the form's submit button:

{
  buttons: {
    submit: {
      label?: string, // Optional custom label
      onSubmit: async ({ values, conversation }) => {
        // Handle form submission with form values and conversation context
        console.log("Form submitted:", {
          values,
          conversationId: conversation?.id,
        });
      },
    }
  }
}

Complete Example

const formSettings = {
  // Optional name for the AI assistant shown to users
  aiAssistantName: "Support Assistant",
  
  // Primary screen - The first form users interact with
  primary: {
    fields: [
      {
        label: "Name",
        name: "name",
        inputType: "text",
        isRequired: true,
      },
      {
        label: "Email",
        name: "email",
        inputType: "email",
        isRequired: true,
      },
      {
        label: "How can we help?",
        name: "additionalDetails",
        inputType: "textarea",
        placeholder:
          "Please provide any additional details that may be helpful.",
      },
    ],
  },
  
  // Secondary screen - Appears after AI processing
  secondary: {
    description: {
      default:
        "To finish submitting a support ticket, confirm the fields below.",
      confident: "Understood. Please confirm the below information:",
    },
    fields: [
      {
        label: "Subject line",
        name: "subject",
        inputType: "text",
        isRequired: true,
        description: "Overview of the issue",
        defaultValue: "General Inquiry",
        shouldPrefillWithAI: true,
      },
      {
        label: "Priority",
        name: "priority",
        inputType: "select",
        isRequired: true,
        items: [
          { label: "Urgent", value: "URGENT" },
          { label: "High", value: "HIGH" },
          { label: "Medium", value: "MEDIUM" },
          { label: "Low", value: "LOW" },
        ],
        placeholder: "Select a priority",
        shouldPrefillWithAI: true,
      },
      {
        label: "Ticket type",
        name: "ticketType",
        inputType: "select",
        isRequired: true,
        items: [
          { label: "Talk to sales", value: "talk_to_sales" },
          { label: "Issue in production", value: "issue_in_production" },
          { label: "Issue in development", value: "issue_in_development" },
          { label: "Report bug", value: "report_bug" },
          { label: "Onboarding help", value: "onboarding_help" },
          { label: "Account management", value: "account_management" },
          { label: "Feature request", value: "feature_request" },
        ],
        placeholder: "Select a ticket type",
        shouldPrefillWithAI: true,
      },
    ],
  },
  
  // Success view shown after form submission
  successView: {
    heading: "Thank you!",
    message: "We'll be in touch soon",
  },
  
  // Button configuration
  buttons: {
    submit: {
      label: "Submit",
      onSubmit: async ({ values, conversation }) => {
        // Send form data to your backend
        console.log("Form submitted:", {
          values,
          conversationId: conversation?.id,
        });
      },
    },
  },
}; 

Changing props after initial render

Sometimes you may need to manage change settings after a widget has already been initialized, for example, to update user privacy preferences. To do this, you can use the update method.

The below example illustrates how you change the primary color on the widget when a button is clicked.

const colors = [
  "#26D6FF",
  "#e300bd",
  "#512fc9",
  "#fde046",
  "#2ecc71",
  "#e74c3c",
  "#9b59b6",
  "#f1c40f",
];
 
let count = 0;
 
const changeColorButton = document.getElementById("change-color-button");
 
changeColorButton.addEventListener("click", () => {
  count++;
  widget.update({
    baseSettings: {
      primaryBrandColor: colors[count % colors.length],
    },
  });
});