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.
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.
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:
- Navigate to Admin Settings → Marketplace for Chat
- Search for "Download Transcript" and install it
- Open any conversation in the inbox
- Click the app icon to download that conversation's transcript as
.txt
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)
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 windowX-RateLimit-Remaining— calls leftX-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_order—ascordesc
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:
- User-first enumeration: Extract all users first, then fetch conversations per user via
GET /v2/users/{user_id}/conversations - Reports-first enumeration: Use the Reports API's
Chat-Transcriptevent 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 hourThe 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.
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— filenameurl— pre-signed S3 download URLfile_size_in_bytes— sizecontent_type— MIME typefile_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_partsas 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
.txtonly 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.contentfield 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_partsas 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'scsv+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_idwhile keeping the sameconversation_id. Deduping oninteraction_idwill overcount unique conversations, while deduping only onconversation_idwill hide reopen cycles. Useconversation_idfor unique conversation counts andinteraction_idto track lifecycle events within a conversation. - Orphaned references: If a user was deleted (GDPR), their
actor_idin messages still exists, butGET /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 inapi_get. - Rich message parts: Bot messages may contain structured objects like
carousel,quick_reply, andbuttonparts 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:
- Verify conversation count matches expected total from the Freshchat dashboard
- Spot-check 10 random conversations: compare message count in export vs. UI
- Confirm all attachment URLs resolved to downloaded files (check for zero-byte files)
- Validate CSAT ratings count against dashboard numbers
- Check for truncated transcripts (conversations with 200+ messages if using the Download Transcript app)
- Verify agent/group assignment data is present on each conversation
- Confirm custom properties (
cf_prefixed fields) exported with values - Group by
conversation_idandinteraction_idseparately to catch reopen logic - Parse JSON columns inside CSV before loading to the target system
- Count distinct
actor_idvalues 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_typeand message metadata - Conversation reassignment history must be reconstructed from message-level
actor_idchanges
See our help desk data migration playbook for destination-agnostic planning guidance.
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:
- No bulk export tool — every export requires custom scripts against the API, with user-windowing and per-conversation message fetching.
- Conversation-centric model — most helpdesk targets use tickets, requiring structural transformation of the exported data.
- 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:
- Scoping (2–4 hours): Inventory objects, estimate volumes from dashboard, identify custom properties, count bot dialog complexity
- API setup (1–2 hours): Generate token, verify access, test endpoints, confirm plan supports API access
- Script development (1–3 days): Build extraction script with pagination, retry logic, 404 handling, attachment download, deduplication
- Extraction (15 min to 5 days): Depends on data volume and attachment count
- Validation (4–8 hours): Spot checks, count reconciliation, attachment verification, deleted-user audit
- 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.


