This guide explains how to create custom integration applications for the tawk.to platform. An application consists of two main files that reside in the same directory:
app.js: Defines the application's behavior, configuration schema, and authentication methods.metadata.json: Provides the content, text, and assets for the application's catalog listing.
To use the validation tools included in this kit, install the development dependencies:
npm installThe app.js file is the core of your integration. It must export a class that extends one of the provided base classes.
The runtime environment provides the following base classes via aliased requires. You do not need to install these packages; they are available globally in the integration environment.
-
App:require('@apps/domain/entities/app')The generic base class for all applications. Use this for most standard integrations. -
McpApp:require('@apps/domain/entities/mcp-app')A specialized base class for Model Context Protocol (MCP) servers. Use this if you are building an integration that exposes tools or resources via the MCP standard.
Your class must define specific static properties and methods.
'use strict';
const App = require('@apps/domain/entities/app');
class MyCustomApp extends App {
// -------------------------------------------------------------------------
// Static Properties (Metadata)
// -------------------------------------------------------------------------
// Display name in the catalog
static name = 'My Custom App';
/**
* categories: Classification for the catalog.
* Available values:
* - 'messaging': Channels like WhatsApp, Messenger
* - 'e-commerce': Shopping carts (Shopify, WooCommerce)
* - 'cms': Content Management Systems (WordPress, Drupal)
* - 'custom-tool': Generic tools or API integrations
*/
static categories = ['custom-tool'];
/**
* features: Capabilities the app provides.
* Available values:
* - 'toolkit': Exposes tools for AI/Automation
*/
static features = ['toolkit'];
// UI Labels (leave empty)
static uiLabels = [];
// Whether only one instance of this app can be installed per property
static singleton = false;
// -------------------------------------------------------------------------
// Configuration Schemas
// -------------------------------------------------------------------------
/**
* configSchema: Defines the "Configuration" step of the installation wizard.
* Uses JSON Schema with custom annotations for UI rendering.
*
* NOTE: This schema generates the actual input form users fill out.
*/
static configSchema = {
type: 'object',
properties: {
url: {
type: 'string',
'@title': 'Server URL',
'@placeholder': 'https://api.example.com',
'pattern': '^https?://' // Standard JSON Schema validation is supported
}
},
required: ['url']
};
/**
* authSchemas: Defines the "Authentication" step.
* A map where keys are auth types (e.g., 'basic', 'bearer') and values are schemas.
*/
static authSchemas = {
none: {
type: 'object',
additionalProperties: false
},
basic: {
type: 'object',
properties: {
username: {
type: 'string',
'@title': 'Username'
},
password: {
type: 'string',
'@title': 'Password',
'@sensitive': true
}
},
required: ['username', 'password']
}
};
// -------------------------------------------------------------------------
// Lifecycle Methods
// -------------------------------------------------------------------------
/**
* getClient: Factory method to create an API client for your service.
*
* @param {Object} params
* @param {Object} params.config - The validated configuration object (from configSchema)
* @param {String} params.authType - The user-selected authentication method key (e.g., 'basic')
* @param {Object} params.authParams - The validated authentication credentials (from authSchemas)
* @returns {Object} A client instance capable of communicating with your service.
*/
static getClient(params) {
const { config, authType, authParams } = params;
// Example: Return a custom client instance.
// You can use any HTTP client (e.g., axios, node-fetch) or a custom SDK.
// return new MyApiClient(config.url, authParams);
// If extending McpApp, you can use the helper:
/*
return McpApp._getClient({
url: config.url,
headers: McpApp._getAuthHeaders(authType, authParams)
});
*/
// NOTE: The client object you return here will be used by the platform to execute
// actions (like tools). If using McpApp, the base class handles this for you.
return {};
}
/**
* getTools: (Required if features includes 'toolkit')
* Discovers available tools from the external service.
*
* NOTE: If you are extending McpApp, this method is already implemented for you.
* Do NOT override it unless you need to change the default behavior.
*
* @param {Object} params
* @param {Object} params.client - The client instance returned by getClient()
* @returns {Promise<Object>} A map of tools where keys are unique Tool IDs.
*
* Return Structure:
* {
* "send-email": {
* "name": "send-email",
* "title": "Send Email",
* "description": "Sends an email to a recipient",
* "inputSchema": {
* "type": "object",
* "properties": {
* "to": { "type": "string" },
* "subject": { "type": "string" }
* },
* "required": ["to"]
* },
* "outputSchema": { // Optional but recommended
* "type": "object",
* "properties": {
* "success": { "type": "boolean" }
* }
* }
* }
* }
*/
static async getTools(params) {
const { client } = params;
// For custom toolkit apps, fetch and map your tools here.
return {};
}
/**
* callTool: (Required if features includes 'toolkit')
* Executes a specific tool.
*
* NOTE: If you are extending McpApp, this method is already implemented for you.
* Do NOT override it unless you need to change the default behavior.
*
* @param {Object} params
* @param {Object} params.client - The client instance returned by getClient()
* @param {String} params.toolName - The name/ID of the tool to execute
* @param {Object} params.input - The arguments for the tool
* @returns {Promise<Object>} The result of the tool execution
*/
static async callTool(params) {
const { client, toolName, input } = params;
// Example: Execute the tool via your client
// return await client.execute(toolName, input);
return {};
}
}
module.exports = MyCustomApp;We use standard JSON Schema to generate the configuration and authentication forms in the UI. To customize the look and feel, we support specific annotations (properties starting with @).
string: Renders a text input.boolean: Renders a checkbox.number/integer: Renders a number input.object: Renders a nested fieldset.array: Renders a dynamic list where users can add or remove items.- Must include an
itemsschema definition.
- Must include an
| Annotation | Type | Description |
|---|---|---|
@title |
String | The label displayed above the input field. |
@placeholder |
String | The placeholder text shown inside the input field. |
@sensitive |
Boolean | If true, the input renders as a password field (masked), and values are encrypted at rest. |
You can use standard JSON Schema validation keywords such as pattern (regex), minLength, maxLength, minimum, and maximum to enforce data constraints. The UI will use these to provide real-time feedback.
Dropdowns (Enums)
To create a dropdown menu, use the enum property in a string schema.
{
"type": "string",
"enum": ["option_a", "option_b"],
"@title": "Select an Option"
}Key-Value Lists (Array of Objects) To allow users to enter multiple pairs (e.g., Custom Headers), use an array of objects:
{
"type": "array",
"items": {
"type": "object",
"properties": {
"key": { "type": "string", "@title": "Name" },
"val": { "type": "string", "@title": "Value" }
}
}
}The metadata.json file controls how your application appears in the integration catalog. It defines the description, logo, screenshots, and installation guide.
The file must contain a single root object content.
{
"content": {
"shortDescription": "Connect to any MCP server.",
"vendor": {
"name": "tawk.to"
},
"logoImage": {
"type": "asset",
"src": "/images/logos/app-logo.svg"
},
"overview": {
"content": "<p>HTML content describing the app...</p>",
"carouselImages": [
{ "type": "asset", "src": "/images/overview/screen1.jpg" }
]
},
"installation": [
{
"title": "Step 1: Configuration",
"description": "Enter your server URL.",
"images": [
{ "type": "asset", "src": "/images/installation/step1.jpg" }
]
}
],
"resources": []
}
}Note: The installation array here defines the instructional text shown to the user in the catalog (e.g., "Step 1: Get your API Key"). It is purely informational. The actual form fields are generated from the configSchema in app.js.
Images (logos, screenshots, installation guides) must be stored locally relative to your app.js file.
Important: The only supported resource type for images is "asset".
- Create a directory structure:
assets/images/. - Place your images inside (e.g.,
assets/images/logos/my-logo.svg). - Reference them in
metadata.jsonusing the prefix/images/.
Mapping Example:
| File System Path | Metadata Reference |
|---|---|
assets/images/logos/icon.svg |
/images/logos/icon.svg |
assets/images/overview/shot1.jpg |
/images/overview/shot1.jpg |
assets/images/installation/step1.jpg |
/images/installation/step1.jpg |
shortDescription: A brief summary (max 1-2 sentences) shown on the catalog card.vendor: Object containingname(String).logoImage: Object withtype: "asset"andsrcpath to the logo.overview:content: Full HTML description of the application.carouselImages: Array of asset objects ({ "type": "asset", "src": "..." }) for screenshots.
installation: Array of objects defining the setup steps.title: Step title.description: Step instructions (supports HTML).images: Array of asset objects ({ "type": "asset", "src": "..." }).
resources: (Optional) Array of objects for external links.label: Link text.url: External URL.
The Application Dev Kit includes a test suite to validate your application's structure and ensure it complies with the platform's requirements before submission.
To test your application, run the following command from the root of the Dev Kit:
npm test -- --dir path/to/your/appExample:
npm test -- --dir examples/basic-appThe test suite performs a static analysis and contract check of your app.js file:
- Structure: Verifies that your app extends the provided base classes correctly.
- Metadata: Checks that all required static properties (
name,categories,features) are present and have the correct data types. - Schemas: Validates that
configSchemaandauthSchemasare valid JSON objects. - Methods: Ensures required lifecycle methods (
getClient,getTools) are defined.
Note on Imports:
The test environment automatically creates aliases for the platform modules. You can leave your require('@apps/domain/entities/app') statements as-is; they will resolve correctly during local testing.
Once your application is ready for review:
- Zip your application folder (containing
app.js,metadata.json, and theassetsfolder). - Send the zip file to your tawk.to Point of Contact (PIC).
- Our team will review your configuration and schemas, and provide feedback on the next steps for publishing.