Skip to content

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.

Raaj Raaj · · 26 min read
tawk.to to Freshchat Migration: A Technical Guide
TALK TO AN ENGINEER

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)
Warning

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_parts schema

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_parts structure. Getting this wrong means garbled conversation history.
  • Orphaned records. Conversations imported without matching contacts create orphaned threads in Freshchat. Freshchat requires a valid user_id to 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

  1. What moves as data: Chat conversations with full message history, contacts with attributes, tags.
  2. What gets rebuilt as configuration: Agents, groups, channels, automations, routing rules, CSAT settings.
  3. What gets archived: Chat analytics, satisfaction survey results, KB articles (if not moving to Freshdesk).
  4. 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:
    1. Phase 1 (Historical): Migrate all data up to a specific freeze date.
    2. Phase 2 (Delta): Migrate any new chats that occurred during the historical sync.
    3. 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_name and last_name for 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 properties on Freshchat contacts. These must be defined in Freshchat before import.
  • Use tawk.to's email as the reference_id in 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_parts object with a text.content field.
  • The sender type must be mapped: visitor → actor_type: "user", agent → actor_type: "agent".
  • You need valid Freshchat user_id and agent_id values — contacts and agents must be created in Freshchat before importing conversations.
  • channel_id is required — map to your designated Freshchat channel.
Warning

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.
Info

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

  1. Log in as Admin
  2. Navigate to Inbox → Chats (or Tickets)
  3. Apply date filters to scope the batch
  4. Select conversations → Export → Enter recipient email
  5. Download ZIP from emailed link
  6. Repeat for each batch/date range
  7. 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 resp
Info

Freshchat'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_time values 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

  1. Import into a Freshchat sandbox or test account first.
  2. Have agents review familiar conversations to verify accuracy.
  3. Test search functionality — can agents find migrated conversations by contact email?
  4. 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_id and restore_id are 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

  1. Back up everything first. Export all tawk.to data (chats, tickets, contacts, KB) before making any changes. Store exports in a secure, versioned location.
  2. Always use a staging environment. Run a full test migration into a Freshchat sandbox before touching production.
  3. Create contacts before conversations. Freshchat requires a valid user_id to associate with a conversation. Import contacts first, build your ID mapping table, then import conversations.
  4. Pre-create Freshchat scaffolding. Set up agents, groups, channels, and custom contact properties before starting the data import.
  5. Deduplicate early. Clean your tawk.to contacts list before export. Merge duplicates, remove test records, and standardize email formats.
  6. Freeze configuration. Do not allow admins to change custom fields, agent roles, or routing rules in either system during the migration window.
  7. 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.
  8. Download attachments during extraction. Don't rely on tawk.to attachment URLs being available indefinitely. Store all files locally before starting the import.
  9. Validate incrementally. Don't wait for the final weekend to check results. Validate after each batch.
  10. 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()
Tip

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.

More from our Blog

Best Practices for a Successful Help Desk Data Migration
Help Desk

Best Practices for a Successful Help Desk Data Migration

Helpdesk migration can feel daunting—but it doesn’t have to be. This guide from ClonePartner walks you through a 7-step roadmap covering planning, backups, testing, and communication to ensure a smooth, secure transition without data loss or downtime.

Raaj Raaj · · 7 min read