Freshservice to Gladly Migration: A Technical Guide
Technical guide to migrating from Freshservice to Gladly. Covers data model differences, API rate limits, entity mapping, import constraints, and what you cannot migrate.
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
What Is a Freshservice to Gladly Migration?
A Freshservice to Gladly migration extracts requesters, tickets, conversations (replies and notes), agents, groups, and knowledge base articles from Freshservice's ITSM model and loads them into Gladly as Customers, Conversation Items, Agents, Teams, Topics, and Answers.
This is not a standard helpdesk-to-helpdesk migration. It is a cross-category data model translation. Freshservice stores tickets — incidents, service requests, problems, and changes — linked to assets and a configuration database, all built around the ITIL framework. Gladly organizes work around people, where each customer has one persistent Conversation that runs for the life of the relationship, with every interaction across every channel landing on that single timeline.
The gap between these two systems is larger than a typical Zendesk-to-Gladly or Freshdesk-to-Gladly move. You are not just remapping ticket fields — you are discarding an entire ITSM layer that has no target in Gladly. Freshservice's ITSM capabilities (asset management, CMDB, change management, approval workflows) are purpose-built features with no Gladly equivalents. The migration scope is fundamentally a question of what customer-facing subset of your Freshservice data belongs in a CX platform — and that subset is almost always smaller than teams expect.
TL;DR — Freshservice to Gladly Migration
Migrating from Freshservice to Gladly is a cross-category migration — you are moving data from an ITIL-aligned IT service management (ITSM) platform to a person-centric, ticketless customer service platform. The data models share almost nothing. Freshservice stores tickets, assets, problems, changes, a CMDB, and a service catalog. Gladly stores Customers with lifelong Conversation Timelines, Conversation Items (individual interactions on the timeline), Topics, and Answers — no ticket numbers, no asset tracking. Most Freshservice ITSM entities (assets, problems, changes, releases, SLA policies, workflow automations) have no equivalent in Gladly and cannot be migrated. Gladly's documented historical import is text-only: it does not support attachments, images, recordings, metrics, or routing assignments, and imported data is not searchable or reportable — it is reference-only on the customer profile. Freshservice API rate limits range from 100 to 500 requests per minute depending on plan. Gladly's default rate limit is 10 API calls per second. Budget 2–4 weeks for a mid-size instance.
Targets Freshservice API v2 and Gladly REST API.
Before you commit: If your Freshservice instance contains a mix of internal IT tickets and external customer tickets, only the external customer-facing subset should move to Gladly. Internal ITSM data (incident management for employees, asset tracking, change requests) does not belong in Gladly and will create noise on agent timelines if imported.
Freshservice vs. Gladly: What Each Platform Actually Does
The structural difference between these two platforms determines what migration is possible. This comparison uses platform-specific terminology.
| Dimension | Freshservice | Gladly |
|---|---|---|
| Data model | Ticket-centric (each interaction = new Ticket ID) | Person-centric (all interactions = one lifelong timeline per customer) |
| Primary object | Ticket (Incident, Service Request, Problem, Change) | Customer profile with Conversation Timeline |
| Thread grouping | Per-ticket thread | Conversation (configurable time window, default 24 hours) |
| Agent routing | Routes to ticket queue | Routes to customer, not ticket |
| Channels | Email, portal, phone, chat | Email, voice, SMS, chat, social — all unified on one timeline |
| ITIL support | Full ITIL framework (incident, problem, change, release) | None |
| Asset management | Full CMDB | None |
| Automation | Workflow Automator, Supervisor, Dispatch'r, Observer | Rules engine |
| Knowledge base | Categories > Folders > Articles | Answers (channel-aware: email, messaging, public, internal variants) |
| Reporting | Analytics with SLA metrics, ticket volume, CSAT | Gladly Insight (conversation-level, not ticket-level) |
| API | REST API v2, Basic Auth | REST API, OAuth2 |
Gladly specifically does not have ticket numbers, ticket-level SLA timers, asset associations, approval workflows, or ITIL change management. These are not feature gaps — they are intentional design choices for a B2C customer service platform. Forcing ITSM data into Gladly does not recreate ITSM functionality; it creates cluttered timelines and orphaned data.
Data Model Gap: ITSM Tickets vs. Person-Centric Timelines
Freshservice: Ticket-Centric
Freshservice uses discrete objects for every issue. If Jane Doe emails support three times about three different issues, Freshservice creates three separate Ticket IDs. Each ticket has its own status, priority, SLA timer, and thread of replies and private notes. Requesters, agents, and groups relate to tickets as foreign-key associations.
Gladly: Person-Centric
Gladly has no concept of a "ticket number." When Jane Doe contacts support, Gladly routes the customer, not the ticket. All interactions — phone calls, SMS, emails, and chats — are appended to Jane Doe's single lifelong Conversation Timeline as Conversation Items. A Conversation in Gladly is a time-bounded grouping of Conversation Items (24-hour window by default, configurable per brand). A Conversation Item is a single discrete interaction: one email, one call, one chat message. The distinction between these two terms matters throughout the migration.
This means that three separate Freshservice tickets from the same requester must all be folded into a single Gladly Customer profile, with each ticket becoming one or more Conversation Items on that customer's timeline.
Entity Mapping
| Freshservice Entity | Gladly Equivalent | Migration Path |
|---|---|---|
| Ticket (Incident/Service Request) | Conversation Items on Customer Timeline | Map each ticket → Conversation Items under the requester's Customer profile |
| Requester | Customer | Map 1:1 by email address |
| Agent | Agent | Create or map manually |
| Group | Team / Inbox | Manual setup in Gladly |
| Conversation reply (public) | Conversation Item | Flatten into timeline items |
| Internal note | Conversation Item (agent-visible only) | Import decision required — see Step 4 |
| Custom Fields | Custom Attributes | Map selectively; Gladly supports fewer field types |
| Knowledge Base Article | Answer | Recreate in channel-aware format; one article often becomes multiple Answer variants |
| Tags | Topics | Map selectively — intent tags only |
| Asset | ❌ No equivalent | Not migratable — archive separately |
| Problem | ❌ No equivalent | Not migratable — export to data warehouse |
| Change | ❌ No equivalent | Not migratable — export to data warehouse |
| Release | ❌ No equivalent | Not migratable |
| Service Catalog | ❌ No equivalent | Redesign as Answers or Sidekick flows |
| CMDB / Configuration Items | ❌ No equivalent | Not migratable |
| SLA Policies | ❌ No equivalent | Rebuild as Gladly Rules from scratch |
| Workflow Automator Rules | ❌ No equivalent | Rebuild as Gladly Rules from scratch |
| Approval Workflows | ❌ No equivalent | Not migratable |
| Custom Dashboards / Analytics | ❌ No equivalent | Rebuild in Gladly Insight |
What Cannot Be Migrated
These Freshservice features have no target in Gladly:
- Assets and CMDB — Gladly has no asset management. Archive this data separately (S3, data warehouse) or retain Freshservice access for IT teams.
- Problems, Changes, and Releases — ITIL constructs with no Gladly equivalent. Export to Snowflake, Redshift, or BigQuery for historical access.
- Service Catalog — Gladly has no service request workflow. Redesign relevant items as Gladly Answers, self-service content, or Sidekick (Gladly's AI agent) flows.
- SLA Policies — Freshservice SLA timers operate at the ticket level with escalation chains. Gladly's SLA targets operate differently at the conversation level. Do not attempt to transfer these — rebuild from scratch as Gladly Rules.
- Workflow Automator, Supervisor, Dispatch'r, and Observer rules — Freshservice's event- and time-based automations do not have a structural equivalent in Gladly's Rules engine. Redefine automation logic from first principles.
- Approval Workflows — Freshservice's multi-level approval chains have no Gladly equivalent.
- Attachments, images, and recordings in Historical Import — Gladly's documented historical import does not support images, recordings, attachments, metrics, or routing/conversation assignments. (help.gladly.com)
- Custom Dashboards and Analytics — Freshservice Analytics reports cannot be exported to Gladly. Recreate reporting views in Gladly Insight. Note that Gladly Insight reports at the conversation level, not the ticket level — your historical Freshservice metrics (MTTR, ticket volume by category, SLA compliance) will not have direct equivalents.
Timeline Scale: When Does the Person-Centric Model Break Down?
A Freshservice requester who submitted 200 tickets over 5 years will have all 200 tickets — potentially thousands of individual Conversation Items — loaded onto a single Gladly timeline. This is the structural risk of migrating to a person-centric model from a ticket-centric one.
At scale, this creates practical usability problems:
- Agents scrolling through hundreds of historical items to find recent context
- Timeline loading time increasing with item density
- Legitimate current interactions visually buried beneath years of imported history
Mitigations:
- Import only the last 12–24 months of ticket history per customer, not full history. Older data can be archived with a reference link in the customer's Custom Attributes.
- Use Gladly's Lookup API to surface order/account/subscription context in real time rather than loading it as static timeline items.
- Mark all imported items with a consistent prefix (e.g.,
[Historical - Freshservice]) so agents can visually distinguish imported reference data from live interactions. - Gladly does not publish a documented per-timeline item limit, but you should test with your highest-volume customers in a staging environment before committing to a full import.
Extraction: Getting Data Out of Freshservice
Freshservice API v2 Basics
The Freshservice API is RESTful, uses Basic Auth with API keys, enforces minute-level rate limits that vary by pricing plan, and paginates with page and per_page query parameters (max 100 per page). (api.freshservice.com)
The extraction endpoints you will use:
GET /api/v2/tickets?per_page=100&page={n} # List tickets
GET /api/v2/tickets/{id} # Single ticket detail
GET /api/v2/tickets/{id}/conversations # Replies and notes
GET /api/v2/requesters?per_page=100&page={n} # List requesters
GET /api/v2/agents?per_page=100&page={n} # List agents
GET /api/v2/groups?per_page=100&page={n} # List groups
GET /api/v2/solutions/categories # Knowledge base
GET /api/v2/ticket_fields # Custom field definitions
Freshservice also provides a Data Export feature (Admin > Account > Data Export) that produces CSV files for tickets. This export covers ticket-level fields but does not include conversation threads or internal notes. It can supplement extraction for large ticket volumes by reducing the number of list API calls needed, but you still require the Conversations API for full thread data.
Rate Limits by Plan
Rate limits are account-wide, regardless of the number of agents or IP addresses making calls:
- Starter: 100 requests/minute
- Growth: 200 requests/minute
- Pro: 400 requests/minute
- Enterprise: 500 requests/minute
Add-on packs can increase the limit: Pack 1 raises it to 1,000 req/min, Pack 2 to 2,000 req/min.
The List All Tickets endpoint has its own sub-limits, ranging from 40 to 140 requests per minute depending on plan. Invalid requests count against the limit, and embedded resources (include= parameters) consume extra API credits.
Extraction Traps
Deep pagination breaks. Freshservice enforces pagination depth limits on list endpoints. For any dataset beyond a few thousand tickets, standard page-based pagination will eventually fail or return empty results. The fix: use the updated_since filter to paginate chronologically through time windows instead of pages.
GET /api/v2/tickets?updated_since=2023-01-01T00:00:00Z&per_page=100&page=1Capture the updated_at timestamp of the last record in each batch and use it as the updated_since value for the next request. This approach also handles delta extraction for cutover without re-running the full pull.
include=conversations is a trap. The include=conversations parameter on ticket list endpoints returns only up to 10 conversations per ticket (sorted by created_at ascending) and counts as 2 API calls per request. For full ticket history, you must call the conversations endpoint for each ticket individually.
Standard exports miss conversations. Freshservice's Data Export feature includes ticket-level data only, not conversations or internal notes. You need the Conversations API for those.
Archived tickets require extra handling. Tickets older than approximately one year may be archived (accounts must have 500,000+ total tickets to be eligible for archival). Archived tickets can be accessed individually by ticket ID but will not appear in standard list responses. You cannot enumerate archived tickets via the list endpoint — you need ticket IDs from a prior export or Data Export CSV to fetch them individually.
Attachment URLs expire. Freshservice stores attachments in AWS S3 and provides temporary, expiring URLs in API responses. These URLs typically expire within 24–48 hours. Your extraction script must download attachments immediately upon extraction, not log the URL for later retrieval.
Multi-workspace gotcha. If you do not pass workspace_id, Freshservice returns only the primary workspace. Passing workspace_id=0 gives cross-workspace results but only global fields. Be deliberate about which workspaces you extract.
Practical extraction throughput by plan, assuming 1 API call per conversation fetch and average 8 conversations per ticket:
- Starter (100 req/min): ~12 tickets/minute with conversation fetch → 20,000 tickets takes ~28 hours
- Growth (200 req/min): ~22 tickets/minute → 20,000 tickets takes ~15 hours
- Pro (400 req/min): ~44 tickets/minute → 20,000 tickets takes ~8 hours
- Enterprise (500 req/min): ~55 tickets/minute → 20,000 tickets takes ~6 hours
These estimates assume single-threaded extraction, no embedded resources, and average conversation count. Parallelizing across date-range partitions can reduce wall-clock time but does not change throughput against the account-wide rate limit.
Loading Data into Gladly
Import Paths
Gladly offers two paths for historical data:
-
Gladly Professional Services import — Gladly can import historical conversations from several popular platforms via structured CSV. Freshservice is not listed as a natively supported source as of the time of writing, so you will need to export data into a Gladly-compatible CSV format. Gladly Professional Services recommends batches of 500K rows, loaded approximately 2 weeks before launch, with a final delta load approximately 2 days after launch. If this import is not defined in your Statement of Work, contact your implementation team for a quote. (help.gladly.com)
-
Gladly REST API (Create Timeline Item) — This API adds items to the timeline for a customer identified by email or phone. If the customer does not exist, a new profile is created. Items created this way are not considered part of a conversation and are non-routable and non-searchable aside from the email address or phone number specified. (developer.gladly.com)
Either way, historical Freshservice data in Gladly is agent context, not operational data. Agents can view it on the customer timeline, but it does not appear in Gladly Insight reporting, cannot be routed, and is not searchable beyond the customer identifier. Set this expectation with your team before the migration begins.
Gladly API Rate Limits
The default is 10 API calls per second. Organizations that exceed this will receive 429 responses. At 10 req/sec, you can create up to 600 timeline items per minute. You need backoff logic that reads the Retry-After response header on 429 responses.
Gladly externalCustomerId and Duplicate Handling
Gladly uses email address as the primary deduplication key for Customer profiles. When you POST a timeline item with a customer email that already exists in Gladly, the item is appended to the existing customer's timeline. A new profile is created only if no matching email is found.
The externalCustomerId field allows you to assign a stable external identifier to a Gladly Customer profile — in this migration, use the Freshservice requester ID (e.g., fs_123456789). This creates a deterministic link that prevents duplicate customer creation during delta syncs.
Important collision behavior: If you attempt to create a Customer with an externalCustomerId that already exists on a different profile, the API returns a conflict error. This can occur if the same requester was extracted twice with different email addresses (common with alias emails or shared inboxes) and loaded as separate Gladly profiles before the deduplication pass. Resolve requester duplicates in your transform step, before loading.
Gladly Import Field Constraints
These limits apply to the historical import CSV format:
body: capped at 25,000 characterstitle: capped at 100 charactersactivityType: must be one ofEMAIL,ISSUE,SMS, orSURVEY- Phone numbers: must be in E.164 format
- Email required: imports without a valid email address are rejected
- Large imports: Gladly recommends batches of 500K rows, loaded ~2 weeks before launch, with a final delta 2 days after launch
- Some profile fields are first-import-only and cannot be updated through subsequent imports
Gladly also supports bulk CSV import for Topics, Answers, and Users. Rules and Inboxes require manual configuration through the Gladly admin UI — there is no bulk import path for those objects.
Step-by-Step Migration Process
Step 1: Audit and Scope Your Freshservice Instance
Before writing any code:
- How many tickets are in scope? Exclude internal IT tickets, spam, and test data. Count only external customer-facing tickets.
- How many unique requesters have valid external email addresses?
- What is your distribution of conversation depth? Average conversations per ticket determines extraction time more than ticket count.
- Which custom fields are actively used by agents and need to carry over?
- Do you need to migrate knowledge base articles?
- What is your Freshservice plan? This determines extraction throughput.
- How many workspaces are in play? Each workspace requires separate extraction.
- What is the oldest ticket date you need to migrate? Older data may be archived and require different handling.
Step 2: Set Up the Gladly Environment
- Provision a Gladly sandbox or staging environment.
- Create Teams (mapped from Freshservice Groups).
- Create Inboxes for each support channel.
- Define Topics (mapped from Freshservice tags or categories — keep the hierarchy shallow, 2–3 levels maximum).
- Set up Custom Attributes for any custom fields you need to preserve.
- Create agent accounts via IdP/SSO or CSV bulk upload. Agents must be provisioned in Gladly before the data migration — do not attempt to create agent credentials via the REST API.
- Disable all Gladly Rules before beginning any import. Active Rules may trigger assignment logic, notifications, or SLA timers on historical data loaded via the API.
Step 3: Extract Data from Freshservice
Build an extraction pipeline that:
- Pulls all requesters via
/api/v2/requesters— collectid,email,name,phone. - Uses Data Export CSV (if available) for an initial ticket list, then supplements with the API for conversations.
- Pulls tickets using
updated_sincepagination to handle large volumes and enable delta re-runs. Partition by 30-day windows for datasets over 10,000 tickets. - For each ticket, fetches full conversations via
/api/v2/tickets/{id}/conversations(do not rely oninclude=conversations— it caps at 10 replies). - Stores everything in an intermediate staging database (SQLite for small migrations, PostgreSQL for large ones) rather than flat JSON files — this allows restarts without re-extracting.
- Downloads all attachments immediately upon extraction to local storage or S3, before URLs expire.
- Implements rate-limit handling with exponential backoff using the
Retry-Afterheader.
import requests
import time
from datetime import datetime, timedelta
FRESHSERVICE_DOMAIN = "yourcompany.freshservice.com"
API_KEY = "your_api_key"
def get_tickets_since(updated_since: str, page: int = 1) -> dict:
"""
Fetch tickets updated after `updated_since` (ISO 8601 string).
Uses time-window pagination to avoid deep page limits.
"""
url = (
f"https://{FRESHSERVICE_DOMAIN}/api/v2/tickets"
f"?updated_since={updated_since}&per_page=100&page={page}"
)
response = requests.get(url, auth=(API_KEY, "X"))
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
print(f"Rate limited. Sleeping {retry_after}s.")
time.sleep(retry_after)
return get_tickets_since(updated_since, page)
response.raise_for_status()
return response.json()
def extract_all_tickets(start_date: str) -> list:
"""
Paginate through all tickets updated since start_date.
Advances the window using the last ticket's updated_at timestamp.
"""
all_tickets = []
current_since = start_date
while True:
page = 1
window_tickets = []
while True:
data = get_tickets_since(current_since, page)
tickets = data.get("tickets", [])
if not tickets:
break
window_tickets.extend(tickets)
page += 1
if not window_tickets:
break
all_tickets.extend(window_tickets)
# Advance window to last ticket's updated_at timestamp
last_updated = window_tickets[-1]["updated_at"]
current_since = last_updated
# If last batch was less than 100, no more pages in this window
if len(window_tickets) < 100:
break
return all_tickets
def get_conversations(ticket_id: int) -> list:
"""Fetch all conversation threads for a single ticket."""
url = f"https://{FRESHSERVICE_DOMAIN}/api/v2/tickets/{ticket_id}/conversations"
response = requests.get(url, auth=(API_KEY, "X"))
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
time.sleep(retry_after)
return get_conversations(ticket_id)
response.raise_for_status()
return response.json().get("conversations", [])Step 4: Transform Data to Gladly Format
For each Freshservice ticket:
-
Identify the customer by requester email. Freshservice requesters without a valid email will be rejected by Gladly — decide whether to enrich those records before migration or accept data loss.
-
Build Conversation Items from the ticket description (opening message) and each reply/note in the thread. Each public reply and each internal note becomes a separate Conversation Item.
-
Preserve chronological order —
occurredAttimestamps determine timeline ordering. Out-of-order timestamps produce a confusing agent experience. -
Preserve the Freshservice Ticket ID. Write the original ticket number into a Custom Attribute or prepend it to the first Conversation Item body:
[Historical Import - Freshservice Ticket #INC-98765]. This is the only way agents can cross-reference the migrated history with the original Freshservice record. -
Map Freshservice
requester_id→ GladlyexternalCustomerIdusing a consistent format likefs_{requester_id}. This creates a deterministic link that prevents duplicate profile creation during delta syncs.Requester → Customer mapping example:
{ "name": "Jane Doe", "emails": ["jane.doe@example.com"], "externalCustomerId": "fs_123456789" } -
Map tags → Topics selectively. Only promote intent-like tags (e.g.,
billing,returns,account-access) to Gladly Topics. Operational tags (waiting-on-vendor,jira-linked,escalated-l2) belong in the body text or a custom attribute, not your Topic tree. -
Map statuses. Freshservice has Open, Pending, Resolved, and Closed. Gladly only has
OPENandCLOSED. Map Open/Pending →OPENand Resolved/Closed →CLOSED. -
Strip ITSM metadata that has no Gladly equivalent (priority, impact, urgency, SLA timer values, asset associations) — or flatten it into the first Conversation Item body for agent reference:
[Freshservice Ticket #INC-98765 | Priority: High | Category: Network | Resolved: 2024-03-15] -
Handle internal notes explicitly. Freshservice conversations include both public replies and private notes (
incomingflag distinguishes them). Gladly's historical import does not have a separate private note type — all Conversation Items are visible to agents. Decide upfront whether to import private notes or exclude them. If you import them, label them clearly in the body. -
Convert HTML to plain text. Freshservice ticket descriptions and replies are HTML. Gladly's historical import expects plain text or a specific format. Strip HTML tags using a library (Python's
html.parser,bleach, ormarkdownify). Rich formatting, inline images, and embedded tables will be lost or degraded — this is expected and not recoverable within Gladly's import constraints. -
Truncate to field limits. Trim
bodyto 25,000 characters andtitleto 100 characters. For long tickets, truncate and append[truncated — see Freshservice ticket #INC-98765 for full history].
Here is the shape of a Gladly-compatible CSV row:
customer_email,customer_name,title,body,activityType,occurredAt,sourceName
jane@example.com,Jane Doe,Ticket 10482 - Password reset,"[Freshservice #INC-10482 | Priority: High | Status: Resolved]
Original body goes here.",ISSUE,2026-07-14T13:22:11.000Z,FreshserviceStep 5: Load into Gladly
Using the Gladly REST API or Professional Services bulk import:
- Create or match Customers — Use email as the unique identifier. If the customer already exists in Gladly, the API merges the timeline item onto the existing profile. If not, a new profile is created.
- Verify
externalCustomerIdbefore each load batch — if a collision is detected (same external ID on a different profile), resolve it before proceeding or you will receive a conflict error that halts the batch. - Insert Conversation Items in chronological order per customer.
- Validate — Spot-check 50–100 customer profiles, weighted toward your highest-volume customers. Verify data integrity, correct ordering, completeness, and that long ticket threads (10+ replies) came through fully without truncation.
- Confirm Rules are disabled during the load. Re-enable them after the import is complete and validated.
Step 6: Rebuild Configurations
No API can migrate business logic. Manually recreate:
- Rules — replacing Freshservice Workflow Automator, Supervisor rules, Dispatch'r, Observer, and SLA policies. Map each Freshservice automation to its Gladly Rules equivalent, or redesign for Gladly's routing model.
- Answers — replacing Freshservice knowledge base articles. Freshservice structures knowledge in Categories > Folders > Articles. Gladly Answers are channel-aware content objects with separate email, messaging, public, and internal variants. One Freshservice article often needs to be split into several Gladly Answer variants because messaging Answers do not support custom HTML or vanity links. Gladly supports bulk Answer import by CSV.
- People Match settings — configure how Gladly identifies returning customers across channels.
- Routing rules and Inbox assignments — configure channel routing, business hours, and escalation paths.
- Sidekick (Gladly AI) configuration, if applicable — define which Answers Sidekick can surface autonomously.
- CSAT survey integration — reconnect or reconfigure your CSAT tooling.
Step 7: Cutover
- Freeze ticket creation in Freshservice (or set to read-only) at the agreed cutover timestamp.
- Run a delta extraction for any tickets created or updated since your last full extraction, using
updated_since={cutover_timestamp}. - Load the delta into Gladly.
- Switch DNS, email forwarding, and live channel routing to Gladly.
- Monitor for 24–48 hours. Keep Freshservice accessible in read-only mode for at least 90 days — because imported Gladly history is reference data, not a replacement for historical Freshservice analytics or archived ITSM records. Your IT team still needs Freshservice for asset and change history.
Edge Cases and Failure Modes
Requester Deduplication
Freshservice requesters may have multiple records for the same person (different email addresses, duplicate entries from portal and email submission). Gladly deduplicates by email and phone. Run a deduplication pass on your extracted requester data before loading — resolve alias emails and shared inboxes during the transform step, or you will create orphaned profiles in Gladly. Common sources of duplicates: requesters who submitted tickets via the portal with one email and via email with a different address, and shared team inboxes that Freshservice logged as individual requesters.
Tickets Without Email Addresses
Freshservice allows tickets from requesters identified only by name or phone number. Gladly imports require a valid email address — rows without one are rejected. You must either enrich the requester record with an email before migration or accept data loss on those tickets. For phone-only requesters, you can attempt import using E.164 phone number as the identifier via the REST API, but the Professional Services CSV import requires email.
Attachment Archival Strategy
Gladly's historical import is text-only. For significant attachment data (screenshots, logs, documents), archive attachments externally — an S3 bucket or shared drive. Include a reference URL in the migrated Conversation Item body so agents can access the original file. Use the link.url and link.title fields in Gladly's CSV import schema for these archive pointers.
Attachment URL expiry is a real operational risk. Freshservice's S3 URLs expire within 24–48 hours of the API response. Your extraction script must download and store attachment binaries immediately. Any extraction script that logs URLs for batch downloading later will fail.
Requester Without Email — Decision Tree
Does the Freshservice requester have a valid email?
├── YES → Include in migration
└── NO
├── Does the requester have a phone number in E.164 format?
│ ├── YES → Load via REST API using phone as identifier (not via CSV bulk import)
│ └── NO → Exclude from migration; log ticket IDs for manual review
└── Can you enrich the record with an email from an external CRM or data source?
├── YES → Enrich and include
└── NO → Exclude and archive
Automation Triggers During Import
If loading data via the Gladly REST API with Rules enabled, newly created timeline items may trigger assignment rules, notifications, or SLA timers on historical data — generating spurious agent notifications and incorrect SLA measurements. Disable all Rules before import; re-enable after validation.
Post-Migration Webhooks and Event System
Gladly supports webhooks for conversation events (conversation created, item added, conversation closed). After cutover, verify that your webhook subscriptions are configured for the live Gladly environment, not the sandbox. If you were sending Freshservice events to a data warehouse or CRM, update those integrations to consume Gladly webhooks instead.
Live Context After Cutover
If agents need order, account, subscription, or loyalty context alongside migrated history, use Gladly's Lookup API rather than overstuffing profile custom attributes with static data. Gladly Lookup responses should return in under 5 seconds; the platform times out after 15 seconds. Loading real-time context via Lookup also avoids the problem of stale data in custom attributes.
Timeline and Effort Estimates
These estimates assume: single-threaded extraction, average of 8 conversations per ticket, average body size of 2KB per conversation, and Gladly Professional Services handling the bulk import. Parallelizing extraction across date-range partitions can reduce wall-clock extraction time but does not increase throughput against the account-wide rate limit.
| Instance Size | Ticket Count | Extraction Time (Pro Plan, 400 req/min) | Load Time | Total Migration Window |
|---|---|---|---|---|
| Small | < 5,000 | 2–4 hours | 1–2 hours | 1 week (including config rebuild) |
| Medium | 5,000–50,000 | 8–36 hours | 4–12 hours | 2–3 weeks |
| Large | 50,000–200,000 | 3–7 days | 1–3 days | 3–4 weeks |
| Enterprise | 200,000+ | 1–2 weeks | 3–5 days | 4–6 weeks |
Configuration rebuild (Rules, Answers, Inboxes, routing) is often the longest phase for complex Freshservice instances — budget 1–2 weeks separately from data migration, regardless of ticket volume.
DIY vs. Managed Migration
DIY makes sense when:
- You have fewer than 5,000 tickets to migrate
- Your Freshservice instance uses mostly default fields and one workspace
- You have engineering resources available for 1–2 weeks
- You are comfortable with data loss on attachments and non-text content
- Requesters have clean, unique email addresses with no deduplication issues
- Your Freshservice plan is Growth or above (100 req/min on Starter makes DIY extraction painful)
A managed migration makes sense when:
- You have more than 5,000 tickets or complex custom field schemas
- You need zero-downtime cutover with delta sync
- You have multi-workspace extraction complexity
- You need attachment archival and reference linking
- You need to coordinate the load timing with Gladly Professional Services
- You cannot afford a failed migration attempt that consumes your cutover window
For related migration planning, see our guides on Zendesk to Gladly migration and Freshdesk to Gladly migration. If you are evaluating adjacent Freshservice destinations, see our Freshservice to LiveChat migration guide.
What a Realistic Migration Looks Like
A Freshservice to Gladly migration is not a weekend project. The data model gap between an ITSM platform and a person-centric CX platform means you are discarding more data than you are keeping — assets, CMDB, changes, problems, releases, SLA history, approval workflows, and all automation logic. That is by design. Gladly is not meant to replace Freshservice's ITSM capabilities.
The honest sequence: audit your Freshservice data and isolate the customer-facing subset, extract within API rate limits using time-window pagination, transform into Gladly's timeline model with explicit handling for internal notes and email-less requesters, load as reference-only historical context with Rules disabled, rebuild all automation and routing logic from scratch in Gladly, and keep Freshservice in read-only mode for at least 90 days post-cutover for IT team reference.
The most common failure modes are: importing too much history (making timelines unusable for high-volume customers), attempting to migrate ITSM concepts that have no Gladly equivalent, and underestimating the configuration rebuild effort for Rules and Inboxes.
Frequently Asked Questions
- Can I migrate Freshservice assets and CMDB data to Gladly?
- No. Gladly has no asset management, CMDB, or configuration item tracking. These entities must be archived separately (e.g., a data warehouse like Snowflake or Redshift) or kept in Freshservice. Only customer-facing ticket data — requesters, conversations, tags — can be migrated to Gladly.
- Does Gladly support importing attachments from Freshservice?
- No. Gladly's historical import is text-only and does not support attachments, images, recordings, or metrics. Archive attachments externally (e.g., S3 bucket) and include reference links in the migrated conversation items using Gladly's link.url and link.title fields.
- How long does a Freshservice to Gladly migration take?
- A small instance (under 5,000 tickets) takes about 1 week including configuration. A mid-size instance (5,000–50,000 tickets) takes 2–3 weeks. Large instances (50,000+) can take 4–6 weeks. Extraction speed depends on your Freshservice plan's API rate limit.
- Is migrated Freshservice data searchable in Gladly?
- No. Historical imports into Gladly are reference-only on the customer profile. They are not searchable, not reportable, and cannot be routed. Agents can view the data on the customer timeline for context, but it does not appear in Gladly analytics or reporting.
- How do I handle multi-workspace Freshservice extraction?
- Pass workspace_id deliberately in your API calls. If you omit it, Freshservice returns only the primary workspace. Setting workspace_id=0 gives cross-workspace results but only with global fields. Plan your extraction per workspace to get complete custom field data.
