Skip to content

How to Export Data from Freshchat: Methods, API Limits & Formats

Freshchat has no bulk export button. Learn every method to extract conversations, messages, users, and attachments via the API, with rate limits and format details.

Nachi Nachi · · 21 min read
How to Export Data from Freshchat: Methods, API Limits & Formats
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

Freshchat has no one-click "Export All" button. Unlike Freshdesk, which offers an admin-panel XML account export, Freshchat forces you to reconstruct your dataset from multiple API endpoints, async report jobs, and one-at-a-time transcript apps. There is no admin-panel bulk download for conversations, users, or message history.

Every complete Freshchat data export is an engineering project: an API token, a script that handles pagination and rate limits, a strategy for stitching conversations back together from their component messages, and a plan for downloading attachments before their signed URLs expire.

This guide covers exactly what you can get out, what you will lose, and how long it takes.

API behavior verified against Freshchat API v2 documentation as of June 2025. Endpoint names, rate limits, and pagination behavior may change — verify against developers.freshchat.com before starting your export.

If you're exporting as part of a migration, these destination-specific guides cover field mapping: Freshchat to Groove, Freshchat to Unthread, Freshchat to HappyFox, or Freshchat to Salesforce Service Cloud.

Info

TL;DR: Freshchat has no bulk export. The REST API v2 covers conversations, messages, users, agents, groups, channels, and roles — all in JSON. The Reports API exports chat transcripts and analytics as CSV in time-windowed batches. Attachments must be downloaded individually via pre-signed S3 URLs embedded in message objects (TTL varies but treat as short-lived — download within minutes of retrieval). Bot configurations and automation rules are not exportable through any method. There is no documented global conversations list endpoint; you must enumerate users first, then fetch conversations per user, or use the Reports API to obtain conversation IDs in bulk. For accounts with 50,000+ conversations on Pro/Enterprise plans (2,000 requests/minute), expect 2–5 days of sustained extraction and validation.

What Data Can You Export from Freshchat?

Freshchat is a conversation-centric messaging platform, not a traditional ticketing system. The core objects are Users (your customers), Conversations (the container), Messages (individual chat messages within a conversation), Agents, Groups, Channels (called Topics in the UI), Roles, and CSAT Ratings.

Freshsales Suite vs. standalone Freshchat: Freshsales Suite accounts are Freshchat instances provisioned through Freshsales CRM, identifiable by the .myfreshworks.com domain pattern (e.g., yourco.myfreshworks.com). Standalone Freshchat accounts use yourco.freshchat.com. Several API behaviors differ between the two — these are flagged throughout this guide.

Object API Export (JSON) Reports API (CSV) Known Limitations
Conversations ✅ via /v2/conversations/{id} ✅ Chat-Transcript report API returns metadata only — no messages in the response. Must call messages endpoint separately.
Messages ✅ via /v2/conversations/{id}/messages ✅ (within Chat-Transcript) Max 50 messages per page. No "list all messages" endpoint. Messages return in chronological order (oldest first) by default; use sort_order=desc for reverse.
Users (Contacts) ✅ via /v2/users Requires at least one query filter (name, email, date range). No unfiltered list-all endpoint.
Agents ✅ via /v2/agents ✅ Agent-Activity report No native UI file export.
Groups ✅ via /v2/groups Read-only. No member listing in the group object.
Channels (Topics) ✅ via /v2/channels Multi-language support requires locale param.
Roles ✅ via /v2/roles Returns role names but not granular permission sets.
CSAT Ratings ✅ via create only ✅ CSAT-Score report No GET endpoint to list all CSATs. Must use Reports API for bulk access.
Conversation Properties ✅ via /conversations/fields Only available for Freshsales Suite accounts (.myfreshworks.com domain). Default properties like group, agent, and status are not returned — only priority and custom properties.
Attachments/Files ✅ (pre-signed S3 URLs in message objects) URLs are time-limited (pre-signed with short TTL — download immediately upon retrieval). Must download during the export run.
Reports (raw metrics) ✅ via /reports/raw 24-hour max window for Chat-Transcript; 30-day max for others.
Bot configurations No API access to bot flows or dialog trees.
Automation rules Not exportable through any method.
Assignment rules Configuration only. No API endpoint.

[For engineering] The GET /v2/conversations/{conversation_id} endpoint does not return messages or user arrays in the response. You must make a separate call to /v2/conversations/{conversation_id}/messages to retrieve the actual chat content. This is the most common gotcha that results in exporting conversation metadata without actual chat history.

[For engineering] There is a quiet custom-field gap. Freshchat's /conversations/fields endpoint is only available for Freshsales Suite accounts (.myfreshworks.com domain), and default conversation properties such as group, agent, and status are not returned — you only get priority plus custom properties. If you are mapping custom fields to another system, test this endpoint early. (developers.freshchat.com)

Export Methods: Every Way to Get Data Out of Freshchat

There are seven practical export paths, and they solve different problems.

Method Data Coverage Volume Limit Speed Complexity Best For
REST API v2 Conversations, messages, users, agents, groups, channels, roles Plan-dependent rate limits Moderate High Full data export with relationships intact
Reports API Chat transcripts, performance metrics, CSAT, agent activity 24h or 30-day windows per request Slow (async) Medium Bulk transcript dumps, analytics, compliance
Webhooks Real-time message, conversation, and user events No volume limit (push-based) Real-time Medium Incremental sync, ongoing replication, event-driven pipelines
Download Transcript App Single conversation transcript 200 messages max Fast Low One-off transcript requests
Analytics Data Export Derived analytics modules App-enforced size limits Fast Low BI dashboards, ops reporting
Single-user GDPR export One user's data One user at a time Fast Low DSAR handling
Third-party ETL (dlt, Portable) Varies by connector Rate-limit-constrained Moderate Medium Warehousing, BI pipelines

Webhooks for Incremental Export

Freshchat supports webhook subscriptions via POST /v2/webhooks for real-time event streaming. Available events include onMessageCreate, onConversationUpdate, onUserCreate, and others. Webhooks push JSON payloads to your endpoint as events occur, which is useful for:

  • Ongoing replication: Stream new messages and conversations to a data warehouse in near-real-time instead of polling.
  • Incremental backup: Capture changes since your last full export without re-enumerating all users and conversations.
  • Migration bridge: During a migration cutover window, webhooks can capture conversations created between your final export and go-live.

Webhooks do not replace a full historical export — they only capture events from the moment of subscription forward. For a complete export, combine a one-time REST API extraction with webhooks for incremental updates.

[For PMs] If you only need dashboards or a single transcript, the UI options are enough. If you need full historical portability, the REST API plus /reports/raw is the supported path that gets you closest to record fidelity. For ongoing sync, webhooks are the correct real-time mechanism. There is no documented direct database export path in Freshchat's public docs. (developers.freshchat.com)

Native UI Export: What Freshchat Does (and Doesn't) Offer

Freshchat does not have an admin-panel data export feature like Freshdesk's Admin → Account → Export Data XML dump. This is a material difference: Freshdesk lets an admin download their entire account as XML, while Freshchat provides no equivalent. The native UI options are limited to analytics tools and single-conversation utilities.

Analytics Data Export

Navigate to Analytics → Settings → Data Export. Pick a module, schedule, timezone, filters, and fields, with delivery by email or API link. This produces CSV-style analytics feeds — useful for dashboards, but this is derived report data, not a system-of-record archive. (crmsupport.freshworks.com)

Report and Widget Export

Curated chat reports can be exported to email or downloaded as PDF. Widget data can be exported as CSV or PDF. Useful for operations teams, but not for migration or backup.

Download Transcript App

The closest thing to a native conversation export:

  1. Navigate to Admin Settings → Marketplace for Chat
  2. Search for "Download Transcript" and install it
  3. Open any conversation in the inbox
  4. Click the app icon to download that conversation's transcript as .txt
Warning

The Download Transcript app caps at 200 messages per conversation. For long-running support threads or WhatsApp conversations that exceed 200 messages, the transcript will be silently truncated — no warning is displayed in the UI. Attachments are not included in the .txt output.

Single-User GDPR Export

Navigate to Settings → Security and Compliance → GDPR → Users, search for the user, and click Request Data. This handles individual DSAR requests but is not a bulk export tool. (freshworks.com)

Warning

None of these native UI paths cover the hard parts of a migration: bulk user history, bundled attachments, admin configuration, or relationship preservation between users, conversations, messages, agents, groups, and topics.

API-Based Export: Endpoints, Pagination, and Rate Limits

Authentication

Freshchat uses Bearer token authentication. Generate your API token at Admin → Configure → API Tokens → Generate Token. For Freshsales Suite accounts (.myfreshworks.com domain), navigate to Settings → Admin Settings → Website Tracking and APIs → API Settings.

All requests require:

Authorization: Bearer <API_KEY>
Accept: application/json

The base URL follows this pattern:

https://<account-name>.freshchat.com/v2/<resource>

For Freshsales Suite integrated accounts:

https://<account-url>.myfreshworks.com/v2/<resource>

Rate Limits by Plan

Freshchat's API rate limits for chat/conversations are account-level (not per-agent), applied per minute:

Plan Rate Limit (chat/conversations API) Dashboard/Metrics API
Free No documented API access N/A
Growth No documented API access N/A
Pro 2,000 requests/minute 100 requests/minute
Enterprise 2,000 requests/minute 100 requests/minute

Free and Growth plans do not have documented API access for chat/conversations as of the current API v2 documentation. The 2,000 req/min limit appears to be a fixed-window bucket (resets each minute), not a sliding window — confirmed by observing the X-RateLimitReset header behavior, which aligns with fixed-window semantics. However, Freshworks does not formally specify window type in their documentation.

When you exceed the limit, you receive HTTP 429 Too Many Requests. Monitor these response headers on every call:

  • X-RateLimit-Limit — total permitted calls in the window
  • X-RateLimit-Remaining — calls left
  • X-RateLimitReset — time (epoch seconds) until the window resets

Freshchat API v1 vs. v2: Freshchat previously exposed a v1 API with different endpoints and authentication. The v2 API is the current supported version. This guide covers v2 exclusively. If you encounter v1 endpoint references in older documentation or community posts, do not mix them — authentication and response shapes differ.

Pagination

Freshchat uses page-number-based pagination. Key parameters:

  • page — starting from 1 (default: 1)
  • items_per_page — records per page (default: 10)
  • sort_orderasc or desc

Critical page size limits:

  • Messages endpoint: max 50 items per page
  • Users/Agents/Groups: max 100 items per page

The response includes a pagination object with total_items, total_pages, current_page, and items_per_page, plus a links object with next_page, previous_page, first_page, and last_page hrefs. (developers.freshchat.com)

Core Export Endpoints

Endpoint Method What It Returns
/v2/users?email=...&created_from=... GET Users matching filter criteria
/v2/users/fetch POST Up to 100 users by IDs (batch)
/v2/users/{user_id}/conversations GET Conversation IDs for a user
/v2/conversations/{conversation_id} GET Conversation metadata (no messages)
/v2/conversations/{conversation_id}/messages GET Messages in a conversation (max 50/page, chronological order by default)
/v2/agents GET All agents (paginated)
/v2/groups GET All groups
/v2/channels GET All channels/topics
/v2/roles GET All roles
/v2/webhooks POST Register webhook for real-time events
/reports/raw POST Async report extraction (CSV)
/reports/raw/{id} GET Report download URL

The Core Challenge: No Global Conversations Endpoint

There is no GET /v2/conversations list endpoint in the public API that returns all conversations across the account. You must either:

  1. User-first enumeration: Extract all users first, then fetch conversations per user via GET /v2/users/{user_id}/conversations
  2. Reports-first enumeration: Use the Reports API's Chat-Transcript event to get conversation IDs in bulk, then hydrate metadata and messages via the REST API

Both paths require user-level or time-windowed enumeration. This is the architectural bottleneck that turns every Freshchat export into a multi-step engineering project. (developers.freshchat.com)

For multi-account enterprises: If your organization operates multiple Freshchat accounts (common in multi-brand or regional setups), each account requires its own API token and independent extraction run. There is no cross-account API.

Full Export Script

import requests
import time
import json
import os
 
BASE_URL = "https://yourco.freshchat.com/v2"
HEADERS = {
    "Authorization": "Bearer YOUR_API_KEY",
    "Accept": "application/json"
}
ATTACHMENT_DIR = "./attachments"
os.makedirs(ATTACHMENT_DIR, exist_ok=True)
 
def api_get(url, params=None):
    """GET with rate-limit handling, retry, and deleted-user tolerance."""
    while True:
        resp = requests.get(url, headers=HEADERS, params=params)
        if resp.status_code == 429:
            retry_after = int(resp.headers.get("Retry-After", 60))
            print(f"Rate limited. Waiting {retry_after}s...")
            time.sleep(retry_after)
            continue
        if resp.status_code == 404:
            # Handle deleted users/conversations gracefully
            print(f"404 for {url} — resource deleted or not found. Skipping.")
            return None
        resp.raise_for_status()
        return resp.json()
 
# Step 1: Export all agents
def export_agents():
    agents = []
    page = 1
    while True:
        data = api_get(f"{BASE_URL}/agents",
                       {"page": page, "items_per_page": 100})
        if data is None:
            break
        agents.extend(data.get("agents", []))
        if page >= data["pagination"]["total_pages"]:
            break
        page += 1
    return agents
 
# Step 2: Export all users (requires date-range windowing)
def export_users(start_date, end_date):
    """
    Users endpoint requires at least one filter.
    Use date-range windows (e.g., monthly) to enumerate all users.
    """
    users = []
    page = 1
    while True:
        data = api_get(f"{BASE_URL}/users", {
            "created_from": start_date,
            "created_to": end_date,
            "page": page,
            "items_per_page": 100
        })
        if data is None:
            break
        users.extend(data.get("users", []))
        pagination = data.get("pagination", {})
        if page >= pagination.get("total_pages", 1):
            break
        page += 1
    return users
 
# Step 3: For each user, get conversation IDs
def get_user_conversations(user_id):
    data = api_get(f"{BASE_URL}/users/{user_id}/conversations")
    if data is None:
        return []  # User may have been deleted (GDPR)
    return [c["id"] for c in data.get("conversations", [])]
 
# Step 4: For each conversation, get all messages and download attachments
def export_messages(conversation_id):
    messages = []
    page = 1
    while True:
        data = api_get(
            f"{BASE_URL}/conversations/{conversation_id}/messages",
            {"page": page, "items_per_page": 50}
        )
        if data is None:
            break
        batch = data.get("messages", [])
        for msg in batch:
            download_attachments(msg, conversation_id)
        messages.extend(batch)
        if len(batch) < 50:
            break
        page += 1
    return messages
 
# Step 5: Download attachments from message_parts before signed URLs expire
def download_attachments(message, conversation_id):
    """
    Detect file/image objects in message_parts and download immediately.
    Pre-signed S3 URLs have a short TTL — download within the same script run.
    """
    for part in message.get("message_parts", []):
        for key in ("file", "image"):
            obj = part.get(key)
            if obj and "url" in obj:
                filename = obj.get("name", f"{message['id']}_{key}")
                local_path = os.path.join(
                    ATTACHMENT_DIR, conversation_id, filename
                )
                os.makedirs(os.path.dirname(local_path), exist_ok=True)
                try:
                    resp = requests.get(obj["url"], timeout=30)
                    resp.raise_for_status()
                    with open(local_path, "wb") as f:
                        f.write(resp.content)
                    obj["local_path"] = local_path  # Replace URL with local ref
                except Exception as e:
                    print(f"Failed to download {obj['url']}: {e}")
 
# Orchestration: deduplicate conversation IDs across users
def full_export(date_ranges):
    """
    date_ranges: list of (start, end) tuples covering your account lifetime.
    """
    all_agents = export_agents()
    all_users = []
    for start, end in date_ranges:
        all_users.extend(export_users(start, end))
 
    seen_convos = set()
    all_conversations = {}
 
    for user in all_users:
        convo_ids = get_user_conversations(user["id"])
        for cid in convo_ids:
            if cid not in seen_convos:
                seen_convos.add(cid)
                # Fetch conversation metadata
                meta = api_get(f"{BASE_URL}/conversations/{cid}")
                msgs = export_messages(cid)
                all_conversations[cid] = {
                    "metadata": meta,
                    "messages": msgs
                }
 
    return {
        "agents": all_agents,
        "users": all_users,
        "conversations": all_conversations
    }

This code handles Freshchat's actual constraints: user-windowing, per-user conversation enumeration, 50-message pagination, 404 tolerance for deleted users, and immediate attachment download. Deduplicate conversation IDs across users before fetching messages, since multiple users may share conversations (e.g., group chats or reassigned threads).

Throughput Math

At 2,000 requests/minute (Pro/Enterprise):

  • Agents, Groups, Channels, Roles: Small datasets. Typically done in under 20 requests total.
  • Users: At 100 users/page, 10,000 users = 100 requests = ~3 seconds.
  • Conversation IDs: 1 request per user. 10,000 users = 10,000 requests = ~5 minutes.
  • Messages: 1+ requests per conversation (depends on message count). 10,000 conversations averaging 20 messages each = ~10,000 requests = ~5 minutes.
  • Total for 10,000 conversations: ~20,000 API calls = ~10 minutes at sustained max rate.
  • Total for 100,000 conversations: ~200,000 API calls = ~100 minutes (under 2 hours).

Real-world throughput is 30–50% lower due to retry overhead from 429s, variable message counts per conversation, attachment download time (which doesn't consume API rate limit but adds wall-clock time), and 404 handling for deleted users.

How to Export Chat Transcripts from Freshchat

The Reports API is the most efficient way to export chat transcripts in bulk. It produces async CSV files covering a defined time window.

# Step 1: Request a Chat-Transcript report (max 24-hour window)
curl -X POST "https://api.freshchat.com/v2/reports/raw" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "start": "2024-01-01T00:00:00.000Z",
    "end": "2024-01-01T23:59:59.000Z",
    "event": "Chat-Transcript",
    "format": "csv"
  }'
 
# Step 2: Poll for completion
curl -X GET "https://api.freshchat.com/v2/reports/raw/{report_id}?status=COMPLETED" \
  -H "Authorization: Bearer YOUR_TOKEN"
 
# Step 3: Download the CSV from the signed S3 URL in the response
# IMPORTANT: Download link expires after approximately 1 hour

The Chat-Transcript report includes: conversation_id, conversation_url, customer_id, message_id, message_parts (as serialized JSON), actor_type, actor_id, actor_email, created_time, message_type, message_source, channel_name, and more.

Warning

The Chat-Transcript report enforces a 24-hour maximum time window per request. To export a year of transcripts, you need 365 sequential report requests. Report download links expire after approximately 1 hour. Note: a Freshworks support article references a 1-month max timerange for Chat-Transcript, but the API reference specifies 24 hours. Treat 24 hours as the safe planning assumption until you test your specific tenant — behavior may vary by account type. (developers.freshchat.com)

Other available report event types: Conversation-Created, Message-Sent, Conversation-Resolved, CSAT-Score, First-Response-Time, Response-Time, Resolution-Time, Agent-Activity, Conversation-Activity.

Combining Reports API with REST API: The most efficient full-export strategy for large accounts is to use the Reports API to obtain all conversation_id values across your history (via Chat-Transcript or Conversation-Created events in 24-hour windows), then hydrate each conversation with metadata and messages via the REST API. This avoids the user-first enumeration bottleneck entirely for conversation discovery.

Does Freshchat Export Include Attachments?

Freshchat does not bundle attachments into any export file. Attachments are embedded as pre-signed S3 URLs within message_parts objects in the API response.

When a message includes a file, the message_parts array contains a file object with:

  • name — filename
  • url — pre-signed S3 download URL
  • file_size_in_bytes — size
  • content_type — MIME type
  • file_extension — e.g., .pdf, .png

Images sent inline appear as image objects with a url field.

Key constraints:

  • The S3 URLs are pre-signed with a short TTL. Freshworks does not publicly document the exact expiration window. In practice, treat these as expiring within minutes to hours — download them immediately in the same script run that retrieves the message. Do not store URLs for later bulk download.
  • Maximum file upload size is 25 MB per file.
  • There is no bulk attachment download endpoint. Each file must be fetched individually via its URL.
  • The Reports API (CSV transcripts) includes message_parts as serialized JSON within a CSV cell — you need to parse the JSON out of the CSV to extract attachment URLs.
  • The Download Transcript app outputs .txt only and does not include file attachments.

[For engineering] Build your export script to detect file and image objects inside message_parts, download each to local storage immediately upon retrieval, and replace the S3 URL with a local path reference in your export record. Map each file back to its original conversation_id and message_id for future import. The code sample above demonstrates this pattern in the download_attachments function.

What Data Cannot Be Exported from Freshchat?

Be explicit about these gaps with stakeholders before starting any export project:

Data Type Exportable? Workaround
Bot flow configurations Manual recreation. No API exposure. See scoping guidance below.
Automation/Assignment rules Screenshot or manual documentation.
IntelliAssign configuration Manual recreation in target platform.
Custom app configurations Reconfigure in target.
Saved views/filters Manual recreation.
Agent permissions detail Partial Roles API returns role names but not granular permission sets.
Business hours config Partial Only a verify endpoint; no GET for full schedule.
Deleted users/conversations GDPR deletion is permanent. No recovery. Export before retention or cleanup windows.
Widget customization Manual reconfiguration.
WhatsApp template approvals Re-submit templates in new platform.
Audit logs No API endpoint for system audit trail.

Scoping Bot Flow Recreation

[For CTOs] The most impactful gap is the absence of bot flow exports. If your team has built Freddy bot dialogs, those must be manually documented and recreated in any target platform. No API, no JSON, no workaround.

Scoping the recreation effort depends on bot complexity:

Bot Complexity Indicators Estimated Documentation Time Estimated Rebuild Time
Simple ≤5 dialogs, no conditional branching, FAQ-style responses 2–4 hours 1–2 days
Moderate 6–20 dialogs, basic conditionals, API integrations, multi-language 1–2 days 3–5 days
Complex 20+ dialogs, nested conditional branches, custom API actions, context-passing between flows, multi-channel (web + WhatsApp + Facebook) 3–5 days 1–3 weeks

Count your dialogs, conditional branches, and external API integrations in the Freddy bot builder before estimating. Each external API action and each conditional branch point adds materially to rebuild time.

Data Format, Encoding, and Cleanup After Export

All REST API responses are JSON (UTF-8). The Reports API produces CSV files. The Download Transcript app outputs .txt. The single-user GDPR export is email-delivered.

Common data quality issues after export:

  • HTML in message content: The message_parts.text.content field can contain HTML markup, especially for bot-sent messages with rich formatting (carousel cards, quick replies, button templates). Strip or convert as needed for your target.
  • Nested JSON in CSV: Chat-Transcript CSV reports embed message_parts as a JSON string inside a CSV cell. Standard CSV tools (Excel, Google Sheets) will choke on this — you need a parser that handles nested structures. Use Python's csv + json.loads() or equivalent.
  • UUID-based IDs: All Freshchat IDs (users, conversations, agents, groups) are UUIDs (e.g., a1b2c3d4-5678-90ab-cdef-1234567890ab), not sequential integers. ID mapping to a target platform must account for this format difference.
  • Timezone handling: All timestamps are UTC in ISO 8601 format (e.g., 2024-01-15T14:30:00.000Z). No timezone conversion is applied. Ensure your destination system does not double-shift upon import.
  • Reopened conversations: Reopened threads get a new interaction_id while keeping the same conversation_id. Deduping on interaction_id will overcount unique conversations, while deduping only on conversation_id will hide reopen cycles. Use conversation_id for unique conversation counts and interaction_id to track lifecycle events within a conversation.
  • Orphaned references: If a user was deleted (GDPR), their actor_id in messages still exists, but GET /v2/users/{id} returns 404. Your export script must handle these gracefully (log and continue) rather than crashing. The code sample above demonstrates this with 404 handling in api_get.
  • Rich message parts: Bot messages may contain structured objects like carousel, quick_reply, and button parts that have no direct equivalent in most ticketing systems. Decide upfront whether to flatten these to plain text or preserve the JSON structure.

Post-Export Validation Checklist

[For PMs] Before you consider the extraction complete:

  1. Verify conversation count matches expected total from the Freshchat dashboard
  2. Spot-check 10 random conversations: compare message count in export vs. UI
  3. Confirm all attachment URLs resolved to downloaded files (check for zero-byte files)
  4. Validate CSAT ratings count against dashboard numbers
  5. Check for truncated transcripts (conversations with 200+ messages if using the Download Transcript app)
  6. Verify agent/group assignment data is present on each conversation
  7. Confirm custom properties (cf_ prefixed fields) exported with values
  8. Group by conversation_id and interaction_id separately to catch reopen logic
  9. Parse JSON columns inside CSV before loading to the target system
  10. Count distinct actor_id values that return 404 — these are deleted users whose messages exist but whose profiles are gone

Export for Migration vs. Backup vs. Compliance

The scope of your export changes based on the business objective.

Migration

You need conversations with full message threads, user-to-conversation relationships, agent assignments, and CSAT scores. The REST API is the correct tool. The Reports API produces flat CSVs that lose the relational structure between conversations, messages, and users.

Conversations must preserve chronological message order, agent assignments at each point, and the relationship between user objects and their conversations. You must maintain an ID mapping table between Freshchat UUIDs and your destination platform's IDs to preserve relational integrity.

The critical transformation challenge: Freshchat uses a conversation-message model (flat list of messages within a conversation container). Most helpdesk targets (Zendesk, Freshdesk, Help Scout, Intercom) use tickets with replies (a ticket has a description, then threaded replies with internal/public distinction). That structural mismatch is where migrations fail — specifically:

  • Freshchat has no concept of "first reply" vs. "description" — all messages are peers
  • Internal notes must be inferred from actor_type and message metadata
  • Conversation reassignment history must be reconstructed from message-level actor_id changes

See our help desk data migration playbook for destination-agnostic planning guidance.

Tip

Extraction is roughly 20% of the total migration effort. Transforming Freshchat's conversation-message data into the ticket-reply schema of your destination platform, mapping custom fields, and handling rich message types (carousels, quick replies) accounts for the remaining 80%.

Backup

For full-fidelity backup, combine REST API extraction (all objects + attachments) with Reports API (analytics and transcripts). Store the raw JSON payloads in cold storage (e.g., Amazon S3 Glacier, Google Cloud Archive). You do not need to transform the data — just secure it. Schedule recurring runs with date-range windowing to capture incremental changes. Use webhooks (POST /v2/webhooks) for near-real-time incremental capture between full export runs. Report download links expire after approximately 1 hour, so your pipeline must fetch and persist CSV files immediately after generation completes.

Compliance (GDPR / DSAR)

Freshchat supports GDPR through per-user data export and deletion via the API. For data subject access requests, use GET /v2/users/{user_id} combined with /v2/users/{user_id}/conversations and fetch all messages per conversation.

The DELETE /v2/users/{user_id} endpoint permanently removes a user's record for right-to-erasure requests. The GDPR admin page (available to Account Owners) provides options to "forget" individual contacts, bypassing any recycle bin. (freshworks.com)

GDPR Article 20 (data portability) requires data in a "structured, commonly used, machine-readable format." Freshchat's JSON API output satisfies this requirement. The lack of a one-click bulk export means fulfilling portability requests for your entire dataset requires engineering work, but a single user's DSAR can be handled through the per-user API flow without a full extraction.

For the compliance layer in migrations, see our GDPR-compliant data migration guide.

Vendor Lock-In and Data Portability Assessment

Freshchat data portability rating: Partially Locked.

  • ~70% of your data is extractable through the API with engineering effort: conversations, messages, users, agents, groups, channels, roles, and raw analytics.
  • ~15% requires transformation: attachments (must download individually from time-limited URLs), rich message parts (carousel cards, quick replies, bot responses need structural conversion for any target platform).
  • ~15% is not extractable: bot flows, automation rules, IntelliAssign config, widget customization, WhatsApp template approval states.

The switching cost comes from three places:

  1. No bulk export tool — every export requires custom scripts against the API, with user-windowing and per-conversation message fetching.
  2. Conversation-centric model — most helpdesk targets use tickets, requiring structural transformation of the exported data.
  3. Bot/automation loss — Freddy bot implementations cannot be migrated programmatically; they must be manually documented and rebuilt.

There are no contractual or ToS restrictions on data export. Freshworks permits you to extract your data through the API at any time. API access requires a Pro or Enterprise plan.

How Long Does a Full Freshchat Data Export Take?

Dataset Size Conversations Estimated API Calls Extraction Time (API only) Total Project Time (with script dev + validation)
Small < 10,000 ~25,000 15–30 min 1–2 days
Medium 10,000–100,000 ~250,000 2–4 hours 3–5 days
Large 100,000–500,000 1,000,000+ 8–24 hours 1–2 weeks
Enterprise 500,000+ 5,000,000+ 2–5 days 2–4 weeks

Phase breakdown:

  1. Scoping (2–4 hours): Inventory objects, estimate volumes from dashboard, identify custom properties, count bot dialog complexity
  2. API setup (1–2 hours): Generate token, verify access, test endpoints, confirm plan supports API access
  3. Script development (1–3 days): Build extraction script with pagination, retry logic, 404 handling, attachment download, deduplication
  4. Extraction (15 min to 5 days): Depends on data volume and attachment count
  5. Validation (4–8 hours): Spot checks, count reconciliation, attachment verification, deleted-user audit
  6. Cleanup (2–8 hours): Deduplicate, normalize formats, map IDs, parse nested JSON from CSV

Minimum team composition:

  • Small export: 1 developer, 1 PM (part-time)
  • Medium/Large: 1 developer (full-time for 1 week), 1 PM, 1 QA reviewer
  • Enterprise: 1–2 developers (full-time for 2 weeks), 1 PM, 1 QA, potentially a data engineer for attachment pipeline

When to Bring in Help

If your Freshchat account has more than 50,000 conversations, significant attachment volumes, or complex Freddy bot flows that need documentation before migration, the export project requires sustained engineering effort. The combination of user-windowed enumeration, per-conversation message fetching, signed-URL attachment downloads, and conversation-to-ticket transformation compounds into a multi-week project for medium-to-large accounts.

Frequently Asked Questions

Can I export all my data from Freshchat?
Yes, but not through a single export button. Freshchat requires API-based extraction for conversations, messages, users, agents, groups, channels, and roles. Bot configurations, automation rules, and widget settings cannot be exported through any method. Expect to write custom scripts or use a managed migration service.
Does Freshchat export include attachments?
Not directly. Attachments appear as pre-signed S3 URLs within message objects returned by the API. You must download each file individually before the URL expires. Maximum file size is 25 MB per file. The Reports API CSV includes attachment URLs embedded in JSON strings within the message_parts column.
How long does it take to export data from Freshchat?
For accounts with under 10,000 conversations, API extraction takes 15–30 minutes. Accounts with 100,000+ conversations require 8–24 hours of sustained API calls. Total project time including validation and cleanup ranges from 1–2 days (small) to 1–2 weeks (large).
What format does Freshchat export data in?
The REST API returns all data as JSON (UTF-8). The Reports API exports raw metrics and chat transcripts as CSV files. The Download Transcript app outputs .txt files. There is no XML or native Excel export option.
What are Freshchat's API rate limits for data export?
Freshchat allows 2,000 API requests per minute on Pro and Enterprise plans for chat/conversations. The limit is account-level, not per-agent. Free and Growth plans do not have documented API access for chat data. The dashboard metrics API has a separate 100 requests/minute limit.

More from our Blog

Help Desk Data Migration Playbook: What Data to Move and What to Leave Behind
Help Desk

Help Desk Data Migration Playbook: What Data to Move and What to Leave Behind

This definitive playbook answers the single most critical question: "What data do we actually need to move?". This strategic guide helps you declutter and decide what's precious and what's junk. We provide a clear breakdown of the non-negotiable Tier 1 data, like tickets , knowledge bases , and user profiles, versus the Tier 2 data that provides rich context, like automations and organizations. Use this as your strategic checklist to avoid common mistakes and ensure a flawless, functional new help desk.

Raaj Raaj · · 7 min read