selfhost.directory

The index of self-hostable projects — ranked, categorized and served with live updates.
Own your data and stop giving it to big tech.

ChatbotX logo

Self-host ChatbotX

v1.16.0

Omnichannel chat-marketing platform with flows and AI agents

ReleaseOpen CoreOther
Updated10 hours ago
LanguageTypescript
Setup difficultyAdvanced
Stars
1 041
CPU
4 vCPUs
RAM
4 GB
Ports
3000 (Builder web app (health endpoint /api/health); the docs compose publishes it as 3123:3000 so the UI opens at http://localhost:3123), 1999 (Realtime / PartySocket WebSocket server)
Requires
PostgreSQL with pgvector, Redis
Docker
ghcr.io/chatbotxio/chatbotx-builder
Install with Docker Compose
AI agents and the flow builderLive chat inbox and team managementBroadcasts and sequencesGrowth tools screenImporting contacts

What is ChatbotX?

Should you self-host ChatbotX?

ChatbotX scores 52/100 on selfhost.directory (how scoring works) and ranks #9 of 12 in Marketing Automation. It has 1 041 GitHub stars.

It shipped 10 stable releases in the past year. The latest, v1.16.0, came out on 24 October 2026. New versions land roughly every 4 days.

Setup is advanced: plan for several services and some ongoing maintenance. An official Docker image is available. It is Other-licensed and written mostly in Typescript.

Its closest alternative on selfhost.directory is wacrm (57/100, 2 627 stars). It scores higher overall, so compare the two before you pick. See ChatbotX vs wacrm side by side.

Features

  • A/B Testing
  • AI Agents
  • Analytics
  • Broadcast messaging
  • Comment automation
  • Comment-to-DM
  • Contact CRM
  • Drip sequences
  • Growth tools
  • Live chat inbox
  • Omnichannel messaging channels
  • REST API, CLI, and MCP server
  • Rich messaging
  • Team ManagementFull RBAC is Enterprise Edition only
  • Visual flow builder

ChatbotX README

How to install ChatbotX

Install ChatbotX with Docker Compose

git clone https://github.com/chatbotxio/chatbotx-docker-compose.git

Then run:

docker compose -p chatbotx up

Pre-built ghcr.io images; the app is then reachable at http://localhost:3123

How to configure ChatbotX

  • AUTH_DISABLE_SIGNUPDisable self-service account creation. Valid invitation links remain usable.

    Disable self-service account creation. Valid invitation links remain usable.

  • AUTH_OAUTH_AUTH_URLAdvanced: use only when the provider does not expose OIDC Discovery. Both authorization and token endpoints are required; userinfo is optional.

    Advanced: use only when the provider does not expose OIDC Discovery. Both authorization and token endpoints are required; userinfo is optional.

  • AUTH_OAUTH_CLIENT_ID
  • AUTH_OAUTH_CLIENT_SECRET
  • AUTH_OAUTH_DISCOVERY_URL
  • AUTH_OAUTH_ENABLEDOptional single OIDC/OAuth 2.0 provider for enterprise deployments. Enable only with a valid enterprise license and complete provider credentials. Recommended: OIDC Discovery. This is the smallest supported configuration: enable flag + client id + client secret + discovery URL. It discovers the authorization, token, and userinfo endpoints automatically.

    Optional single OIDC/OAuth 2.0 provider for enterprise deployments. Enable only with a valid enterprise license and complete provider credentials. Recommended: OIDC Discovery. This is the smallest supported configuration: enable flag + client id + client secret + discovery URL. It discovers the authorization, token, and userinfo endpoints automatically.

  • AUTH_OAUTH_SCOPESComma-separated OAuth scopes. Defaults to openid,email,profile.

    Comma-separated OAuth scopes. Defaults to openid,email,profile.

  • AUTH_OAUTH_TOKEN_URL
  • AUTH_OAUTH_TRUST_EMAILTrust an IdP that omits email_verified to link an existing account. This weakens account-linking verification; leave false unless the IdP is trusted.

    Trust an IdP that omits email_verified to link an existing account. This weakens account-linking verification; leave false unless the IdP is trusted.

  • AUTH_OAUTH_USERINFO_URL
  • BETTER_AUTH_SECRET───────────────────────────────────────────── Authentication ───────────────────────────────────────────── Secret used to sign sessions and tokens. Must be a 32-byte base64 string. Generate with: openssl rand -base64 32

    ───────────────────────────────────────────── Authentication ───────────────────────────────────────────── Secret used to sign sessions and tokens. Must be a 32-byte base64 string. Generate with: openssl rand -base64 32

  • BETTER_AUTH_URLhttp://localhost:3123Public URL of the builder app (used for OAuth redirects and email links).

    Public URL of the builder app (used for OAuth redirects and email links).

  • CHAT_WORKER_CONCURRENCY
  • DATABASE_URLpostgresql://chatbotx:secretkey@localhost:5432/chatbotx?schema=public───────────────────────────────────────────── Database ─────────────────────────────────────────────

    ───────────────────────────────────────────── Database ─────────────────────────────────────────────

  • ENABLE_MESSAGE_SHARDING───────────────────────────────────────────── Message Sharding (optional — for horizontal scaling) ───────────────────────────────────────────── Set to "true" to enable sharded message storage.

    ───────────────────────────────────────────── Message Sharding (optional — for horizontal scaling) ───────────────────────────────────────────── Set to "true" to enable sharded message storage.

  • ENCRYPTION_KEY───────────────────────────────────────────── Encryption ───────────────────────────────────────────── Active 32-byte key (hex, 64 chars) used to encrypt developer-app secrets at rest. Generate with: openssl rand -hex 32 MUST be overridden in production.

    ───────────────────────────────────────────── Encryption ───────────────────────────────────────────── Active 32-byte key (hex, 64 chars) used to encrypt developer-app secrets at rest. Generate with: openssl rand -hex 32 MUST be overridden in production.

  • EXPO_ACCESS_TOKEN
  • EXPO_PUSH_ENABLEDExpo Push Service. Expo needs no credential to send, so EXPO_PUSH_ENABLED is the explicit kill switch (defaults to true). EXPO_ACCESS_TOKEN is only needed if Expo's "enhanced push security" is enabled on the project.

    Expo Push Service. Expo needs no credential to send, so EXPO_PUSH_ENABLED is the explicit kill switch (defaults to true). EXPO_ACCESS_TOKEN is only needed if Expo's "enhanced push security" is enabled on the project.

  • FACEBOOK_BUSINESS_AI_APP_ID───────────────────────────────────────────── Messenger conversation routing ───────────────────────────────────────────── App id of the automated-assistant app a Messenger conversation is handed back to ("return to bot"). Unset = return-to-bot is refused and a hand-back to this app never starts the handover resume flow.

    ───────────────────────────────────────────── Messenger conversation routing ───────────────────────────────────────────── App id of the automated-assistant app a Messenger conversation is handed back to ("return to bot"). Unset = return-to-bot is refused and a hand-back to this app never starts the handover resume flow.

  • FORCE_PUBLIC_HTTPSForce generated public URLs to use HTTPS. This does not configure TLS or redirect incoming HTTP traffic.

    Force generated public URLs to use HTTPS. This does not configure TLS or redirect incoming HTTP traffic.

  • INTEGRATION_WORKER_CONCURRENCYIntegration containers are memory-constrained (~2GB each in an 8-per-16GB-host layout) and share the queue with heavy coexist sync jobs; keep this modest.

    Integration containers are memory-constrained (~2GB each in an 8-per-16GB-host layout) and share the queue with heavy coexist sync jobs; keep this modest.

  • JAVASCRIPT_EXECUTOR_TOKENStatic bearer token shared only by workers and the executor (minimum 32 chars). MUST be overridden in production.

    Static bearer token shared only by workers and the executor (minimum 32 chars). MUST be overridden in production.

  • JAVASCRIPT_EXECUTOR_URLhttp://localhost:3210───────────────────────────────────────────── JavaScript Executor ───────────────────────────────────────────── Internal HTTP endpoint used by workers to run execute-javascript flow steps.

    ───────────────────────────────────────────── JavaScript Executor ───────────────────────────────────────────── Internal HTTP endpoint used by workers to run execute-javascript flow steps.

  • LICENSE_KEYRequired when NEXT_PUBLIC_EDITION=enterprise | cloud. See docs/licensing.md. The signed license token issued by the vendor. Verified fully offline against the public key baked into the app. It anchors this deployment's license identity.

    Required when NEXT_PUBLIC_EDITION=enterprise | cloud. See docs/licensing.md. The signed license token issued by the vendor. Verified fully offline against the public key baked into the app. It anchors this deployment's license identity.

  • LICENSE_REFRESH_ENABLEDSet false for air-gapped installs that use a long-lived offline token.

    Set false for air-gapped installs that use a long-lived offline token.

  • LICENSE_REFRESH_URLVendor endpoint used by the hourly online license refresh.

    Vendor endpoint used by the hourly online license refresh.

  • LIVE_AVATAR_LAZY_CHANNELSmessenger,instagramSame for contact profile pictures: not downloaded when the contact is created, fetched the first time something needs the picture.

    Same for contact profile pictures: not downloaded when the contact is created, fetched the first time something needs the picture.

  • LIVE_MEDIA_LAZY_CHANNELSmessenger,instagramChannels whose webhook keeps the provider's media URL instead of downloading the media (comma separated). The bytes are downloaded, re-encoded and stored the first time the inbox, an AI reader or a flow needs them; until then the provider must still serve them, so unsent/revoked media is lost for good. Empty = download at webhook time everywhere. Applies to media on the provider's own CDN only; st

    Channels whose webhook keeps the provider's media URL instead of downloading the media (comma separated). The bytes are downloaded, re-encoded and stored the first time the inbox, an AI reader or a flow needs them; until then the provider must still serve them, so unsent/revoked media is lost for good. Empty = download at webhook time everywhere. Applies to media on the provider's own CDN only; st

  • LOG_DEBUGfalsePromotes opt-in diagnostic lines (e.g. sanitized webhook request bodies) from debug to info, so they survive LOG_LEVEL=info in production without turning on every other debug line. Enable briefly; log content may include redacted customer data.

    Promotes opt-in diagnostic lines (e.g. sanitized webhook request bodies) from debug to info, so they survive LOG_LEVEL=info in production without turning on every other debug line. Enable briefly; log content may include redacted customer data.

  • LOG_LEVELdebug───────────────────────────────────────────── Logging ───────────────────────────────────────────── Log verbosity: error | warn | info | debug

    ───────────────────────────────────────────── Logging ───────────────────────────────────────────── Log verbosity: error | warn | info | debug

  • MAX_CONCURRENCYMaximum isolated-vm executions handled concurrently by one executor process. Keep this aligned with the executor's CPU allocation (the dev stack uses 2).

    Maximum isolated-vm executions handled concurrently by one executor process. Keep this aligned with the executor's CPU allocation (the dev stack uses 2).

  • MESSAGE_SHARDS_PASSWORDShared password for all shard connections (overridden per-shard if needed).

    Shared password for all shard connections (overridden per-shard if needed).

  • MESSAGE_SHARDS_SSLSet to "true" to require SSL on shard connections.

    Set to "true" to require SSL on shard connections.

  • NEXT_PUBLIC_AUTH_OAUTH_DISPLAY_NAMEThe sign-in button defaults to "SSO"; its logo is optional.

    The sign-in button defaults to "SSO"; its logo is optional.

  • NEXT_PUBLIC_AUTH_OAUTH_LOGO_URL
  • NEXT_PUBLIC_BROKER_URLOptional: dedicated, brand-neutral broker host (GHL/LeadConnector-style). The canonical provider-facing origin for BOTH OAuth redirect_uris AND host-validated webhooks (WhatsApp/Meta, TikTok) — providers cannot reach a white-label custom domain. This is the SINGLE redirect_uri you register with every OAuth provider (Google/Facebook SSO, TikTok, Google Sheets, …). All white-label callbacks land her

    Optional: dedicated, brand-neutral broker host (GHL/LeadConnector-style). The canonical provider-facing origin for BOTH OAuth redirect_uris AND host-validated webhooks (WhatsApp/Meta, TikTok) — providers cannot reach a white-label custom domain. This is the SINGLE redirect_uri you register with every OAuth provider (Google/Facebook SSO, TikTok, Google Sheets, …). All white-label callbacks land her

  • NEXT_PUBLIC_BUILDER_URLhttp://localhost:3123───────────────────────────────────────────── Public URLs (Next.js) ───────────────────────────────────────────── Canonical public URL of the builder app.

    ───────────────────────────────────────────── Public URLs (Next.js) ───────────────────────────────────────────── Canonical public URL of the builder app.

  • NEXT_PUBLIC_EDITIONcommunity───────────────────────────────────────────── App Edition ───────────────────────────────────────────── community | enterprise | cloud

    ───────────────────────────────────────────── App Edition ───────────────────────────────────────────── community | enterprise | cloud

  • NEXT_PUBLIC_INTERNAL_STORAGE_URLOptional: override the storage base URL used by the browser. Defaults to the S3_ENDPOINT value resolved server-side. Useful when the storage service is reachable under a different host locally.

    Optional: override the storage base URL used by the browser. Defaults to the S3_ENDPOINT value resolved server-side. Useful when the storage service is reachable under a different host locally.

  • NEXT_PUBLIC_PANCAKE_CHAT_PAGE_IDOptional: Pancake chat page id for the builder app support widget. Only renders on the canonical NEXT_PUBLIC_BUILDER_URL domain.

    Optional: Pancake chat page id for the builder app support widget. Only renders on the canonical NEXT_PUBLIC_BUILDER_URL domain.

  • NEXT_PUBLIC_STORAGE_URLOptional: public-facing storage domain (e.g. CDN, external S3 proxy, or whitelabel storage). When set, all public file URLs are served from this domain instead of <APP_URL>/storage/. Per-user overrides can also be set via PlatformSetting.storageUrl in the database.

    Optional: public-facing storage domain (e.g. CDN, external S3 proxy, or whitelabel storage). When set, all public file URLs are served from this domain instead of <APP_URL>/storage/. Per-user overrides can also be set via PlatformSetting.storageUrl in the database.

  • NODE_OPTIONSIncrease Node.js heap for large workloads. Set per-process, not globally.

    Increase Node.js heap for large workloads. Set per-process, not globally.

  • NOTIFICATION_WORKER_CONCURRENCY
  • PLATFORM_ADMIN_EMAIL───────────────────────────────────────────── Platform Admin ───────────────────────────────────────────── Email address that can access /manage (platform admin UI). Required when NEXT_PUBLIC_EDITION=community or enterprise.

    ───────────────────────────────────────────── Platform Admin ───────────────────────────────────────────── Email address that can access /manage (platform admin UI). Required when NEXT_PUBLIC_EDITION=community or enterprise.

  • PROFILE_SNAPSHOT_JOBS_PER_SECOND
  • QUOTA_MAC_ADMISSION───────────────────────────────────────────── Worker Tuning ───────────────────────────────────────────── MAC admission defaults to the atomic live-counter strategy. Set to lock for operational rollback; atomic and lock may run side by side, so a rolling restart is safe.

    ───────────────────────────────────────────── Worker Tuning ───────────────────────────────────────────── MAC admission defaults to the atomic live-counter strategy. Set to lock for operational rollback; atomic and lock may run side by side, so a rolling restart is safe.

  • REALTIME_BROADCAST_SECRETHMAC secret shared between builder and realtime to sign/verify short-lived (60s) JWTs. The workspace/guest connect token travels as a `?token=` query param on the WebSocket URL, not a header; `Authorization: Bearer <token>` is used only by the gateway's presence report back to the builder. MUST be overridden in production (minimum 32 characters, or the gateway fails to boot).

    HMAC secret shared between builder and realtime to sign/verify short-lived (60s) JWTs. The workspace/guest connect token travels as a `?token=` query param on the WebSocket URL, not a header; `Authorization: Bearer <token>` is used only by the gateway's presence report back to the builder. MUST be overridden in production (minimum 32 characters, or the gateway fails to boot).

  • REALTIME_CONNECTION_LIFETIME_MSForces every connection to periodically re-handshake (fresh token mint, re-checked membership/permissions) — see docs/realtime.md's close-code table.

    Forces every connection to periodically re-handshake (fresh token mint, re-checked membership/permissions) — see docs/realtime.md's close-code table.

  • REALTIME_MAX_CONNECTIONSPer-process realtime socket cap. Over the cap the gateway closes new connections with code 4003 and a retryAfter hint instead of degrading.

    Per-process realtime socket cap. Over the cap the gateway closes new connections with code 4003 and a retryAfter hint instead of degrading.

  • REALTIME_MAX_CONNECTIONS_PER_GUESTConnections allowed for one guestConversationId.

    Connections allowed for one guestConversationId.

  • REALTIME_MAX_CONNECTIONS_PER_WORKSPACEMember connections allowed for one workspace.

    Member connections allowed for one workspace.

  • REALTIME_MAX_GUEST_CONNECTIONSGuest sub-pool of the total cap above, across the whole server.

    Guest sub-pool of the total cap above, across the whole server.

  • REALTIME_MAX_GUEST_CONNECTIONS_PER_WORKSPACEGuest connections allowed for one workspace, across every guest conversation.

    Guest connections allowed for one workspace, across every guest conversation.

  • REALTIME_PROXY_URLOptional: realtime HTTP proxy target for local development. This value is only used by the builder server.

    Optional: realtime HTTP proxy target for local development. This value is only used by the builder server.

  • REDIS_CACHE_URLSplit Redis per role (optional — each falls back to REDIS_URL if unset). `REDIS_QUEUE_URL` moves the hot queues (integration, chat, notification, low, callTranscription, whatsappVoipSignaling) and the event-bus Streams/plain-KV users sharing the hot connection. `REDIS_SEQUENCE_URL` keeps sequence scheduling separate. Set REDIS_CACHE_URL to route cache reads to a separate VM.

    Split Redis per role (optional — each falls back to REDIS_URL if unset). `REDIS_QUEUE_URL` moves the hot queues (integration, chat, notification, low, callTranscription, whatsappVoipSignaling) and the event-bus Streams/plain-KV users sharing the hot connection. `REDIS_SEQUENCE_URL` keeps sequence scheduling separate. Set REDIS_CACHE_URL to route cache reads to a separate VM.

  • REDIS_QUEUE_BULK_URLSet REDIS_QUEUE_BULK_URL to further split bulk queues (aiAgent, heavy, default, schedule, trigger, webhook, quota). It falls back to REDIS_QUEUE_URL, then REDIS_URL. Drain existing bulk jobs and restart every producer/consumer before cutover.

    Set REDIS_QUEUE_BULK_URL to further split bulk queues (aiAgent, heavy, default, schedule, trigger, webhook, quota). It falls back to REDIS_QUEUE_URL, then REDIS_URL. Drain existing bulk jobs and restart every producer/consumer before cutover.

  • REDIS_QUEUE_URL
  • REDIS_SEQUENCE_URL
  • REDIS_URLredis://localhost:6379───────────────────────────────────────────── Redis ─────────────────────────────────────────────

    ───────────────────────────────────────────── Redis ─────────────────────────────────────────────

  • S3_ACCESS_KEY_ID───────────────────────────────────────────── S3 / Object Storage ─────────────────────────────────────────────

    ───────────────────────────────────────────── S3 / Object Storage ─────────────────────────────────────────────

  • S3_BUCKETchatbotx
  • S3_ENDPOINThttp://localhost:9000Custom endpoint for S3-compatible storage (e.g. RustFS, MinIO). Leave unset to use AWS S3.

    Custom endpoint for S3-compatible storage (e.g. RustFS, MinIO). Leave unset to use AWS S3.

  • S3_REGIONus-west-2
  • S3_SECRET_ACCESS_KEY
  • SCHEDULER_BUCKET_RANGE0-255───────────────────────────────────────────── Scheduler & Runtime ───────────────────────────────────────────── Hex range of sequence-scheduler buckets this instance handles (0-255).

    ───────────────────────────────────────────── Scheduler & Runtime ───────────────────────────────────────────── Hex range of sequence-scheduler buckets this instance handles (0-255).

  • SMTP_FROMno-reply@localhost
  • SMTP_SERVERsmtp://username:password@localhost:1025───────────────────────────────────────────── SMTP / Email ───────────────────────────────────────────── Connection URL: smtp[s]://user:pass@host:port

    ───────────────────────────────────────────── SMTP / Email ───────────────────────────────────────────── Connection URL: smtp[s]://user:pass@host:port

  • SNOWFLAKE_PLACE_IDSnowflake ID place id (0-15). Every process that writes to the database (builder, each worker replica, realtime, mcp) should get a DIFFERENT value so two processes minting an id in the same millisecond cannot collide. Unset → a random slot in 1-15 is drawn at startup (0 is reserved for pre-fix processes so a rolling deploy never overlaps them).

    Snowflake ID place id (0-15). Every process that writes to the database (builder, each worker replica, realtime, mcp) should get a DIFFERENT value so two processes minting an id in the same millisecond cannot collide. Unset → a random slot in 1-15 is drawn at startup (0 is reserved for pre-fix processes so a rolling deploy never overlaps them).

  • STORED_IMAGE_AVATAR_MAX_DIMENSION
  • STORED_IMAGE_AVATAR_MIN_SAVING_PERCENT
  • STORED_IMAGE_AVATAR_QUALITY
  • STORED_IMAGE_ENCODE_TIMEOUT_SECONDS
  • STORED_IMAGE_INLINE_AVATAR_MAX_MEGAPIXELS
  • STORED_IMAGE_INLINE_CONCURRENCY
  • STORED_IMAGE_INLINE_MAX_MBInline encoding limits; anything larger goes to the background job. Concurrency is per process; 0 leaves every image to the job.

    Inline encoding limits; anything larger goes to the background job. Concurrency is per process; 0 leaves every image to the job.

  • STORED_IMAGE_INLINE_MAX_MEGAPIXELS
  • STORED_IMAGE_JOB_MAX_SOURCE_MB
  • STORED_IMAGE_JOB_MIN_SOURCE_KBBackground job: skip attachments under the floor and sources over the ceiling.

    Background job: skip attachments under the floor and sources over the ceiling.

  • STORED_IMAGE_MAX_INPUT_MEGAPIXELSLarger images are never decoded (memory guard); slow encodes give up.

    Larger images are never decoded (memory guard); slow encodes give up.

  • STORED_IMAGE_MEDIA_MAX_DIMENSIONTuning (defaults shown). Longest side in px, quality 1-100, and the minimum saving (%) for the re-encode to replace the original.

    Tuning (defaults shown). Longest side in px, quality 1-100, and the minimum saving (%) for the re-encode to replace the original.

  • STORED_IMAGE_MEDIA_MIN_SAVING_PERCENT
  • STORED_IMAGE_MEDIA_QUALITY
  • STORED_IMAGE_OPTIMIZATIONonStored media Re-encode received photos (JPEG) and contact avatars (WebP) to cut object-storage size: inline before the first write when the image is small, otherwise by a background job. Images sent as files keep their original. "off" stops both and makes queued jobs no-ops; objects already stored are left as they are.

    Stored media Re-encode received photos (JPEG) and contact avatars (WebP) to cut object-storage size: inline before the first write when the image is small, otherwise by a background job. Images sent as files keep their original. "off" stops both and makes queued jobs no-ops; objects already stored are left as they are.

  • SUPPORT_ACCESS_REQUIRE_CONSENTRequire each workspace owner to opt in before platform admins can access it. Enterprise deployments can set false to grant platform admins support access to every workspace. Community deployments always require consent.

    Require each workspace owner to opt in before platform admins can access it. Enterprise deployments can set false to grant platform admins support access to every workspace. Community deployments always require consent.

  • TURN_STATIC_SECRET
  • TURN_URL───────────────────────────────────────────── In-app WhatsApp calling (VoIP) ───────────────────────────────────────────── TURN relay. Required for real calls — without it media never flows and Meta ends the call as failed. Must be publicly reachable over UDP; localhost and HTTP tunnels cannot work. coturn REST/HMAC (`use-auth-secret`) only. See docs/whatsapp-calling-voip.md.

    ───────────────────────────────────────────── In-app WhatsApp calling (VoIP) ───────────────────────────────────────────── TURN relay. Required for real calls — without it media never flows and Meta ends the call as failed. Must be publicly reachable over UDP; localhost and HTTP tunnels cannot work. coturn REST/HMAC (`use-auth-secret`) only. See docs/whatsapp-calling-voip.md.

  • WEBHOOK_WORKER_CONCURRENCYWebhook and integration handling are I/O-bound; other workers use their default.

    Webhook and integration handling are I/O-bound; other workers use their default.

ChatbotX releases & version history

More in Marketing Automation

Rate this project

Click to rate — no account needed.

0 comments

Posting as guest
Loading comments…