tawk.to to Freshchat Migration: A Technical Guide
A technical guide to migrating from tawk.to to Freshchat. Covers data extraction methods, API constraints, schema mapping, edge cases, and step-by-step migration architecture.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
tawk.to to Freshchat Migration: A Technical Guide
Migrating from tawk.to to Freshchat means moving from a free-tier live chat platform with a gated API into a paid omnichannel messaging product within the Freshworks ecosystem. There is no native import path between the two. No one-click migration tool, no vendor-supported connector, and no CSV upload that maps tawk.to's chat history into Freshchat conversations. Every migration here is a custom engineering project.
This guide covers the real technical path: data model differences, extraction methods and their limitations, transformation logic, Freshchat API import mechanics, edge cases, and validation strategies.
Last verified: July 2025. API behaviors and pricing may change; confirm against current documentation before starting your migration.
Why Teams Migrate from tawk.to to Freshchat
tawk.to is a free live chat application for monitoring and chatting with website visitors. Its core functionality — unlimited conversations, agents, and chat history — is free. Paid add-ons include branding removal ($19/month) and AI chatbot capabilities ($29/month+). Its architecture centers around discrete chat sessions and visitors within site-level "Properties."
Freshchat is Freshworks' modern messaging platform spanning web chat, mobile, WhatsApp, Facebook Messenger, Instagram, Apple Business Chat, and email. Pricing starts at $19/agent/month (Growth) through $79/agent/month (Enterprise), with a limited free tier. It organizes data around persistent users and channels, treating conversations as ongoing threads rather than isolated sessions.
The most common reasons teams move:
- Omnichannel consolidation. tawk.to is primarily web chat. Freshchat covers WhatsApp, Facebook Messenger, Instagram, Apple Business Chat, email, and mobile SDK — all in one inbox.
- Freshworks ecosystem integration. Teams already on Freshdesk, Freshsales, or Freshworks CRM want their chat tool tightly coupled with ticketing and CRM data.
- AI and automation. Freshchat's Freddy AI is included in paid plans. tawk.to charges separately for AI, and its automation capabilities are more limited.
- Scalability and routing. As teams grow past 10+ agents, tawk.to's reporting and routing become limiting. Freshchat offers assignment rules, IntelliAssign, and CSAT flows natively.
- API maturity. tawk.to's REST API is still in private beta with a gated approval process. Freshchat provides a documented, publicly accessible REST API.
The core technical challenge lies in translating tawk.to's session-based, property-centric schema into Freshchat's persistent user-conversation model without losing historical context, attachment integrity, or agent attribution.
Core Data Model Differences
The two platforms are architecturally different. tawk.to is organized around Properties (websites), with Chats, Tickets, Contacts, and a Knowledge Base under each property. Freshchat is organized around Conversations, Channels, Users/Contacts, Agents, and Groups — scoped to a single account.
| Concept | tawk.to | Freshchat |
|---|---|---|
| Site/workspace | Property | Account |
| End users | Visitors → Contacts | Users / Contacts |
| Chat threads | Chats | Conversations |
| Individual messages | Chat messages | Messages (message_parts) |
| Email-based support | Tickets | Not native (use Freshdesk) |
| Agent grouping | Departments | Groups |
| Agents | Property members | Agents |
| Help articles | Knowledge Base | Not native (use Freshdesk) |
| Categorization | Tags | Conversation properties / Tags |
| Custom data | Custom Attributes | Custom properties (on contacts) |
tawk.to Tickets (email-based support threads) have no direct equivalent in Freshchat. Freshchat is a messaging platform, not a ticketing system. If you rely on tawk.to's ticketing, you need Freshdesk alongside Freshchat, or Freshworks Customer Service Suite.
Migration Approaches: What Actually Works
1. Manual Dashboard Export + Freshchat API Import
How it works: Export chat history and contacts from tawk.to's dashboard as JSON/CSV files, then transform the data and push it into Freshchat via the REST API.
tawk.to admins can export chat transcripts from the Inbox by selecting conversations and clicking Export. The recipient receives a ZIP file containing JSON files with message details including timestamps, visitor and agent names, and message content. Contacts can be exported separately as CSV. Chat export from the Inbox is limited to 50 messages at a time, and ticket export links stay valid for 30 days. (help.tawk.to)
A typical tawk.to chat export JSON entry looks like this:
{
"id": "chat-abc123",
"visitor": {
"name": "Jane Doe",
"email": "jane@example.com",
"city": "Austin",
"country": "US"
},
"agents": ["Agent Smith"],
"department": "Sales",
"tags": ["billing", "urgent"],
"messages": [
{
"timestamp": "2024-03-15T14:32:00Z",
"sender": "Jane Doe",
"type": "visitor",
"text": "Hi, I need help with my invoice."
},
{
"timestamp": "2024-03-15T14:33:12Z",
"sender": "Agent Smith",
"type": "agent",
"text": "Sure, can you share your account number?"
}
],
"attachments": [
{
"filename": "invoice.pdf",
"url": "https://tawk.to/files/...",
"size": 142056
}
],
"startedAt": "2024-03-15T14:31:45Z",
"endedAt": "2024-03-15T14:52:30Z"
}When to use it: Small accounts with under 5,000 conversations and limited custom data.
Pros:
- No API access request needed on the tawk.to side
- JSON export includes full message content and metadata
- Works for any tawk.to plan
Cons:
- Manual selection process — you must select conversations in the dashboard UI, requiring multiple export batches
- Custom attribute data is not included in contact CSV exports (confirmed by tawk.to support)
- No attachment file downloads — only metadata and URLs are included
- JSON structure requires significant transformation to match Freshchat's
message_partsschema
Complexity: Medium
2. tawk.to REST API Extraction → Freshchat API Import
How it works: Use tawk.to's REST API to programmatically extract chats, tickets, contacts, and KB articles, transform them, and push into Freshchat via its v2 API. The tawk.to REST API uses HTTP Basic Auth with API key credentials at https://api.tawk.to/v1/. (help.tawk.to)
The catch: tawk.to's REST API requires a formal access request and approval. Multiple community reports indicate wait times of months to over a year, even for paying customers. The API documentation itself is gated — you only receive it after approval.
When to use it: Medium-to-large accounts where manual export is impractical and you can get API access.
Pros:
- Programmatic, repeatable, and scriptable
- Can filter by date range, agent, tag, department
- Includes chat statistics and metadata not available in dashboard exports
- Supports pagination for large datasets
Cons:
- API access is gated behind a request/approval process with unreliable turnaround
- No public rate limit documentation — limits are shared privately upon approval
- API is still labeled "beta" — endpoints may change
- Custom attributes on contacts may still require separate extraction
Complexity: High
3. Webhook-Based Forward Capture + Backfill
How it works: Configure tawk.to webhooks to forward new chat transcripts to an intermediate service in real-time, while separately backfilling historical data via export or API.
tawk.to webhooks deliver complete chat transcripts via HTTP POST when a chat ends. The payload includes chat details, visitor info, and full message history. Webhooks are signed with HMAC-SHA1 via the X-Tawk-Signature header. If your endpoint doesn't respond within 30 seconds or returns an error, tawk.to retries for up to 12 hours. Properties are capped at 10 webhooks each. (help.tawk.to)
When to use it: Ongoing sync scenarios during a transition period, or when you want to capture new conversations while planning the historical backfill.
Pros:
- Real-time capture with no manual intervention
- Includes attachment metadata and URLs
- Signed payloads for verification
- Built-in retry logic
Cons:
- Only captures new chats going forward — no historical backfill
- Must handle duplicate webhook deliveries (design for idempotency)
- 30-second response timeout is tight for complex processing pipelines
- Does not cover contacts, tickets, or Knowledge Base content
Complexity: Medium
4. Middleware Platforms (Zapier, Make)
How it works: Use Zapier or Make to connect tawk.to triggers (new chat, new ticket) to Freshchat actions (create conversation, create contact). (zapier.com)
When to use it: Small-volume, forward-only sync. Not viable for historical migration.
Pros:
- No-code setup
- Works within minutes
- Good for bridging gaps during transition
Cons:
- No historical data transfer — only new events
- Limited field mapping flexibility
- Per-task pricing adds up quickly at volume (Zapier's Starter plan starts at $19.99/month for 750 tasks)
- Not suitable as a migration tool — only a bridging mechanism
Complexity: Low
5. Custom ETL Pipelines
How it works: Build a staging database or object store, maintain ID crosswalk tables, run deterministic transforms, and load Freshchat through workers with checkpoints and dead-letter queues.
When to use it: Enterprise environments where chat data must be sanitized, audited, or joined with other databases before landing in Freshchat. Also relevant for M&A consolidation or regulated environments.
Pros: Best control over validation, idempotency, and coexistence windows. Extremely resilient and auditable.
Cons: Highest build cost and longest lead time. Overkill for standard helpdesk migrations.
Complexity: High
6. Managed Migration Service
How it works: A migration service handles the full extract-transform-load pipeline: extracting data from tawk.to via all available methods, transforming it to Freshchat's schema, and loading it via the Freshchat API with validation at every stage.
When to use it: Any scenario where accuracy matters, your team doesn't have migration experience, or you can't afford downtime.
Pros:
- Handles API access negotiation, edge cases, and error recovery
- Preserves conversation threading, timestamps, and attribution
- Includes validation and rollback planning
- Typically completed in days, not weeks
Cons:
- External cost (typically $2,000–$15,000+ depending on data volume and complexity)
- Requires sharing API credentials
Complexity: Low (for you)
Approach Comparison
| Approach | Historical Data | Ongoing Sync | Complexity | Scale | Cost |
|---|---|---|---|---|---|
| Manual Export + API | ✅ | ❌ | Medium | Small | Low |
| tawk.to API → Freshchat API | ✅ | Possible | High | Medium–Large | Medium |
| Webhook Capture | ❌ (forward only) | ✅ | Medium | Any | Low |
| Zapier / Make | ❌ (forward only) | ✅ | Low | Small | Per-task |
| Custom ETL | ✅ | ✅ | High | Enterprise | High |
| Managed Service | ✅ | ✅ | Low (for you) | Any | Service fee |
Which Approach for Your Scenario
- Small business, <5K chats, no dev team: Manual export + Freshchat API import, or managed service.
- Mid-size, 5K–50K chats, some engineering capacity: tawk.to API (if you can get access) → custom ETL → Freshchat API.
- Enterprise, 50K+ chats, compliance requirements: Managed migration service or dedicated ETL pipeline with audit logging.
- Transition period (running both tools): Webhook capture for new chats + historical backfill via any method above.
Estimated Engineering Effort and Duration
| Data Volume | Approach | Estimated Engineering Hours | Elapsed Calendar Time |
|---|---|---|---|
| <1,000 conversations | Manual export + script | 8–16 hours | 1–3 days |
| 1K–5K conversations | Manual export + API import | 20–40 hours | 3–7 days |
| 5K–20K conversations | API extraction + ETL | 40–80 hours | 1–3 weeks |
| 20K–100K conversations | Custom ETL pipeline | 80–160 hours | 3–6 weeks |
| 100K+ conversations | Custom ETL or managed | 160+ hours (DIY) | 4–8 weeks (DIY) |
These estimates include extraction, transformation, loading, debugging, and validation. They do not include time waiting for tawk.to API access approval, which can add weeks to months of calendar delay.
When NOT to Build This In-House
Building an in-house migration script often looks like a two-week project on paper. In reality, it consumes far more. Here are the failure modes that aren't obvious until you're deep in:
- tawk.to API access delays. If your REST API request isn't approved, your entire project timeline is blocked. There's no SLA on approval.
- Schema translation errors. tawk.to's flat JSON chat export doesn't map cleanly to Freshchat's
message_partsstructure. Getting this wrong means garbled conversation history. - Orphaned records. Conversations imported without matching contacts create orphaned threads in Freshchat. Freshchat requires a valid
user_idto create a conversation. - Custom attribute loss. tawk.to's CSV contact export doesn't include custom attributes — a fact many teams discover only after starting the migration.
- Attachment handling. tawk.to exports include attachment URLs, but those URLs may expire or require authentication. Files need to be downloaded and re-uploaded separately.
- Rate limit math. Freshchat enforces per-account rate limits that vary by plan. A naive script will crash; a resilient script requires queueing and backoff algorithms.
The hidden cost isn't the migration script — it's the three rounds of debugging, the validation spreadsheets, and the week your senior engineer spends reverse-engineering undocumented API behavior instead of shipping product.
Skip the DIY route when:
- Your engineering team is actively shipping product features
- You have over 50,000 historical conversations
- You cannot afford data loss or downtime during the cutover
- tawk.to REST API access is not yet approved
- Legal or operations wants repeatable audit logs
Pre-Migration Planning
Data Audit Checklist
Before anything else, catalog what you have and what you need:
| Data Type | tawk.to Location | Migrate? | Notes |
|---|---|---|---|
| Live chat conversations | Inbox → Chats | Yes | Core migration target |
| Chat messages + timestamps | Within each chat | Yes | Map to Freshchat message_parts |
| Tickets (email threads) | Inbox → Tickets | Conditional | Freshchat doesn't handle tickets — route to Freshdesk if needed |
| Contacts | People → Contacts | Yes | CSV export lacks custom attributes |
| Organizations | Linked to contacts | Yes | Map to Freshchat contact properties |
| Tags | Applied to chats/tickets | Yes | Recreate as Freshchat conversation properties |
| Custom attributes | Contact profiles | Yes | Must extract via API or manual pull |
| Knowledge Base articles | KB section | No (Freshchat) | KB belongs in Freshdesk, not Freshchat |
| Agents / Departments | Admin settings | Rebuild | Create manually in Freshchat |
| Shortcuts (canned responses) | Admin → Shortcuts | Rebuild | Recreate in Freshchat as canned responses |
| Automations / Triggers | Admin settings | Rebuild | No migration path — rebuild in Freshchat |
Define Migration Scope
- What moves as data: Chat conversations with full message history, contacts with attributes, tags.
- What gets rebuilt as configuration: Agents, groups, channels, automations, routing rules, CSAT settings.
- What gets archived: Chat analytics, satisfaction survey results, KB articles (if not moving to Freshdesk).
- What gets dropped: Redundant or test conversations, spam contacts, duplicate records.
Migration Strategy
For live chat migrations, a phased approach reduces risk:
- Big bang: Export everything, transform, load, cut over on a set date. Best for small-to-medium accounts where a single weekend is sufficient.
- Phased delta:
- Phase 1 (Historical): Migrate all data up to a specific freeze date.
- Phase 2 (Delta): Migrate any new chats that occurred during the historical sync.
- Phase 3 (Cutover): Swap the website widgets.
- Parallel run: Keep tawk.to live while importing history into Freshchat. Use webhooks to capture new tawk.to chats during the transition. Cut over when validated.
Your risk plan should define backup location, dry-run dates, UAT owners, rollback criteria, and who approves the final routing switch.
GDPR and Compliance Considerations
If you operate in the EU or handle EU customer data, the tawk.to-to-Freshchat migration involves a data transfer between processors that triggers GDPR obligations:
- Data Processing Agreements (DPAs). Ensure you have signed DPAs with both tawk.to and Freshworks. Freshworks publishes its DPA at freshworks.com/privacy.
- Data residency. tawk.to stores data globally. Freshchat (Freshworks) offers data center selection (US, EU, IN, AU). Confirm your Freshchat account is provisioned in the correct region before importing data.
- Lawful basis for transfer. Your existing lawful basis for processing chat data (typically legitimate interest or contract performance) should cover the migration, but document the transfer in your Records of Processing Activities (ROPA).
- Right to erasure. If any contacts have submitted deletion requests, honor those before migration. Do not import records that should have been deleted.
- Data minimization. Use the migration as an opportunity to purge unnecessary data — test conversations, spam, and records beyond your retention policy.
- Encryption in transit. Both tawk.to exports and Freshchat API calls use HTTPS/TLS. If you stage data locally, ensure at-rest encryption on your staging database or file system.
Data Mapping: tawk.to Objects to Freshchat
Contacts
tawk.to contacts include: name, email, phone, organization, tags, custom attributes, city, country, and last seen timestamp.
Freshchat contacts (users) include: first_name, last_name, email, phone, reference_id, avatar, properties, and created_time.
Key mapping decisions:
- tawk.to stores names as a single field. Split into
first_nameandlast_namefor Freshchat. - tawk.to's Organization field maps to a custom property on the Freshchat contact — there is no native "company" object in standalone Freshchat. If you need a proper account/company model, that belongs in Freshsales or your CRM of record.
- Custom attributes from tawk.to map to
propertieson Freshchat contacts. These must be defined in Freshchat before import. - Use tawk.to's email as the
reference_idin Freshchat to enable deduplication and idempotent loads.
Conversations and Messages
tawk.to chats export as JSON with a flat structure: timestamp, sender (visitor or agent name), message text, and metadata (see the sample JSON in the Manual Export section above).
Freshchat conversations use a nested structure:
{
"status": "resolved",
"messages": [
{
"message_parts": [
{
"text": {
"content": "Hello, I need help with my order."
}
}
],
"channel_id": "channel-uuid",
"message_type": "normal",
"actor_type": "user",
"actor_id": "user-uuid"
}
],
"channel_id": "channel-uuid",
"users": [
{
"id": "user-uuid"
}
]
}Transformation requirements:
- Each tawk.to message becomes a
message_partsobject with atext.contentfield. - The sender type must be mapped: visitor →
actor_type: "user", agent →actor_type: "agent". - You need valid Freshchat
user_idandagent_idvalues — contacts and agents must be created in Freshchat before importing conversations. channel_idis required — map to your designated Freshchat channel.
The Timestamp Constraint: Freshchat's created_time on messages and conversations is system-generated and not exposed as a request input in the public API. (developers.freshchat.com) To preserve the historical timestamp of a tawk.to message, prepend the original timestamp as text within the message body during migration (e.g., [Original Time: 2023-04-12 14:32] Client: Hello). This is a workaround, not a native feature. Messages will appear in the Freshchat UI with their import timestamp, not their original timestamp.
Tags and Departments
- tawk.to Tags → Freshchat conversation properties or labels.
- tawk.to Departments → Freshchat Groups. Create groups manually before import and maintain a mapping table of tawk.to department IDs to Freshchat group UUIDs.
Custom conversation properties with the cf_ prefix are documented only for chat accounts that are part of Freshsales Suite, not standalone Freshchat. (developers.freshchat.com) If you need custom data on conversations in standalone Freshchat, verify what your plan supports before building your mapping.
Sample Field Mapping Table
| tawk.to Field | Freshchat Field | Transformation |
|---|---|---|
| Contact Name | first_name + last_name |
Split on first space |
| Contact Email | email + reference_id |
Direct map; use email as dedup key |
| Contact Phone | phone |
Direct map |
| Organization | properties.organization |
Define as custom property first |
| Custom Attributes | properties.* |
Define each in Freshchat before import |
| Country / City | properties.country, properties.city |
Define as custom properties |
| Chat Message Text | message_parts [].text.content |
Wrap in message_parts; prepend historical timestamp |
| Chat Sender (visitor) | actor_type: "user", actor_id |
Lookup from contacts map |
| Chat Sender (agent) | actor_type: "agent", actor_id |
Lookup from agents map |
| Chat ID | Custom property or reference_id |
Store source ID for audit trails |
| Department | Group assignment (assigned_group_id) |
Map via UUID lookup table |
| Tag | Conversation property | Recreate as property |
| Attachment URL | message_parts [].image.url or file |
Download + re-upload |
Migration Architecture
Data Flow: Extract → Transform → Load
┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ tawk.to │ │ Transform │ │ Freshchat │
│ │────▶│ Layer │────▶│ │
│ • Dashboard │ │ • Split names │ │ • POST /users │
│ JSON export│ │ • Map sender IDs │ │ • POST /conver. │
│ • REST API │ │ • Restructure │ │ • POST /messages │
│ • Webhooks │ │ messages │ │ • Upload files │
│ • CSV export │ │ • Validate refs │ │ │
└──────────────┘ └──────────────────┘ └──────────────────┘
Do not stream directly from tawk.to to Freshchat. An error on the destination side will force you to re-fetch from the source. Always stage extracted data locally (PostgreSQL, MongoDB, or flat JSON files) before transformation.
tawk.to Extraction
Option A: Dashboard export
- Log in as Admin
- Navigate to Inbox → Chats (or Tickets)
- Apply date filters to scope the batch
- Select conversations → Export → Enter recipient email
- Download ZIP from emailed link
- Repeat for each batch/date range
- Export contacts separately from People → Contacts
Option B: REST API (if approved)
import requests
TAWK_API_BASE = "https://api.tawk.to/v1"
TAWK_API_KEY = "your-api-key"
TAWK_API_SECRET = "your-api-secret"
def get_chats(property_id, page=1):
response = requests.get(
f"{TAWK_API_BASE}/property/{property_id}/chats",
auth=(TAWK_API_KEY, TAWK_API_SECRET),
params={"page": page, "limit": 100}
)
response.raise_for_status()
return response.json()Freshchat API Import
Freshchat's v2 API uses Bearer token auth. Generate an API token from Admin → API Tokens in the Freshchat dashboard.
Design the load in dependency order: groups/channels → agents → users → conversations → messages → attachments → assignment/status updates → validation. Freshchat requires valid references (user IDs, channel IDs, group IDs) when creating conversations, so all scaffolding must exist before data loads begin.
Rate Limits and Throttling
Freshchat enforces per-account rate limits that vary by plan. Observed limits are approximately 50 requests per minute on Growth plans and higher on Pro/Enterprise, but Freshworks does not publish exact figures in public documentation. When you hit the limit, the API returns HTTP 429 with X-RateLimit-Limit and X-RateLimit-Remaining headers.
For a migration with 10,000 contacts and 20,000 conversations (each requiring a user lookup + conversation creation + message batches), a rough estimate of API calls:
| Operation | API Calls per Record | Total Calls (10K contacts, 20K convos, avg 8 msgs each) |
|---|---|---|
| Create users | 1 | 10,000 |
| Create conversations | 1 | 20,000 |
| Post messages | 1 per message | ~160,000 |
| Upload attachments | 1 per file | Variable |
| Total | ~190,000+ |
At 50 requests/minute, that's approximately 63 hours of continuous API calls — or less if you have a higher rate limit. Build your loading architecture with a queueing system and respect Retry-After headers.
import time
def rate_limited_request(func, *args, **kwargs):
while True:
resp = func(*args, **kwargs)
if resp.status_code == 429:
retry_after = int(
resp.headers.get("Retry-After", 60)
)
time.sleep(retry_after)
continue
return respFreshchat's Messages API has a max items_per_page of 50. When importing conversations with more than 50 messages, create the conversation first, then append additional messages via POST /conversations/{id}/messages in batches.
Step-by-Step Migration Process
Step 1: Prepare Freshchat Scaffolding
Create groups, channels/topics, agents, and any required custom contact properties in Freshchat before importing any data. Freshchat requires valid references when creating conversations. (developers.freshchat.com)
Freshchat sandbox/test accounts: Freshworks offers sandbox environments for accounts on the Pro plan ($49/agent/month) and above. If you're on the Growth plan, you can create a second Freshchat account for testing — note that this consumes a separate license. Contact Freshworks support to confirm sandbox availability on your plan before starting.
Step 2: Extract Data from tawk.to
Pull contacts, organizations, chats, tickets, and attachment references from dashboard exports or the REST API. Keep the raw files unchanged as your rollback source. (help.tawk.to)
Step 3: Transform and Deduplicate
Normalize phone/email formats, deduplicate contacts (using email as the canonical key), split names into first/last, restructure flat chat messages into Freshchat's message_parts format, map senders to actor_type (user/agent), and convert timestamps. Build source-to-target ID crosswalk tables.
Step 4: Import Contacts into Freshchat
Use POST /v2/users to create each contact. Use email as reference_id for deduplication. Build a mapping table of tawk.to email addresses to Freshchat user UUIDs.
import requests, time
FRESHCHAT_URL = "https://your-domain.freshchat.com/v2"
FRESHCHAT_TOKEN = "your-bearer-token"
headers = {
"Authorization": f"Bearer {FRESHCHAT_TOKEN}",
"Content-Type": "application/json"
}
def create_user(first_name, last_name, email, properties=None):
payload = {
"first_name": first_name,
"last_name": last_name,
"email": email,
"reference_id": email,
}
if properties:
payload["properties"] = properties
resp = requests.post(
f"{FRESHCHAT_URL}/users",
json=payload, headers=headers
)
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 60))
time.sleep(retry_after)
return create_user(first_name, last_name, email, properties)
resp.raise_for_status()
return resp.json()Step 5: Import Conversations and Messages
For each tawk.to chat, create a Conversation in Freshchat associated with the corresponding user_id. Reference the user ID map and agent ID map to set actor_id correctly. For conversations with more than 50 messages, create the conversation first, then append messages in batches.
def post_message(conversation_id, actor_type, actor_id, original_time, text):
endpoint = f"{FRESHCHAT_URL}/conversations/{conversation_id}/messages"
formatted_text = f"[Original Time: {original_time}]\n{text}"
payload = {
"actor_type": actor_type,
"actor_id": actor_id,
"message_type": "normal",
"message_parts": [
{"text": {"content": formatted_text}}
]
}
response = requests.post(endpoint, headers=headers, json=payload)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
time.sleep(retry_after)
return post_message(
conversation_id, actor_type, actor_id, original_time, text
)
elif response.status_code not in [200, 201]:
print(f"Error posting message: {response.text}")
return None
return response.json()Step 6: Handle Attachments
Parse message bodies for tawk.to attachment URLs. Download each file to a temporary server — don't rely on tawk.to URLs being available indefinitely. Upload to Freshchat and attach the resulting URL to the message payload. Freshchat file uploads are one per request with a 25 MB limit. (developers.freshchat.com) Files exceeding the limit must be hosted externally (e.g., an AWS S3 bucket) and linked as text URLs within the message.
Step 7: Validate the Migration
Compare record counts between tawk.to and Freshchat. Sample 5% of contacts for field-level accuracy. Open 20+ conversations at random and compare message content, sender attribution, and timestamps against tawk.to exports. Verify attachments are accessible and conversations are linked to correct contacts.
Step 8: Cut Over and Rebuild Configuration
Remove the tawk.to JavaScript snippet from your website and deploy the Freshchat web widget. Rebuild automations, routing rules, and canned responses. Train agents on the Freshchat inbox. Keep tawk.to active until stakeholders sign off on the migration.
Freshchat API Error Reference for Migration
During import, you'll encounter these Freshchat API errors. Categorize them as transient (retry) or permanent (fix and retry):
| HTTP Status | Error | Type | Cause | Action |
|---|---|---|---|---|
| 400 | Bad Request |
Permanent | Malformed payload, missing required field, invalid actor_type |
Fix payload; check required fields (channel_id, user_id) |
| 401 | Unauthorized |
Permanent | Invalid or expired Bearer token | Regenerate API token |
| 403 | Forbidden |
Permanent | Token lacks permission for the endpoint | Verify token scope and agent role |
| 404 | Not Found |
Permanent | Invalid user_id, conversation_id, or channel_id |
Verify ID exists in Freshchat; check crosswalk table |
| 409 | Conflict |
Permanent | Duplicate reference_id (user already exists) |
Lookup existing user instead of creating |
| 422 | Unprocessable Entity |
Permanent | Validation failure (e.g., invalid email format, custom property not defined) | Fix data; ensure custom properties are pre-created |
| 429 | Too Many Requests |
Transient | Rate limit exceeded | Wait for Retry-After seconds, then retry |
| 500 | Internal Server Error |
Transient | Freshchat server error | Retry with exponential backoff (max 3 retries) |
| 502/503 | Bad Gateway / Service Unavailable |
Transient | Freshchat infrastructure issue | Retry with exponential backoff |
Design rule: Route transient errors to a retry queue with exponential backoff (initial delay 1s, max delay 300s, max 5 retries). Route permanent errors to a dead-letter queue for manual review. Log the tawk.to source ID with every failed record.
Edge Cases and Challenges
Agent Mapping for Departed Employees
If an agent no longer works at your company, you cannot create them as an active, paid agent in Freshchat just for historical data. Create a single "Legacy Support" agent in Freshchat and map all departed tawk.to agents to this profile. Append the original agent's name within the message body to preserve context (e.g., [Original Agent: Sarah Chen]\n{message text}).
Anonymous Visitors
tawk.to allows visitors to chat without providing contact details. Freshchat requires at least a placeholder identifier for Users. You have two options: skip those conversations, or create placeholder contacts with a generated reference ID (e.g., anon-{tawk_chat_id}@placeholder.local).
Duplicate Contacts
tawk.to creates contacts from pre-chat forms, offline messages, and manual entry. The same person may appear multiple times with variations in name or email. Deduplicate before import — use email as the canonical key and merge conversation histories. tawk.to supports merging contacts, but the merge cannot be undone, so verify carefully. (help.tawk.to)
Custom Attribute Data Loss
tawk.to's CSV contact export does not include custom attribute data. This is a confirmed limitation. You must either extract custom attributes via the REST API (if you have access) or manually export them from individual contact profiles.
Attachment URL Expiration
tawk.to's export includes attachment metadata and URLs, but not the files themselves. Those URLs may expire or require authentication. Download all attachments during the extraction phase and store them locally before starting the import. Expired URLs mean permanent data loss.
Ticket Migration
Freshchat does not have a native ticketing system. tawk.to tickets — email-based support threads — need to be routed to Freshdesk if you want to preserve them. If you're only setting up Freshchat, those tickets will either be converted to resolved conversations (lossy) or archived outside the platform.
Conversation Threading
tawk.to stores conversations as flat lists of messages. Freshchat's conversation model supports reply threading and message types (normal, private, system). Map all tawk.to messages as message_type: "normal" unless you have metadata distinguishing internal notes.
Widget Identity Linking (external_id and restore_id)
Migrated conversations exist in Freshchat's backend but will not automatically appear to returning visitors in the web widget. For a visitor to see their conversation history in the Freshchat messenger, the widget must be initialized with their external_id (and optionally restore_id) matching the reference_id used during migration. This requires updating your website's Freshchat widget initialization code:
window.fcWidget.init({
token: "your-freshchat-token",
host: "https://wchat.freshchat.com",
externalId: "jane@example.com", // Must match reference_id from migration
restoreId: null // Will be generated on first load; store for future use
});If external_id is not set, returning visitors will start new conversations with no link to their migrated history.
Multi-Source Collisions
If you are simultaneously migrating data from another platform, ensure your User mapping logic deduplicates based on email address across all data sources.
API Failures and Retries
Build idempotency into your import pipeline. Use tawk.to's chat ID as a reference to check whether a conversation has already been created in Freshchat before retrying. Without this, failed-and-retried imports create duplicate conversations.
Limitations and Constraints
tawk.to Side
- REST API is gated. You cannot assume you'll have API access when planning your timeline. There's no SLA on approval.
- No bulk export API. Even with REST API access, there's no dedicated bulk export endpoint — you paginate through results.
- Custom attributes excluded from CSV export. Confirmed by tawk.to support.
- No public rate limit documentation. Limits are shared only after API approval.
- Webhooks capped at 10 per property. (help.tawk.to)
Freshchat Side
- No native ticketing. Tickets must go to Freshdesk.
- No Knowledge Base. KB content must go to Freshdesk.
- Rate limits vary by plan and are enforced at the account level. Approximate observed limits: ~50 req/min on Growth, higher on Pro/Enterprise.
- No bulk import endpoint. Every contact and conversation is created individually via API.
- Messages max 50 per page. Large conversations require multiple API calls.
- File uploads are one per request, capped at 25 MB. (developers.freshchat.com)
- No DELETE /v2/agents endpoint in the public REST API. Agent management requires SCIM (Enterprise) or manual admin action.
- Timestamps are system-generated. The API does not accept historical
created_timevalues on messages or conversations. - Custom conversation properties (
cf_*) are documented only for Freshsales Suite chat accounts, not standalone Freshchat.
Validation and Testing
Do not rely on random spot-checking. Implement a structured validation protocol.
Record Count Comparison
After import, verify counts match:
| Object | tawk.to Count | Freshchat Count | Status |
|---|---|---|---|
| Contacts | X | X | ✅ / ❌ |
| Conversations | X | X | ✅ / ❌ |
| Messages (total) | X | X | ✅ / ❌ |
| Tags/Properties | X | X | ✅ / ❌ |
Acceptable variance should be near 0%. Any discrepancy above 0.5% warrants investigation.
Field-Level Validation
- Sample 5% of contacts and verify all fields (name, email, phone, custom properties) match.
- Open 20+ conversations at random in Freshchat and compare message content, sender attribution, and timestamps against tawk.to exports.
- Verify that conversations are linked to the correct contacts — not orphaned.
Sampling Strategy
- Pull the oldest conversation, the newest, and several mid-range conversations from each date bucket.
- Check conversations with attachments separately — verify files are accessible.
- Check conversations from anonymous visitors — verify placeholder contacts exist.
UAT Process
- Import into a Freshchat sandbox or test account first.
- Have agents review familiar conversations to verify accuracy.
- Test search functionality — can agents find migrated conversations by contact email?
- Verify that conversation statuses (resolved, new) are set correctly.
Rollback Planning
- Freshchat does not have a bulk delete for imported conversations. If the migration fails validation, you'll need to delete records individually via API or request a data purge from Freshworks support. For large failed imports (10,000+ records), contact Freshworks support directly — they can perform account-level data purges that aren't available through the API.
- Keep your tawk.to account active until validation is complete and stakeholders sign off.
Post-Migration Tasks
Rebuild Configuration
- Automations: Recreate tawk.to triggers and shortcuts as Freshchat assignment rules, auto-resolve rules, and canned responses.
- Channels: Set up web, mobile, and social channels in Freshchat. Update the chat widget on your website.
- Routing: Configure IntelliAssign or manual assignment rules to replace tawk.to's department routing.
- CSAT: Set up satisfaction surveys in Freshchat — these don't migrate from tawk.to.
Agent Onboarding
- Walk agents through the Freshchat inbox, conversation views, and keyboard shortcuts.
- Show how migrated conversations appear and how to search historical chats.
- Set expectations: migrated conversations will look slightly different from native Freshchat conversations (timestamps in message body, formatting differences).
- Emphasize how Freshchat's continuous conversation UI differs from tawk.to's session-based view.
Monitor for Data Inconsistencies
- Watch for contacts reaching out who can't see their conversation history in the widget. Migrated conversations are in Freshchat's backend but will not appear in the end-user-facing messenger unless
external_idandrestore_idare properly configured (see the Widget Identity Linking section above). - Monitor for duplicate contacts created when returning visitors are not matched to migrated records.
Best Practices
- Back up everything first. Export all tawk.to data (chats, tickets, contacts, KB) before making any changes. Store exports in a secure, versioned location.
- Always use a staging environment. Run a full test migration into a Freshchat sandbox before touching production.
- Create contacts before conversations. Freshchat requires a valid
user_idto associate with a conversation. Import contacts first, build your ID mapping table, then import conversations. - Pre-create Freshchat scaffolding. Set up agents, groups, channels, and custom contact properties before starting the data import.
- Deduplicate early. Clean your tawk.to contacts list before export. Merge duplicates, remove test records, and standardize email formats.
- Freeze configuration. Do not allow admins to change custom fields, agent roles, or routing rules in either system during the migration window.
- Log everything. Every API call, every error, every skipped record. If a message fails to post due to a malformed character, you need the exact tawk.to ID to retry it.
- Download attachments during extraction. Don't rely on tawk.to attachment URLs being available indefinitely. Store all files locally before starting the import.
- Validate incrementally. Don't wait for the final weekend to check results. Validate after each batch.
- Keep source IDs. Store tawk.to source IDs in custom fields or an external audit table for provenance tracking.
Sample Automation Script
Below is a high-level Python outline for the full migration pipeline:
"""
tawk.to → Freshchat Migration Script (Outline)
Requires: requests, json, csv, time, logging
"""
import json, csv, time, logging, requests
# --- Configuration ---
TAWK_EXPORT_DIR = "./tawk_exports/"
CONTACT_CSV = "./tawk_contacts.csv"
FRESHCHAT_URL = "https://your-domain.freshchat.com/v2"
FRESHCHAT_TOKEN = "your-bearer-token"
CHANNEL_ID = "target-channel-uuid"
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("migration")
headers = {
"Authorization": f"Bearer {FRESHCHAT_TOKEN}",
"Content-Type": "application/json"
}
# --- Step 1: Import contacts, build ID map ---
def import_contacts():
id_map = {}
with open(CONTACT_CSV) as f:
reader = csv.DictReader(f)
for row in reader:
names = (row.get("Name", "") or "").split(" ", 1)
first = names[0]
last = names[1] if len(names) > 1 else ""
email = row.get("Primary Email", "")
if not email:
continue
user = create_freshchat_user(first, last, email)
id_map[email] = user["id"]
logger.info(f"Created user {email} -> {user['id']}")
return id_map
# --- Step 2: Transform and import conversations ---
def import_conversations(id_map, agent_map):
for export_file in get_export_files(TAWK_EXPORT_DIR):
with open(export_file) as f:
chats = json.load(f)
for chat in chats:
visitor_email = chat.get("visitor", {}).get("email")
user_id = id_map.get(visitor_email)
if not user_id:
user_id = create_anonymous_user(chat["id"])
messages = transform_messages(
chat["messages"], user_id, agent_map
)
create_freshchat_conversation(
user_id, CHANNEL_ID, messages
)
logger.info(f"Migrated chat {chat['id']}")
# --- Step 3: Validate ---
def validate():
# Compare record counts
# Sample field-level checks
# Report discrepancies
pass
if __name__ == "__main__":
agent_map = build_agent_mapping()
id_map = import_contacts()
import_conversations(id_map, agent_map)
validate()This is an outline, not production code. Real implementations need exponential backoff, checkpoint/resume logic for recovering from mid-migration failures, attachment handling, dead-letter queues for failed records, and comprehensive error logging.
Making the Right Call
Migrating from tawk.to to Freshchat is an architectural shift — from session-based chat to continuous, omnichannel messaging. The concept is straightforward (extract, transform, load), but the operational complexity comes from tawk.to's gated API, missing custom attribute exports, Freshchat's lack of a bulk import endpoint, and the timestamp limitation that prevents historical backdating.
For small accounts with simple data, a manual export plus scripted import works. For anything beyond a few thousand conversations, the engineering time, error handling, and validation effort escalates quickly — refer to the effort estimates in the approach comparison section to calibrate your expectations.
For related reading, check out our Freshchat to HappyFox migration guide and our help desk data migration checklist.
Frequently Asked Questions
- Can I directly import tawk.to chats into Freshchat?
- No. There is no native import tool, connector, or CSV upload that maps tawk.to data into Freshchat. You need to export from tawk.to (JSON via dashboard or REST API), transform the data to match Freshchat's conversation schema, and import via the Freshchat REST API.
- Does tawk.to have a public API for data export?
- tawk.to has a REST API, but it is in private beta and requires a formal access request. Approval can take weeks to months, and some users report waiting over a year. The API documentation is only shared after approval. For migration purposes, you may need to rely on manual dashboard exports (JSON/CSV) as a fallback.
- How do I retain the original timestamps of my tawk.to chats in Freshchat?
- Freshchat's API sets created_time as a system-generated field and does not accept historical timestamps as input. The workaround is to prepend the original historical timestamp as text within the message body during migration (e.g., '[Original Time: 2023-04-12 14:32] Client: Hello').
- What tawk.to data cannot be migrated to Freshchat?
- Freshchat does not support ticketing or Knowledge Base articles — those belong to Freshdesk. tawk.to tickets, KB content, satisfaction survey results, and chat analytics have no direct equivalent in Freshchat. Custom attributes on contacts are also excluded from tawk.to's CSV export and require API access or manual extraction.
- How long does a tawk.to to Freshchat migration take?
- It depends on data volume and method. A small account (under 5,000 conversations) can be migrated in 1–3 days. Mid-size accounts (5K–50K conversations) typically take 3–7 days including validation. Enterprise-scale migrations may take 1–2 weeks. Working with a managed migration service typically compresses timelines.
