Plugins | Widgets
Give Feedback

Generic Widget

Updated on October 4, 2021

With Generic widgets, you can build a simple, yet powerful widget. A Generic widget is made of one or several sections, each of them containing one or several items.

Use Cases

Built-in items can allow the following use-cases:

  • Open a URL in a modal or a new tab (eg. open the user profile from your internal CRM)
  • Send a request to your API (eg. quickly refund your user, start a debug sequence, etc.)
  • Display and edit data from your API (eg. display the current plan of your user)
Example of a generic widget

Widget Schema

A generic widget is defined as the following (see the full reference):

{
  "version": "1.0",
  "sections": [
    {
      "id": "information",
      "title": "Information",
      "items": [
        // Items…
      ]
    },

    // More sections…
  ]
}
A complete Generic Widget example is available in the Examples.

Sections

Sections serve as groups for items. For a simple widget, you'll likely use only one section, but for a more complex widget, you may want to organize items by category, use-case, etc.

By default, all sections are deployed. Operators can choose to minimize a section by clicking on it. This "minimized" / "deployed" state is saved in permanent storage, meaning that it remains the same after reloading the Crisp app, restarting the browser, etc.

Sections can also be fully hidden with the help of Conditions.

Minimized and deployed sections
For widgets with only one section, the section title will be hidden.

Items

Sections are populated with items. Two types of built-in items exist:

  • button: represents a button, to proceed to various actions from it
  • data: allows to display and edit data from various sources

Button Items

Any button item can have its label and color customized:

{
  // <other properties eluded>

  "value": {
    // <other properties eluded>

    "label": "View account 🔎",
    "color": "blue"
  }
}
Various button items

A button item of type link is a button that opens a link in a new tab. For example, to open an CRM page, to view the full details of a customer's order, etc.

The url property represents the actual URL of the page to open. You can choose to attach additional data to it, and even to build it dynamically.

A button item of type modal is a button that opens a link in a modal, above the Crisp app itself. This allows the user to view another page without having to leave the current conversation. Controls ("Open in new tab", "Close", "Minimize" and "Move" buttons) are available bellow the modal.

The url property represents the actual URL of the page to display. You can choose to attach additional data to it, and even to build it dynamically.

The page displayed in the modal can be an already existing page of yours, for example the user profile from your internal CRM. You can also choose to build custom pages, powered by our widget JS SDK:

A normal-sized modal with some controls

Hook Button Item

A button item of type hook is a button that sends an event to your plugin's action URL, to trigger an internal flow on your side. For example, to quickly refund your user, to start a debug sequence, etc.

View Events for more information.

Submit Button Item

A button item of type submit is a button that sends an event to your plugin's action URL, with all the values of the data items matching the group identifier. This is exclusively built to mimic forms. The submit button item and the data items must belong to the same section.

View Events for more information.

A section acting as a form

Data Item

An item of type data can display data from different sources (eg. static data, Crisp data, data from your API). Supported types are string, number and boolean. Depending on the value property, the behavior of the data item changes. Please refer to the Widget Reference for more details.

Data can also be edited by operators, if you choose to allow it (via the editable property). When editing a data, a "Data Edit" event is immediately sent to the plugin's action URL (unless if the group identifier is set, in that case a "Button" event is sent when the corresponding submit button is clicked).

Various data items

Data Binding

Data binding is a syntax allowing you to access to Crisp data right in your generic widget. This can be pretty handy to dynamically build a button URL, to display a section according to a condition, etc. In other cases, this can eliminate the need for you to make additional requests to our REST API.

The syntax is simple: just wrap the path of the Crisp data you want to access to with a pair of brackets ({}). For example, {conversation.meta.data.order_status} will be replaced by the actual value of the conversation custom data order_status. If the value of that custom data was to change, then {conversation.meta.data.order_status} would be automatically refreshed with the new value.

Data binding also supports comparison operators (==, ===, !=, !==) and logical operators (&&, ||).

See Data Access for the full list of supported data namespaces and properties.

Usages

Conditions

Conditions are used to dynamically hide and show sections and items:

// Example 1: show a section / item only if the conversation custom data or contact custom data `order_id` exists
"condition": "{conversation.meta.data.order_id || conversation.contact_data.order_id}"

// Example 2: show a section / item only if the conversation custom data `order_status` is "finished"
"condition": "{conversation.meta.data.order_status === 'finished'}"

// Example 3: show a section / item only if the conversation custom data `order_status` is "finished" or "pending"
"condition": "{conversation.meta.data.order_status === 'finished' || conversation.meta.data.order_status === 'pending'}"

// Example 4: show a section / item only if the conversation is pending
"condition": "{conversation.state === 'pending'}"

The url property of link and modal button items can be built with data binding inside:

// Example 1: build a button URL with data binding
"url": "https://acme.com/orders/order/{conversation.meta.data.order_id || conversation.contact_data.order_id}/details/"

Button Item / Data Item

Any button item (link, modal, hook and submit) and data item (only when fetching the value) has a data property that can be used to pass additional data along the request (as query parameters). Data binding is supported by this property:

// Example 1: embed various data
"data": {
  "order_status": "{conversation.meta.data.order_status || conversation.contact_data.order_status}",
  "conversation_state": "{conversation.state}",
  "user_verified": "{conversation.is_verified === true}",
  "operator": "{operator.email}"
}

Data Item

The value property of a data item can be bound to Crisp data. This can be useful to show an information that the Crisp app doesn't usually show, to display a specific custom data while having the regular "Visitor Data" widget closed, etc.

// Example 1: display a custom data
"value": "{conversation.meta.data.order_status || conversation.contact_data.order_status}"

// Example 2: display the conversation creation date
"value": "{conversation.created_at}"

Modifiers

Modifiers can be used to alter the way data is rendered:

  • url_encode: whether to URL-encode or not the data. Please note that data is URL-encoded by default when embedded inside the URL of an iFrame Widget, Modal Button Item or Hook Button Item. Usage: {DATA_PATH | url_encode}, {DATA_PATH | url_encode=true}, {DATA_PATH | url_encode=false}.
// Example 1: disable URL-encoding for data embedded inside an iFrame Widget URL
"url": "https://acme.com/widget.html?order_id={conversation.meta.data.order_id | url_encode=false}"

// Example 2: URL-encode the data of a Data Item
"value": "{conversation.created_at | url_encode}"

Events

Two types of events exist: button and action. They occur in the following cases:

Type Item Occurs when… Method Target URL
Button Event Link Button Item …clicking on the button GET The url defined in the button
Button Event Modal Button Item …clicking on the button GET The url defined in the button
Action Event Hook Button Item …clicking on the button POST The plugin's action URL
Action Event Submit Button Item …clicking on the button POST The plugin's action URL
Action Event Data Item …fetching the value (either automatically or manually) POST The plugin's action URL
Action Event Data Item …editing the value POST The plugin's action URL

Attached data

Data is passed along those events, either as query parameters (for GET requests), or as a body payload (for POST requests):

  • Default data:

    • website_id
    • token
  • Optional data:

    • locale: only for Link Button Item and Modal Button Item
    • session_id: only if your plugin has at least one website:conversation:* token scope granted
  • Additional data: You can also pass along your own data, by declaring them in the data property of the corresponding item. The values can be literal strings, or data bindings (see Data binding for more information):

    {
      // <other properties eluded>
    
      "value": {
        // <other properties eluded>
    
        "data": {
          // Literal string
          "seed": "abcde",
    
          // Data binding
          "order_status": "{conversation.meta.data.order_status}"
        }
      }
    }

Button events

Following is an example of a GET request URL (for example, when clicking on a Modal Button Item), with aforementioned query parameters attached to it:

"https://acme.com/widget/modal.html?session_id=session_4396ad07-53d9-47a7-81ba-3b6278bf5fae&website_id=a63d1c82-809d-4ff0-be7b-9c82b24cfcf3&token=c99e0df2-db6f-4b0c-9505-83fcbb2da627&locale=en&seed=abcde&order_status=finished"

Action events

As per the table above, Action events are sent to your plugin's action URL. To configure the action URL of your plugin, go to the Marketplace, then to your plugin, then Settings.

Action event general format

An Action event HTTP POST body is JSON-encoded and formatted as such:

{
  "action"  : {                   // The action type and method (see examples below)
    "type"   : "type",
    "method" : "method"
  },
  "widget"  : {                   // The widget the event occurred in
    "section_id" : "section_id",
    "item_id"    : "item_id"
  },
  "origin"  : {                   // The website and conversation the event occured in
    "website_id" : "website_id",
    "session_id" : "session_id"
  },
  "payload" : {},                 // The event payload (format depends on event type)
  "timestamp" : "timestamp"       // The UNIX timestamp of the event (in milliseconds)
}

Requests will be sent to your server with the Crisp-HooksDeliver 1.0 (+https://crisp.chat) User Agent, so make sure to whitelist it.

Redeliveries attempts

Your server must respond with a 200 HTTP code to such requests, otherwise they will be considered as failed. In such case, further attempts will be done (between 2 and 3 attempts), each spaced several seconds apart (between 10 and 15 seconds). If your server still fails to respond to those additional attempts, the request will be dropped and considered as definitely failed. Information about the current delivery attempt and the maximum number of attempts, are available in the X-Delivery-Attempt-Count and X-Delivery-Attempt-Limit headers.

Verifying events signature

Action Events that are received by your server should be verified before being processed. The secret from your Production Token can be used to verify received Action Events.

The verification algorithm is the same as the one used for Web Hooks, and is described in the Web Hooks Reference.

We recommend using the node-crisp-api library to verify Action Events signatures:

const express = require("express");
const bodyParser = require("body-parser");
const Crisp = require("crisp-api");

// Configuration
const SECRET = "<your_web_hooks_secret_here>";

// Create the Crisp client (it lets you access both the REST API and RTM events)
var CrispClient = new Crisp();

// Configure your Crisp authentication tokens ('plugin' token)
CrispClient.authenticateTier("plugin", "<token_identifier>", "<token_key>");

// Context
const app = express();
const port = 3997;

app.use(bodyParser.json());

// Handlers
app.post("/", (request, response) => {
  response.sendStatus(200);

  console.log(
    `<-- ${request.protocol}://${request.get("host")}${request.originalUrl}\n`,
    request.body
  );

  let _timestamp = request.headers["x-crisp-request-timestamp"],
      _signature = request.headers["x-crisp-signature"];

  // Verify signature
  let _verified = CrispClient.verifyWidget(
    SECRET, request.body, _timestamp, _signature
  );

  console.log(
    `${_signature} |remote| <- SIGNATURE -> |local| (hidden)`, _verified
  );
});

// Initializers
app.listen(port, () => {
  console.log(`Hooks server listening at http://localhost:${port}`);
});

Action event examples

Hook Button Item

{
  "action": {
    "type": "button",
    "method": null
  },

  "widget": {
    "section_id": "section_information",
    "item_id": "item_button_hook"
  },

  "origin": {
    "website_id": "a63d1c82-809d-4ff0-be7b-9c82b24cfcf3",
    "session_id": "session_4396ad07-53d9-47a7-81ba-3b6278bf5fae"
  },

  "payload": {
    "data": {
      "seed": "abcde",
      "order_status": "finished"
    }
  },

  "timestamp": 1633625955045
}

Submit Button Item

{
  "action": {
    "type": "button",
    "method": null
  },

  "widget": {
    "section_id": "section_information",
    "item_id": "item_button_submit"
  },

  "origin": {
    "website_id": "a63d1c82-809d-4ff0-be7b-9c82b24cfcf3",
    "session_id": "session_4396ad07-53d9-47a7-81ba-3b6278bf5fae"
  },

  "payload": {
    "value": {
      "data_user_creation_date": "new value",
      "data_user_id": "new value"
    },

    "data": {
      "seed": "abcde",
      "order_status": "finished"
    }
  },

  "timestamp": 1633625955045
}

Data Item (Fetch)

{
  "action": {
    "type": "data",
    "method": "fetch"
  },

  "widget": {
    "section_id": "section_information",
    "item_id": "item_data"
  },

  "origin": {
    "website_id": "a63d1c82-809d-4ff0-be7b-9c82b24cfcf3",
    "session_id": "session_4396ad07-53d9-47a7-81ba-3b6278bf5fae"
  },

  "payload": {
    "data": {
      "seed": "abcde",
      "order_status": "finished"
    }
  },

  "timestamp": 1633625955045
}

For this request, your server must respond with a 200 HTTP code and a response body, containing the data that was requested. Supported data types are string, number and boolean:

{
  "data": {
    "value": "my item value"
  }
}

Data Item (Edit)

{
  "action": {
    "type": "data",
    "method": "edit"
  },

  "widget": {
    "section_id": "section_information",
    "item_id": "item_data"
  },

  "origin": {
    "website_id": "a63d1c82-809d-4ff0-be7b-9c82b24cfcf3",
    "session_id": "session_4396ad07-53d9-47a7-81ba-3b6278bf5fae"
  },

  "payload": {
    "value": "new value"
  },

  "timestamp": 1633625955045
}
A complete Generic Widget example is available in the Examples.