Move to Kommio

Migrating from Chatwoot

Bring a whole Chatwoot account into Kommio: people, inboxes, contacts, every conversation with its messages and files, and your settings. Import ahead of time, keep Chatwoot running, and switch over with a short catch-up.

Last updated

Kommio imports one Chatwoot account at a time: people, teams, inboxes, contacts with their custom attributes, conversations with every message, private note and attachment, labels, business hours, CSAT ratings, canned responses, macros, automation rules, webhooks and the help center. Nothing is sent while importing: no email, reply, webhook, notification, rule, bot or survey runs. You can import ahead of time, keep working in Chatwoot, and move over with a short final catch-up.

There are two ways in, and both use the same importer, so you can mix them:

  • Settings › Import › Import from Chatwoot, for anyone with the imports:manage permission (Administrators by default): connect with a Chatwoot access token and run the dry run, the import and the catch-up from the browser. It works with Chatwoot Cloud and with any Chatwoot that Kommio can reach over the internet.
  • A database import, straight from a copy of Chatwoot's database (or a pg_dump file) and its file storage. It is the fastest way for very large accounts, reaches a Chatwoot on a private network, and carries a few things Chatwoot's API does not expose (see API or database). On Kommio Cloud we run it for you: write to [email protected]. Self-hosted operators run it from the kommio command (below), which can also run the API import (--source-api) from a machine that reaches a Chatwoot on a private network.

Import from the web

  1. Connect

    Enter the address you open Chatwoot at (https://app.chatwoot.com, or your own domain) and an access token: in Chatwoot, open Profile settings (your avatar, bottom left) and copy the Access token at the bottom of the page. It must belong to an administrator of the account. Test the connection lists the token's accounts; pick one and connect. The token is stored encrypted and never shown again, only its last four characters. A Chatwoot on a private network or behind a VPN cannot be reached from Kommio Cloud; use the database import instead.

  2. Choose the options

    Include the help center or not; publish the articles Chatwoot had published (off: they arrive as drafts); copy the website chat's identity secret and the mailbox passwords, which Chatwoot's API shows to administrators; and Only contacts who contacted you, which leaves out contacts with no conversation and no label (silent contacts). With the identity secret, signed-in visitors keep their history without a change to your server's signing key.

  3. Dry run

    Required before the first import. It reads everything and writes nothing, and shows the counts per kind of record, everything that cannot be mapped, and the attachments that are missing.

  4. Import

    Runs in the background (you can leave the page) with live counts and a Cancel button. Cancelling keeps what was imported, and starting again continues from there. One import runs per workspace at a time.

  5. Catch up and switch

    At cut-over, stop working in Chatwoot, press Catch up now to bring over what changed since the import, deletions included (see catching up), and follow the checklist on the page, which is the cut-over below. After the switch, catch up only with Only new records switched on (after the switch).

People who already use this Kommio server through another workspace are not added by a self-serve import; the report lists them so you can invite them from Settings › Team.

API or database

Chatwoot's API does not expose everything its database holds. The differences:

Database importFrom the web (API)
Former agents, no longer in the accountCreated as disabled members, their messages linked to themNot listed; their messages keep their name
Contact nameFirst, middle and last nameThe name field only
Contacts without email, phone or identifierListedThose with a conversation are fetched with it
Leaving out silent contactsFiltered in the database query, so they are never readThe conversations are listed once first to learn who has one, then the rest of the contact listing is skipped
Edits without new activity (a message edit, a contact edited on its own)Picked up by a catch-upPicked up once the conversation or contact has new activity
Messages deleted outright in ChatwootDeleted in Kommio tooNot found (the API cannot list them)
Deleted contacts and conversationsFound by comparing idsFound by paging through the whole account, which is slower on large accounts
Resolution time of a resolved conversationWhen its status changedIts last update
Creation times of inboxes, teams, macros, webhooks, articlesKeptNot exposed
Help center articlesEvery languageThe languages the portal lists
Mailbox passwords Chatwoot encryptedCannot be read (enter them again)Read
Agents' passwordsCan be carried (below)Not exposed: "Forgot password" or an invitation

Conversations imported one way and caught up the other are matched by their Chatwoot number, so a web import followed by a database catch-up never duplicates anything.

What you find in Kommio

  • Conversations keep their status, priority, assignee, team, labels (as tags), timestamps and every message, private note, activity line and attachment, in order. Kommio numbers conversations itself; the Chatwoot number is kept in the attribute chatwoot_display_id, so a saved view filtered on it finds #1234. Messages that were unread stay unread. Reports are rebuilt from the imported history.
  • People are members of the workspace, disabled, and nobody is emailed. Someone already on the Kommio server with the same email is linked instead. Chatwoot administrators get the Administrator role and agents the Agent role; a custom role is reported and becomes Agent.
  • Automation rules arrive switched off and webhooks paused, with a new signing secret; the report and each rule's description say what did not map. Chatwoot's events become the matching Kommio triggers, and "conversation opened" becomes "A conversation is reopened". Chatwoot also fires "opened" when a pending or snoozed conversation turns open; Kommio's trigger does not, since those are not reopens. "Remove assigned team" becomes the Remove team action.
  • Macros and rules keep every step that does something. A label that only a macro or rule names (Chatwoot lets a macro apply a label it has no label record for) becomes a tag by name, noted in the report. A step that assigns an agent or team deleted in Chatwoot, or removes a label no conversation carries, did nothing there and is left out with a warning; a rule lists its left-out steps in its description. A macro or rule that sends a webhook keeps that step and sends Kommio's signed payload (receivers verify Kommio's signature); a URL Kommio's outbound policy refuses, such as a private address or plain http, is left out with the URL and the reason in the report, to fix under Automation › Macros. A macro or rule whose every step is left out is skipped and reported.
  • Email inboxes are paused, so Kommio does not read the mailbox while Chatwoot still does. A mailbox Chatwoot read with Microsoft or Google sign-in arrives waiting for that sign-in, with its address and provider: at cut-over you only sign in (email inboxes). Chatwoot's own tokens are never copied.
  • Telegram and SMS inboxes and channels Kommio does not connect yet (WhatsApp, Facebook, Instagram, LINE and others) arrive as read-only history inboxes: every conversation is there, and replies are refused until the channel is connected. A Telegram history inbox becomes live when you give it the bot's token (Telegram), and returning customers land on their imported contact.
  • Custom attributes keep their names, types and values. None is marked as personal data, but the report lists those whose name looks like an ID, passport, tax, bank, IBAN, card or account number, so you can tag them before agents start work.
  • Images are cleaned of their location and other metadata before they are stored, like every upload (files and storage), and their previews fill in over the hours after a large import.

Every run, with its report, is listed in Settings › Import. Imports are safe to run again: every Chatwoot record is recorded against what it became in Kommio, so a rerun skips what is unchanged and updates what changed, and a run that stopped resumes where it stopped.

Silent contacts: only those who contacted you

A Chatwoot website widget creates a contact for every signed-in user the moment they load a page, so a site that identifies all its users fills the account with contacts who never wrote; on busy sites they can be 99 percent of all contacts, and every catch-up adds the new ones. Only contacts who contacted you in the wizard, --skip-silent-contacts on the command line, leaves them out. For a website that identifies every logged-in user, switch it on before the first import.

  • Silent means no conversation and no label in the Chatwoot account. A conversation is what the import is for, and a label is something a person put on the contact on purpose, so either one keeps a contact. Contact notes do not count: the import does not carry them. Anonymous visitors are left out as before, whatever this option says.
  • A skipped contact who writes later is imported with that conversation, by the next catch-up, with their attributes and identities like any other contact, or linked to a Kommio contact with the same email, phone or identifier.
  • The choice is remembered per Chatwoot account and Kommio workspace: a catch-up applies the last run's choice without the flag, so a delta cannot flip it by accident, and the wizard's toggle shows the remembered value. --include-silent-contacts turns it off again; passing both flags is refused.
  • Contacts imported before you switched it on stay as they are: a silent contact is neither created nor updated, mapped or not. Removing the ones already imported is a separate decision. A skipped contact was never brought over, so it is never a deletion and never counts at the mass-delete safety valve.
  • The report counts them as skipped_silent under the contacts' skipped count, says whether the choice came from the flag or was remembered, and counts the contacts imported with their first conversation.

Cut-over

  1. Stop working in Chatwoot

    Tell the team, and stop answering, closing and assigning in Chatwoot for the few minutes the switch takes.

  2. Catch up

    Catch up now in the wizard, or a database catch-up. Read its report, especially what it changed, which Kommio edits it overwrote and what is gone from the source, before you switch. This is the last full catch-up: once agents work in Kommio, only --only-new catches up.

  3. Switch the website snippet

    Replace Chatwoot's loader with Kommio's (Settings › Inboxes › the website inbox › Install) and change the sign-in call as described below.

    <!-- remove the Chatwoot loader (window.chatwootSettings / chatwootSDK.run) -->
    <script src="https://app.kommio.io/widget/widget.js" data-key="INBOX_PUBLIC_KEY" async></script>
  4. Resume the email inboxes

    Check each email inbox's settings and resume it. An inbox that used Microsoft or Google sign-in shows Connect with Microsoft (or Google): sign in with the account that has access to the mailbox, then resume it. If Chatwoot received mail by forwarding, point the forwarding at the mailbox Kommio reads.

  5. Enable the people

    Enable members in Settings › Team. With carried passwords they sign in with their Chatwoot password; otherwise they use "Forgot password", or you send an invitation.

  6. Switch on rules, webhooks and assignment

    Turn on the rules and webhooks you want, and auto-assignment on the teams that should receive conversations (it starts off). Integrations that used Chatwoot's API move to Kommio's API with a new API key, and webhook receivers verify Kommio's signature.

  7. After the switch, only new records

    If something still reaches Chatwoot after the switch (a late email, a visitor on a cached page), catch it up with --delta --only-new, or Only new records in the wizard: it creates new records only and never changes what agents did in Kommio (details).

Catching up: what it carries

A catch-up brings everything that changed in Chatwoot since the last successful run and, like every run, sends nothing. It starts a few minutes before the previous run started, so a record saved while that run was reading is read again rather than missed. Catch-ups only run when you start them; nothing syncs on its own.

Changed in ChatwootIn Kommio
New conversations, messages, contacts, ratingsCreated
A conversation's status, priority, assignee, team, snooze or attributesUpdated field by field
A label added or removedThe tag is added or removed; only tags the import added are ever removed
A contact's name, company, blocked state, attributes, email, phone, identifier or labelsUpdated; an attribute or identity the import set and Chatwoot no longer has is removed. With Only contacts who contacted you, a contact with no conversation and no label is left alone
A silent contact's first conversationThe contact is created with it, or linked to a Kommio contact with the same email, phone or identifier
Two contacts mergedMerged in Kommio too, with their conversations
A message edited, or deleted with Chatwoot's delete buttonUpdated; a deleted one reads "This message was deleted" and loses its files
Teams, inboxes, labels, attribute definitions, canned responses, macros, rules, webhooks, help centerUpdated
An agent's role, name or emailRole and name are updated; email (and a carried password) only on logins the import created that nobody has used
An agent removed from the accountDisabled in the workspace (never the owner or someone who was a member before the import)

Deletions are mirrored

Every imported record that is gone from Chatwoot is removed from Kommio by the next catch-up, through Kommio's own delete paths and without sending anything, and listed in the report under Gone from the source. A deleted contact's personal data is erased; conversations and messages go with their files; canned responses, macros, rules, webhooks and teams are deleted; a tag or an attribute definition only when nothing uses it any more. Inboxes and help centers are listed, never deleted: delete them yourself when you no longer need their history. A contact skipped as silent was never brought over, so it is never a deletion. If Chatwoot cannot be read for a kind of record, nothing of that kind is deleted.

Deletions are found before anything is written, by comparing the ids Chatwoot still has with what was imported. A database catch-up compares contacts, conversations and messages per range of 10,000 ids by their count and a fingerprint of the ids, so only the ranges that differ are listed one by one; smaller kinds, and every kind through the API, are listed in full.

Chatwoot is the source of truth

Until you switch, Chatwoot's version always wins. A catch-up applies everything that changed in Chatwoot, including over edits someone made in Kommio to a record the import brought over, and the report lists each one under Kommio edits overwritten with both values, so you can redo the ones you still want. Conversations, settings and people are compared field by field (a field only Kommio changed keeps Kommio's value); contacts, messages and articles as a whole. A record deleted in Chatwoot is deleted even when it was edited in Kommio.

What Kommio owns is never overwritten or deleted, because it is not a version of a Chatwoot record: replies, notes, conversations, contacts and tags created in Kommio (an imported conversation that got replies, notes or tags in Kommio is kept when Chatwoot deletes it); the cut-over switches, whether a rule, webhook or inbox is on, auto-assignment, and an email inbox's Microsoft or Google sign-in; and credentials, which change only on imported logins nobody has used.

After the switch: only new records

Once agents work in Kommio, Chatwoot's copy of every imported conversation is out of date, and a plain catch-up would overwrite a status an agent changed, an assignment or a contact they edited with Chatwoot's stale version. So do not run a plain catch-up after agents start working in Kommio, and the importer checks it for you: before writing anything, a plain catch-up counts the conversations and messages created in Kommio since the last plain run (replies, notes, conversations started in Kommio: the sign the team works there). If there are any, it stops, writes nothing, and its report gives the counts and what to do; a dry run reports the same counts as a note instead of stopping. The Only new records catch-ups below neither run the check nor move the point it counts from, so a plain catch-up a week after the switch still finds everything done since.

For the rollback case, where Chatwoot becomes the source of truth again, or a catch-up before the switch over a reply someone made early, Allow overwriting work done in Kommio in the wizard's catch-up step (--allow-overwrite-kommio-work on the command line) runs it anyway, and the report notes the override. Edits to imported records, and contacts, tags and settings changed in Kommio, are not counted: the catch-up's report lists the edits it overwrites, as above.

If something still reached Chatwoot after the switch, catch it up with Only new records in the wizard, or:

kommio import chatwoot --source-account 1 --account-email [email protected] \
  --storage-dir /mnt/chatwoot/storage --delta --only-new

It creates what is new in Chatwoot since the last run (conversations, contacts, messages, ratings, settings, articles) and adds new messages to the conversations they belong to, and it never updates or deletes anything imported before: a conversation keeps its status, assignee and other fields as Kommio has them, even if Chatwoot reopened it for the new message, and the report lists those conversations to check. It mirrors no deletions and carries no edits.

Signed-in visitors keep their history

Chatwoot and Kommio sign a visitor's identity the same way: a lower-case hex HMAC-SHA256 of the visitor's identifier, keyed with the inbox's secret. The importer stores each Chatwoot contact's identifier as the Kommio contact's verified external identity, which is exactly what a signed Kommio identity resolves to, so a visitor who signs in with the same id lands on their imported contact and sees their past conversations.

ChatwootKommio
SecretThe web widget's HMAC tokenThe inbox's identity secret (Install › Identify signed-in users)
Signed valueidentifierid
Algorithmhex(HMAC-SHA256(secret, identifier))the same
Browser call$chatwoot.setUser(identifier, { identifier_hash, name, email })Kommio.identify({ id, hmac, name, email })
EmailTrusted as sentShown only, unless you also sign it with email_hmac
Custom attributesUnsignedSigned with attributes_hmac; unsigned ones are refused

With the identity secret copied (the wizard's option, or the database import's), the hash your server already computes is valid as it is, and only the browser call changes:

// before (Chatwoot)
window.$chatwoot.setUser(user.id, { identifier_hash: user.hash, name: user.name, email: user.email });
// after (Kommio): same id, same hash
window.Kommio.identify({ id: String(user.id), hmac: user.hash, name: user.name, email: user.email });

$chatwoot.reset() on sign-out becomes Kommio.logout(). Without the copied secret, put the Kommio inbox's identity secret in your server's configuration in place of Chatwoot's HMAC token; the signing code does not change. Attributes and emails you want trusted are signed as described in Identify signed-in visitors. Anonymous visitors start a new chat on Kommio, since Chatwoot's browser session has no Kommio equivalent; their past conversations are still in Kommio under their contact.

Agents keep their passwords

With the database import, people can sign in with their current Chatwoot password. Chatwoot stores passwords as bcrypt hashes; the import puts that hash on the Kommio login it created, only when that login has no password yet, so a password set in Kommio or an existing login is never replaced. The first successful sign-in replaces it with Kommio's own Argon2id hash. Members still arrive disabled, so nobody signs in before you enable them at cut-over. Two-factor secrets cannot be carried (Chatwoot encrypts them with its own key), and Chatwoot's API does not expose password hashes, so the web import cannot carry passwords.

What moves, and what does not

ChatwootKommioNot carried over
Agents and administratorsMembers, disabled, with the Agent or Administrator role, matched by emailCustom roles (become Agent), availability, signatures, avatars
Former agents named in the historyDisabled members, so their messages keep a name (database import; the API does not list them)
TeamsTeams and members, matched by name"Allow auto assign" (auto-assignment starts off), team icons
Website widget inboxWebsite chat inbox: colour, greeting, away message, pre-chat name and email, business hours, CSAT on or off, members, identity secret on requestWelcome title and tagline, reply-time text, pre-chat phone and custom fields, wildcard allowed domains (the list is left open), "HMAC mandatory", the website token (the snippet changes)
Working hours and time zoneThe inbox's business hoursHours in a time zone that is not an IANA name (reported; UTC is used)
Email inboxEmail inbox, paused, with its servers; passwords on request; a Microsoft or Google sign-in waits to be connectedChatwoot's sign-in tokens, forwarding addresses
API inboxAPI inboxCallback URL and HMAC token (use Kommio webhooks and API keys)
WhatsApp, Facebook, Instagram, Telegram, SMS, LINE and other channelsRead-only history inbox, keeping each customer's channel id for reconnectionThe live connection, until the channel is connected in Kommio
LabelsTags with their colour; a label only a macro or rule names becomes a tag too, by name (noted in the report); labels on contacts become the attribute chatwoot_labelsLabel descriptions, sidebar visibility
Custom attribute definitionsCustom attributes with their types (checkbox as yes or no; currency and percent as numbers)Company attributes, regex validation, default values
ContactsName, email, phone, identifier (as the verified external identity), company, blocked, custom attributes, city and country, last activityContact type, browser and IP details, social profiles, avatars; anonymous visitors with no identity and no conversation; silent contacts when you choose so
Conversations and messagesEverything listed above, with email headers for threadingParticipants, mentions, SLA, reactions and the history of message edits; rich message formats become text with their choices and answers
AttachmentsFiles up to 25 MBFiles missing from storage, larger than 25 MB or of a blocked type (all reported); shared locations and links become a line of text
CSAT responsesSatisfaction ratings with comments; they count in ReportsReview notes
Canned responsesCanned responses, placeholders convertedUnknown placeholders stay as text (reported); a shortcut Kommio already has keeps Kommio's text
MacrosMacros whose every step maps, "send webhook" included (Kommio's signed payload); a step on an agent or team deleted in Chatwoot, or removing a label no conversation has, is left out with a warning, as is a webhook URL Kommio's outbound policy refusesMacros with snooze, mute, email transcript, attachments or "assign to me", or whose agent or team exists but was not imported (reported); a macro whose every step is left out
Automation rulesRules, switched off, with the conditions and actions that map; labels only a rule names become tags; steps on a deleted agent or team, on a label no conversation has, or on a refused webhook URL are left out and listed in the rule's descriptionConditions on browser language, country, city, referrer, email or phone; actions that mute, snooze, send files or email transcripts (listed)
WebhooksWebhooks, paused, with a new secret and mapped eventsInbox-only scope; "webwidget triggered", "message updated" and typing events
Help centerHelp centers, collections with their translations, and articles, as drafts unless you publish themCustom domains (verify again), portal colour, homepage link and page title, images stored in Chatwoot (upload again), languages Kommio does not publish in
ReportsRebuilt from the imported historyChatwoot's own report data

Database import

For very large accounts, a Chatwoot on a private network, or to carry what the API cannot, the importer reads a copy of Chatwoot's Postgres database (a read replica or a restored snapshot is best; it is opened read-only and never written) and Chatwoot's files from its storage directory or its S3-compatible bucket. On Kommio Cloud we run it: send us a database dump of the account and storage access, and we agree the timing with you. Self-hosted operators run it on their server:

dry run, then import
export KOMMIO_IMPORT_SOURCE_DB='postgres://readonly:<password>@replica:5432/chatwoot_production'
kommio import chatwoot --source-account 1 --account-email [email protected] \
  --storage-dir /mnt/chatwoot/storage --dry-run --report-text dry-run.txt

# the same without --dry-run imports; add --with-channel-secrets, --with-agent-passwords
# and, for a site that identifies every signed-in user, --skip-silent-contacts
kommio import chatwoot --source-account 1 --account-email [email protected] \
  --storage-dir /mnt/chatwoot/storage --with-channel-secrets --with-agent-passwords --skip-silent-contacts
from a pg_dump file, and the catch-up at cut-over
kommio import chatwoot --from-dump chatwoot.dump --source-account 1 \
  --account-email [email protected] --storage-dir /mnt/chatwoot/storage

kommio import chatwoot --source-db "$CHATWOOT_DATABASE_URL" --source-account 1 \
  --account-email [email protected] --storage-dir /mnt/chatwoot/storage --delta

The Chatwoot account id is the number in Chatwoot's dashboard address (/app/accounts/<id>/). --from-dump restores the file into a temporary database next to Kommio, imports from it and drops it; it needs the PostgreSQL client tools where the command runs. The web import's token source is available to operators as --source-api https://your-chatwoot.example, with the token in KOMMIO_IMPORT_API_TOKEN, which also reaches a Chatwoot on a private network from a machine inside it. A catch-up (--delta) behaves exactly as described above, --allow-mass-delete lets a checked mass deletion through, --allow-overwrite-kommio-work lets a plain catch-up through once the team has worked in Kommio, and after the switch --delta --only-new creates new records only and never changes what agents did in Kommio. --skip-silent-contacts and --include-silent-contacts set the silent contacts choice, which the runs after remember; --include-anonymous also imports anonymous visitors with no identity and no conversation.

Every run's report is saved as files: at the paths given with --report-text and --report-json, or, without them, as chatwoot-<workspace>-<mode>-<time>.txt and .json in KOMMIO_IMPORT_REPORT_DIR (the current directory when it is unset; in a container, point it at a writable mounted folder). When the named path cannot be written, the command prints the report and exits with an error after the import itself succeeded; the run and its report are also in Settings › Import.

The database import writes contacts and conversations in bulk on several connections at once, with the same result as writing them one by one (conversations are still numbered in Chatwoot's order). In our benchmark with 200,000 contacts, 10,000 conversations and 150,000 messages, a full import went from 8 min 44 s to 1 min 33 s with the bulk writers; your timing depends on your servers and on how close the source is. Importing from a dump or a replica next to the Kommio server is the quickest; reading a live database over a VPN is the slowest.

Troubleshooting

  • "Chatwoot refused the access token": copy it again from Chatwoot's Profile settings; resetting it there makes the old one stop working.
  • "Not an administrator of this Chatwoot account": the token must belong to an administrator of the account you import; an agent's token cannot read every conversation or the settings.
  • "This address is on a private network": your Chatwoot is behind a VPN or firewall; run the import from the command line on a machine that reaches it (--source-api, or the database import).
  • "Still rate limited after many waits": Chatwoot Cloud limits how fast a token may read; run it again later, and it continues where it stopped.
  • A conversation failed: the report names it and the reason; fix the cause and run the import again, and everything else is skipped as unchanged.
  • A catch-up stopped because of work done in Kommio: the team has replied, written notes or started conversations in Kommio since the last plain run. After the switch, catch up with Only new records (--delta --only-new); override only if Chatwoot is to win again (details).

Read more

What moves and how long it takes, told as a story: Moving from Chatwoot to Kommio. Deciding first? Kommio as a Chatwoot alternative compares pricing, gaps and features, and Kommio vs Chatwoot the two designs.

Every claim on these pages is covered by a test in the repository, and the API reference is generated from the same contract every server serves at /api/openapi. Corrections to [email protected].