How to Migrate From Zendesk to Self-Hosted Chatwoot
A step by step plan to move from Zendesk to self-hosted Chatwoot: plan-gated data exports, NDJSON gotchas, API rate limits, object mapping, cutover checklist, and real costs.

Moving a support team off Zendesk onto self-hosted Chatwoot is a two-to-six-week project with three real workstreams: getting your data out of Zendesk, standing up and importing into Chatwoot, and rebuilding the working layer (macros, triggers, SLAs, help center) that does not transfer. The official Chatwoot migration guide covers the happy path, but it skips the parts that actually bite: Zendesk gates its full data export by plan, exports are switched off until you ask support to enable them, and nothing migrates your automations. This guide covers the full job, including the parts the official one leaves out.
The short answer: contacts move by CSV, conversations move by API, everything else gets rebuilt by hand, and you should budget for a parallel-run period where you pay for both tools.
What actually moves and what does not
Before touching anything, split your Zendesk account into two piles: data that transfers and configuration that does not.
Data that transfers:
- Contacts and users. Exported from Zendesk as CSV, imported through the Contacts > Import function in Chatwoot, as described in Chatwoot's official migration guide.
- Tickets with their comment history. Exported from Zendesk (UI export or API), then recreated as Chatwoot conversations through the conversations API. Each ticket comment becomes a message.
- Organizations. These map roughly to Chatwoot companies, created through the API or recreated manually if the list is short.
- Attachments. Retrievable through the Zendesk API, but re-attaching them to imported messages is the fiddliest part of the whole job. Plan real time for it or accept losing inline files on old tickets.
Configuration that does not transfer:
- Triggers and automations. Chatwoot has its own automation rules. You rewrite them.
- Macros. These become Chatwoot canned responses. Export the text, recreate them.
- SLA policies. Chatwoot supports SLAs on higher plans and self-hosted, but the policies themselves are rebuilt.
- Help center articles. Zendesk Guide content has to be exported and re-imported into a Chatwoot portal, article by article or with a script.
- Agent skills, routing, groups, business hours. Recreated in Chatwoot as teams, inboxes, and working-hour settings.
- CSAT history and reporting history. Old satisfaction scores do not carry across in any meaningful way. Export them for your records and start fresh.
The practical rule: if it is a row of data, it moves. If it is a rule, a workflow, or a report, you rebuild it.
What the move costs
A worked example with real numbers, because that is usually the question behind the question.
Take a 15-agent team on Zendesk Suite Professional, paid annually:
- Suite Professional: $115 per agent per month, so 15 agents cost $1,725 per month, per the Zendesk pricing page.
- Add the Copilot add-on at $50 per agent per month and you are at $2,475 per month.
The same team on self-hosted Chatwoot:
- Software: $0. Chatwoot is open source; the code is on GitHub and you run it on your own infrastructure.
- Server: a mid-sized VPS handles a team this size comfortably. Our production sizing guide for Chatwoot puts a 15-agent deployment in the $40 to $120 per month range depending on provider and redundancy, and our guide to self-hosting a business stack compares server sizes across the whole stack, not just the helpdesk.
- Chatwoot Cloud as an alternative: 15 agents on the Business plan at $39 per agent per month, billed annually, comes to $585 per month, with channels and a monthly Captain AI credit allowance included, per Chatwoot's pricing. For a different seat-math comparison, we ran the numbers for Chatwoot vs Intercom for a 20-seat support team.
Then the one-time costs people forget:
- Parallel run. Two to four weeks of paying for both while you cut over. For the example team that is one extra month of Zendesk, roughly $1,725.
- Migration labour. Export scripts, import scripts, testing, rebuilding automations. A careful in-house job is 60 to 120 hours of engineering and admin time for a mid-sized account. This is where most of the real budget goes, and it is also where a custom build engagement makes sense if your team does not have spare API capacity.
- Retraining. Agents need a few hours each on the new inbox. Cheap, but not zero.
The payback on licence savings alone for this example team is under two months if you self-host, and under a year on Chatwoot Cloud. The wider economics of trading SaaS subscriptions for a self-hosted stack are covered in our breakdown of the real cost of replacing SaaS with open source.
Step 1: Get your data out of Zendesk
This is the step with the most surprises, so start here before you provision anything.
Enable exports first
Data export in Zendesk is off by default. The account owner has to contact Zendesk customer support to activate it, per Zendesk's own instructions. Do this on day one; waiting on a support ticket is a silly reason to lose a week.
Once enabled, the export option appears under Admin Center > Account > Tools > Reports, and only admins or custom roles with export permission can see it, as Zendesk documents here.
Know your plan limits
The full JSON or full XML export requires a Suite Growth or Support Professional plan or higher. On lower plans you still have a path: the API, which works on any plan. Zendesk's ticket export options page lays out exactly which plan gets which export.
Two format gotchas:
- Full JSON exports are NDJSON, one JSON object per line, not a single valid JSON array. If your import script chokes on line one, that is why; Zendesk explains the format here.
- CSV exports cap out on large accounts, and ticket comments do not come through cleanly in CSV at all. For anything beyond a few thousand tickets, use JSON or the API.
Use the incremental export API for tickets and comments
For a full-fidelity pull, use the incremental export endpoints:
GET /api/v2/incremental/tickets/cursor?start_time=...for tickets, cursor-paginated.GET /api/v2/incremental/ticket_events?start_time=...with thecomment_eventssideload to get the actual comment bodies. Without the sideload you only get flags saying a comment exists, not its content.- Carry the
end_timeof each response into thestart_timeof the next request so you do not skip tickets.
Watch the rate limits. Incremental exports carry their own budget separate from the account-wide limit: the general incremental limit is 10 requests per minute (30 with the High Volume API add-on), while the cursor-based endpoints are documented at 20 requests per minute by default and 60 with the add-on, per Zendesk's rate limit documentation. The sample export endpoint is stricter still, at 10 requests per 20 minutes and 50 results per call, so use it to test your parser, not to test throughput. A 200,000-ticket history takes hours, not minutes. Run the export as a resumable script that saves the cursor, because it will get interrupted.
Step 2: Stand up Chatwoot
Decide where Chatwoot will live before you import anything, because the import target has to exist.
- Self-hosted: the self-hosted installation guide walks through a production deployment on your own infrastructure. Docker is the common path. Put Postgres and Redis on the same box for a small team, split them out as you grow, and set up backups and object storage for attachments before the import, not after.
- Chatwoot Cloud: faster to start, hosted on AWS in the United States. If data residency matters to you, that location is a decision point; self-hosting removes it.
Set up at least one inbox per channel you plan to carry over: website live chat, email, and whichever messaging channels you use. If WhatsApp is one of them, that reconnection is its own mini-project with Meta's approval flow; we have a separate guide on connecting Chatwoot to the WhatsApp Business API with the costs.
Step 3: Import contacts
The easy part, and a good smoke test before the heavy work:
- Export your users from Zendesk as CSV.
- In Chatwoot, open Contacts, press Import, upload the CSV.
- Spot-check a dozen records: names, emails, phone numbers, and any custom attributes you mapped.
Clean the CSV first. Dedupe on email, normalise phone numbers to international format, and drop test accounts. Every dirty row you import now becomes a confused conversation routing later.
Step 4: Import conversations through the API
There is no button for this. You write a script that reads your Zendesk export and recreates history in Chatwoot:
- Create or match the contact in Chatwoot by email.
- Create a conversation against the right inbox using the create-conversation endpoint from the Chatwoot API.
- Add each ticket comment as a message in order, marking agent comments as outgoing and customer comments as incoming.
- Map status. Zendesk's new, open, pending, hold, solved, closed collapse into Chatwoot's open, resolved, pending, and snoozed. Decide the mapping once, write it down, apply it uniformly.
- Close historical conversations so thousands of solved tickets do not flood the open queue on day one.
Three honest limits:
- Timestamps. Imported messages are created when you create them. You can record the original date in the message content or a custom attribute, but the conversation timeline will not be perfectly historical. For most teams that is fine; for regulated record-keeping, keep the raw Zendesk export archived.
- Attachments. Zendesk attachment URLs require authentication and expire. Download them during export, then re-upload through the Chatwoot API. This is slow and worth automating properly.
- Rate limits on both sides. Throttle the import, run it against a staging inbox first, and expect at least one full re-run after you find a mapping bug.
Step 5: Rebuild the working layer
Budget a few days for this; it is configuration, not code, but it is what agents actually feel.
- Macros to canned responses. Export your top 20 macros by usage, recreate them, ignore the long tail nobody used.
- Triggers to automation rules. Chatwoot automations fire on conversation created, updated, and message events. Most standard routing triggers translate directly.
- SLAs and business hours. Recreate policies and set working hours per inbox.
- Help center. Stand up a Chatwoot portal and re-import articles. If your Zendesk Guide is large, script it through both APIs rather than copy-pasting.
- Reporting expectations. Tell the support lead plainly: historical dashboards do not come across. Export Zendesk reports to CSV for the archive.
Step 6: Cutover and parallel run
The safe pattern:
- Week 0: Chatwoot fully configured, history imported, agents trained.
- Weeks 1 to 2: new conversations land in Chatwoot. Swap the website widget (remove the Zendesk snippet first, per the official guide), point support email forwarding at the Chatwoot email channel, reconnect messaging channels. Zendesk stays open for in-flight tickets only.
- Weeks 3 to 4: drain Zendesk. No new tickets created there. Agents work both tools until the Zendesk queue hits zero.
- Week 4: final incremental export to catch anything created during the overlap, import the delta, downgrade Zendesk.
Do not cancel Zendesk until the final delta import is verified. Keep the account on the cheapest plan or export-and-archive for one billing cycle if your compliance posture requires ticket retention.
Common mistakes
- Assuming export is a button. It is gated by plan, disabled by default, and NDJSON-formatted. Start the export request on day one.
- Importing into production directly. Always run the import against a staging instance first. You will find mapping bugs.
- Leaving old tickets open after import. Thousands of zombie conversations destroy the agents' first impression of the new tool.
- Forgetting attachments until after Zendesk's signed URLs expire. Download them during export.
- Skipping the parallel run to save one month of licence fees, then losing in-flight tickets. The overlap is the cheapest insurance in the project.
- Rebuilding every macro and trigger including the dead ones. Migrate the 20 percent that handles 80 percent of volume.
When staying on Zendesk is the wrong choice to reverse
Honest limits, because this move is not for everyone:
- You rely on Zendesk-specific depth. Workforce management, advanced QA, sophisticated Guide theming, and the app marketplace are genuinely ahead of Chatwoot. If your operation uses them daily, the licence is buying something real.
- You have no one to run a server. Self-hosted means you own patching, backups, and uptime. If that capacity does not exist in-house, use Chatwoot Cloud or a managed service instead of pretending otherwise.
- Your team is small and happy. At five agents on Suite Team at $55, the savings are real but small, and migration effort dominates. The case gets strong around 10 to 15 agents or when you are on Professional with add-ons.
- You are mid-contract. Zendesk annual contracts do not refund. Time the cutover to renewal.
Frequently asked questions
Can I migrate Zendesk tickets to Chatwoot automatically? Partially. Contacts import by CSV through the Chatwoot UI. Tickets and comments need a script that reads the Zendesk export and recreates them through the Chatwoot conversations API. There are third-party migration services that do this for a fee if you do not want to write the script.
Does Zendesk let me export all my data? Yes, but with conditions. Full JSON or XML export requires a Suite Growth or Support Professional plan or higher, exports are disabled until the account owner asks Zendesk support to enable them, and the API works on every plan as a fallback.
Will conversation history keep its original dates in Chatwoot? Not exactly. Messages are created at import time. You can store original timestamps in the content or custom attributes, but the timeline itself reflects the import. Keep the raw Zendesk export as your historical archive.
How long does a Zendesk to Chatwoot migration take? Two to six weeks for a typical team: a week for export and environment setup, a week for import scripting and testing, and two to four weeks of parallel run while in-flight tickets drain out of Zendesk.
Is Chatwoot really free if I self-host? The software is open source and free. You pay for the server (typically $40 to $120 per month for a mid-sized team), plus the time to maintain it, or you pay someone to manage it for you.
What happens to my Zendesk help center? It does not migrate automatically. Articles are exported through the Zendesk API and re-created in a Chatwoot portal. Treat it as a separate workstream from ticket migration.
Where to go from here
If the plan above reads like more work than your team has spare capacity for, that is the normal situation: migrations fail on spare time, not on difficulty. We deploy and manage Chatwoot as part of our managed open-source stack service, including exactly this kind of Zendesk migration, and the ongoing patching, backups, and monitoring after it. One conversation with an engineer will tell you whether self-hosted, Chatwoot Cloud, or staying put is the right call for your team.
Related reading
About AI Agents Plus Editorial
AI automation expert and thought leader in business transformation through artificial intelligence.



