A starter template for building custom apps that run inside Rechat's CRM platform.
Rechat allows third-party developers to build custom UIs that are embedded directly into its CRM. Your app is hosted on your own server and loaded into Rechat via an iframe-like integration.
The key concept: your app does not bundle its own React or UI libraries. Instead, Rechat injects them at runtime. This means your bundle stays small, and your UI is visually consistent with the rest of the CRM.
At runtime, Rechat loads your app's JavaScript bundle and calls its default export, passing in:
- React, Material-UI, and react-use libraries (available via
window.libs) - Data models like the current
contactanduser - API functions like
updateContact()andclose() - UI Components provided by Rechat (email composer, date picker, wizard forms, etc.)
- Utility functions like
notify()for showing toast notifications - Hooks for wizard form state management
Your app receives all of this through a single EntryProps object and renders its UI using the injected libraries.
app/ # Frontend source code
index.tsx # Entry point — receives injected props from Rechat
App.tsx # Main application component
core/libs/ # Wrappers that access injected libraries from window.libs
react.ts # React
material-ui.ts # Material-UI
react-use.ts # react-use
core/utils/ # Utilities (component factory, etc.)
components/ # Your custom components
static/ # Icons and logos
server/ # Express.js backend
main.ts # Server entry point
routes.ts # Route definitions
app/controllers/ # Route controllers
types/ # TypeScript type definitions
core.d.ts # EntryProps interface and component types
models/ # Data model types (User, Contact, CRM tasks, etc.)
components/ # Prop types for injected components
.configuration/ # Build tooling
webpack/ # Webpack configs (base, dev, production)
build/ # Production build script
update-manifest/ # Manifest timestamp updater
manifest.json # App metadata — required by Rechat
Every Rechat app must expose a manifest.json at its root URL. This tells Rechat about your app:
{
"name": "My Contact App",
"icon": "./static/icon.png",
"version": "1.0.0",
"build": "1653421766",
"inputs": [],
"size": "md"
}| Field | Description |
|---|---|
name |
Display name shown in Rechat |
icon |
Path to the app icon |
version |
Semantic version of your app |
build |
Unique build identifier (auto-updated on each build) |
inputs |
Input configurations required by the app |
size |
UI size: sm, md, or lg |
The build value is used to reference your bundle file (bundle.<build>.js), so Rechat always loads the correct version.
Your app's compiled output is a single ES module (bundle.<build>.js). Rechat imports it and calls the default export, passing in all the injected dependencies:
// This is what Rechat does internally (simplified):
const app = await import(`https://your-app.com/bundle.1653421766.js`)
app.default({
models: { contact, user },
api: { updateContact, close },
utils: { notify },
hooks: { wizard: { useSectionContext, useWizardContext, useSectionErrorContext } },
Components: { Logo, DatePicker, SingleEmailComposeForm, Wizard }
})Your entry point (app/index.tsx) receives these props and renders your app:
export default function Bootstrap({ Components, ...props }: EntryProps) {
return <App Components={createComponents(Components)} {...props} />
}Since React, Material-UI, and react-use are provided by the host platform, you do not import them from node_modules. Instead, use the wrapper modules:
import React from '@libs/react'
import Ui from '@libs/material-ui'
import ReactUse from '@libs/react-use'These read from window.libs, which Rechat populates before loading your bundle.
The libraries are listed in
package.jsonfor TypeScript type-checking only. They are not included in your bundle.
Your app's default export receives an EntryProps object:
interface EntryProps {
models: {
contact: IContact // The CRM contact being viewed
user: IUser // The logged-in Rechat user
}
api: {
updateContact: (contact: IContact) => Promise<void> // Save contact changes
close: () => void // Close the app panel
}
utils: {
notify: (data: NotificationData) => void // Show toast notifications
}
hooks: {
wizard: {
useSectionContext: () => IWizardSectionState
useWizardContext: () => IWizardState
useSectionErrorContext: () => Optional<string>
}
}
Components: {
Logo: React.FC
DatePicker: React.FC
SingleEmailComposeForm: React.FC
Wizard: {
QuestionWizard: React.FC
QuestionSection: React.FC
QuestionTitle: React.FC
QuestionForm: React.FC
}
}
}Full type definitions for all models and components are in the types/ directory.
Once your app is registered with Rechat, it shows up on the contact profile page in the CRM. Users see your app's icon and name, and clicking it opens your UI in a panel.
- Node.js 18+
- npm
- Access to a Rechat CRM account
npm installnpm run developThis starts an Express server with Webpack dev middleware and hot reloading on port 8081.
Since your app runs inside Rechat, you can't test it in isolation — you need the actual CRM to provide the injected libraries and data. Rechat has a built-in dev mode for this:
-
Run your local dev server:
npm run develop
-
Open Rechat in your browser and navigate to any contact's profile page.
-
Append
?dev=true&host=localhost:8081to the URL and reload. For example:https://app.rechat.com/dashboard/contacts/61f669de-...?dev=true&host=localhost:8081 -
Now when you click on any app on that contact's profile, Rechat will load it from your local dev server instead of the production URL.
This lets you develop with hot reloading while getting real contact data, real API functions, and the full Rechat runtime environment.
npm run buildThis will:
- Update the
buildtimestamp inmanifest.json - Compile the frontend bundle (
dist-web/bundle.<build>.js) - Compile the server (
dist-server/)
npm startdocker build -t my-rechat-app .
docker run -p 8081:8081 my-rechat-appYour app must be hosted at a publicly accessible URL. Rechat needs to reach two endpoints:
GET /manifest.json- Returns your app's manifestGET /bundle.<build>.js- Returns your compiled bundle (served as a static file)
Once deployed, register your app's URL with Rechat so the platform knows where to load it from.
For questions about app development and integration: emil@rechat.com | ramin@rechat.com
