---
title: "How to Migrate from Gladly to Intercom: The Complete Technical Guide"
slug: how-to-migrate-from-gladly-to-intercom-the-complete-technical-guide
date: 2026-07-14
author: Nachi
categories: [Migration Guide, Gladly, Intercom]
excerpt: "How to migrate from Gladly to Intercom — object mapping, API limits, timeline-to-conversation splitting, and step-by-step architecture from migration engineers."
tldr: Gladly to Intercom migration requires splitting continuous customer timelines into discrete conversations under Intercom's 500-part limit. Expect 2–4 weeks for 50K–150K items.
canonical: https://clonepartner.com/blog/how-to-migrate-from-gladly-to-intercom-the-complete-technical-guide/
---

# How to Migrate from Gladly to Intercom: The Complete Technical Guide


# How to Migrate from Gladly to Intercom: The Complete Technical Guide

> [!NOTE]
> **TL;DR — Gladly to Intercom Migration**
>
> Migrating from Gladly to Intercom is a **high-complexity** data-model translation project. Gladly stores all customer interactions in a single, lifelong Conversation Timeline with no ticket numbers. Intercom stores interactions as discrete Conversations, each hard-limited to 500 parts ([Intercom API Reference: Conversations](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Conversations/)). A typical migration takes **2–4 weeks** for 50,000–150,000 conversation items. The single biggest risk is **silent data truncation** — Gladly's API returns at most 100 conversations per customer and caps timeline items at 1,000 per conversation, flagged only by the `Gladly-Limited-Data` response header ([Gladly API Docs: Rate Limits](https://developer.gladly.com/rest/#section/Rate-Limits)). If your extraction script ignores that header, you lose history with no error message. Gladly automations, routing rules, SLA configurations, and People Match rules cannot be migrated and must be rebuilt manually in Intercom. Teams with fewer than 5,000 conversation items and simple schemas can attempt a scripted DIY migration (100–160 engineer-hours). For anything larger — especially with voice history, GDPR data-residency requirements, or zero-downtime needs — a managed migration service is the safer path.
>
> *Written July 2025. Targets Gladly REST API and Intercom API v2.11.*

## What Is a Gladly to Intercom Migration?

A Gladly to Intercom migration is the process of extracting Customers, Conversations, Conversation Items, Agents, Teams, Topics, Tasks, and Answers from Gladly's person-centric data model and loading them into Intercom as Contacts, Companies, Conversations, Conversation Parts, Teammates, Tags, Tickets, and Articles. The goal is to preserve full customer interaction history so Intercom agents can see previous exchanges without gaps.

Teams typically migrate from Gladly to Intercom for three reasons:

1. **AI-first support architecture.** [Intercom's Fin AI agent](https://clonepartner.com/blog/blog/ultimate-guide-Intercom-2026/) resolves conversations autonomously using your knowledge base, custom actions, and workflows. For teams handling 10,000+ conversations per month, this reduces agent handle time measurably — a capability Gladly's AI (Sidekick) is still developing.
2. **Product-led growth integration.** Intercom's CDP model (custom events, company associations, user segments, product tours) connects support data directly to product analytics and lifecycle campaigns. [Gladly](https://clonepartner.com/blog/blog/ultimate-guide-gladly-2026/) is optimized for high-touch, agent-driven support but lacks native product event tracking.
3. **Tickets as a structured back-office layer.** Intercom's Tickets product gives teams defined states, custom attributes, and SLA tracking for trackable requests (bug reports, feature requests) separate from live conversations. Gladly uses Tasks for internal follow-up, but these lack the structured lifecycle of Intercom Tickets.

The non-trivial part is not extracting data — it is deciding what becomes an Intercom conversation, what becomes a ticket, and what must be preserved as context only.

## The Core Challenge: Continuous Timelines vs. Discrete Conversations

The architectural mismatch between Gladly and Intercom is the hardest part of this migration.

**Gladly's model is person-centric.** Every customer has a single, lifelong Conversation Timeline that spans every channel — voice, email, chat, SMS, WhatsApp, Facebook Messenger, and Instagram. There are no ticket numbers. A customer who contacts support six times over two years has all six interactions in one continuous stream. Gladly's own documentation describes this as putting "Customers — not tickets — at the center" ([Gladly: Customer Service Philosophy](https://www.gladly.com/customer-service-philosophy/)).

**Intercom's model is conversation-centric.** Each support interaction is a discrete Conversation object with a defined lifecycle: created → open → snoozed → closed. A customer who contacts support six times has six separate Conversations, each with its own ID, tags, assignee, and conversation parts ([Intercom API Reference: Conversation Model](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Conversations/conversation/)).

This mismatch creates three practical problems:

1. **Long timelines must be split.** A single Gladly Customer Timeline must be divided into multiple Intercom Conversations. Gladly does have Conversation objects within the unified timeline, and each maps to one Intercom Conversation. But if a single Gladly Conversation exceeds 500 items, it must be split further into linked Intercom Conversations.
2. **Unsupported channel types need normalization.** Gladly treats voice calls, SMS, and Instagram Direct as equal nodes on a timeline. Intercom's conversation creation API only supports `inapp`, `email`, `sms`, `whatsapp`, and `facebook` as message types ([Intercom API: Create Conversation](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Conversations/createConversation/)). Voice calls, voicemails, and Instagram Direct have no native equivalent and must be stored as internal notes.
3. **Topic hierarchies flatten.** Gladly topics can be nested. Intercom tags are flat. You must decide whether to flatten hierarchies or encode path strings (e.g., `Billing > Refunds > Partial`).

## How Do Gladly Objects Map to Intercom?

Start from customer profiles, conversations, messages, topics, tasks, and answers. Only map into Intercom companies or tickets when the source data actually carries those semantics. Refer to our [help desk data migration playbook](https://clonepartner.com/blog/blog/help-desk-data-migration-playbook/) for a broader mapping strategy.

### Object Mapping Table

| Gladly Object | Intercom Object | Notes / Caveats |
|---|---|---|
| Customer | Contact (User or Lead) | Gladly merges profiles automatically. Intercom deduplicates on `external_id` or `email` ([Intercom: Contacts](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Contacts/)). Role (`user` vs `lead`) must be assigned during import. Gladly allows multiple emails/phones per customer. |
| Conversation | Conversation | Gladly Conversations exist within a customer timeline. Each maps to a discrete Intercom Conversation. |
| Conversation Item (Email) | Conversation Part (`comment`) | Each email becomes a conversation part. HTML is **not** supported in the initial conversation body — only in reply parts (verified against Intercom API v2.11; check the [Create Conversation endpoint docs](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Conversations/createConversation/) for current behavior). |
| Conversation Item (Chat) | Conversation Part (`comment`) | Direct mapping. |
| Conversation Item (SMS) | Conversation Part (`comment`) | SMS content migrates as text. Channel metadata (carrier, delivery status) is lost. |
| Conversation Item (Phone Call) | Conversation Part (`note`) | No native equivalent. Migrate as internal notes with call metadata (duration, recording URL). |
| Conversation Item (Voicemail) | Conversation Part (`note`) | Same as phone calls — recording URLs preserved as attachment links in S3/GCS. |
| Conversation Item (Instagram Direct) | Conversation Part (`note`) | Intercom does not support Instagram Direct as a create-conversation message type. Store as notes. |
| Conversation Item (Note) | Conversation Part (`note`) | Direct mapping for internal notes. |
| Topic | Tag | Gladly Topics map to Intercom Tags. Create tags before importing conversations. Flatten nested hierarchies. |
| Task | Ticket | Gladly Tasks (due date, assignee, description) map best to Intercom Tickets with custom ticket types. |
| Answer (Public) | Article | Gladly Answers map to Intercom Articles. Sections map to Collections. Audiences map to Help Center audiences. |
| Agent | Teammate / Admin | Agent profiles must exist in Intercom before conversation import for proper attribution. Map by email address. |
| Team | Team | Direct mapping. Create teams in Intercom before import. |
| Inbox | Team Inbox | Map Gladly Inboxes to Intercom team inboxes or views. |
| Custom Attributes | Custom Data Attributes | Create CDAs via the [Data Attributes API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Data-Attributes/) before importing records. |

### What Has No Clean Equivalent in Intercom

- **People Match rules.** Gladly's identity resolution logic (matching customers across channels by email, phone, social) has no API-portable equivalent. Intercom identifies contacts by `external_id`, `email`, or Intercom ID.
- **Routing rules and SLA policies.** Must be rebuilt as Intercom Workflows and SLA rules manually. Budget 1–2 days depending on rule complexity.
- **Voice/SMS channel metadata.** Intercom has no native voice channel. Call recordings, durations, and IVR paths are preserved only as note text or attachment URLs.
- **Sidekick (AI) configuration.** Guides, Journeys, and AI training data cannot be exported or transferred.
- **Conversation status granularity.** Gladly statuses (`OPEN`, `CLOSED`, `WAITING`) must be mapped to Intercom's three states: `open`, `closed`, or `snoozed`. Map `WAITING` to `snoozed` with a calculated timestamp.
- **Webhooks.** Gladly webhooks (conversation events, customer events) that feed downstream systems (CRMs, analytics pipelines, Slack alerts) need to be re-pointed to [Intercom's webhook infrastructure](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Data-Export/) or rebuilt as Intercom Workflow triggers.

### Field-Level Transformations

- **Timestamps:** Gladly exports ISO 8601. Intercom's API expects Unix timestamps (seconds since epoch) for historical imports. Convert during the transform phase: `int(datetime.fromisoformat(gladly_ts).timestamp())`.
- **Custom Attributes:** Pre-create Intercom CDAs with the correct type — `string`, `integer`, `float`, `boolean`, `date`, or `options` — before loading contact data.
- **Identity Strategy:** Intercom's CSV imports match contacts in this order: Intercom ID → `user_id` → email. If you mix email and `user_id` inconsistently, you will create duplicates. Intercom also supports [CSV bulk imports](https://www.intercom.com/help/en/articles/15-import-users-from-a-csv-file) for contacts as an alternative to API-only loading — useful for the initial contact seed if you have clean, deduplicated customer data.

## API Rate Limits and Export Constraints

Rate limits are the primary throughput constraint. Gladly is the bottleneck.

### Gladly Extraction Limits

| Endpoint Type | Rate Limit | Notes | Source |
|---|---|---|---|
| Standard REST API | 10 requests/second | Rolling window | [Gladly API: Rate Limits](https://developer.gladly.com/rest/#section/Rate-Limits) |
| Reporting API | 10 requests/minute | 2 concurrent requests max across the organization | [Gladly API: Reporting](https://developer.gladly.com/rest/#tag/Reports) |
| List Customer Profiles | Max 50 per response | Paginated | [Gladly API: Customers](https://developer.gladly.com/rest/#tag/Customers) |
| List Customer Conversations | Max 100 per response | **Not paginated** — truncated silently | [Gladly API: Conversations](https://developer.gladly.com/rest/#tag/Conversations) |
| Conversation Timeline Items | Max 1,000 per conversation | Truncated silently | [Gladly API: Conversation Items](https://developer.gladly.com/rest/#tag/Conversation-Items) |
| Customer Tasks | Max 2,000 per response | — | [Gladly API: Tasks](https://developer.gladly.com/rest/#tag/Tasks) |

Gladly's API has two data-truncation behaviors that cause **silent data loss** if unhandled:

1. **Conversation list cap.** `GET /api/v1/customers/{customerId}/conversations` returns at most 100 conversations per customer and is not paginated. If a customer has more than 100 conversations, the `Gladly-Limited-Data` response header is set to `true`. For high-volume customers (loyalty programs, VIP accounts), 100+ conversations are common.

2. **Timeline item cap.** The conversation timeline endpoint returns at most 1,000 items per conversation. If exceeded, the `Gladly-Limited-Data` header flags the truncation. For enterprise customers with multi-year histories, this is a real risk.

Your extraction script **must** check this header on every API response. Gladly's API uses Basic Auth with an API token — `Authorization: Basic base64(email:token)` on every request. There is no OAuth flow.

### Gladly Export API

For full-history migrations, Gladly's **Export API** is often safer than REST-based crawling. It outputs JSONL files — `agents.jsonl`, `customers.jsonl`, `topics.jsonl`, and `conversation_items.jsonl` — bypassing the per-request truncation limits of the REST endpoints.

The Export API has its own constraints:

- Default schedule is daily. Hourly or one-time schedules require a Gladly support change.
- Job metadata and files are retained for only **14 days**.
- One-time exports covering more than six months may incur a service fee from Gladly (confirm with your Gladly account manager — pricing is not published).
- Some records are excluded: undelivered email messages with invalid recipients and certain EMAIL/SMS auto-replies sent by rules.

**Practical recommendation:** Use the Export API for the bulk historical load. Use REST for targeted lookups, recent deltas, and the final sync during cutover.

### Intercom Load Constraints

| Constraint | Limit | Source |
|---|---|---|
| Private App API calls | 10,000 requests/minute per app | [Intercom API: Rate Limiting](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Rate-Limiting/) |
| Workspace total | 25,000 requests/minute | [Intercom API: Rate Limiting](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Rate-Limiting/) |
| Conversation parts | **500 parts maximum per conversation** | [Intercom API: Conversations](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Conversations/) |

Intercom's rate limits are applied in 10-second windows (~1,666 calls per window for private apps). Each Gladly Conversation Item requires at minimum one API call (create conversation or reply). A customer with 50 conversation items across 3 conversations requires approximately 53 API calls (3 create + 50 reply).

**Throughput math:** At 10,000 calls/minute with no errors, you can import roughly 10,000 conversation parts per minute. In practice, expect 60–70% of theoretical throughput due to retries, 429 responses, and variable latency — roughly **400,000 parts per hour**.

Intercom's Conversations API accepts a `created_at` timestamp field specifically for historical migration. The [documentation](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Conversations/createConversation/) states this field is "only recommended for migrating past conversations from another source into Intercom." **Important: this feature may be gated by Intercom plan level.** Test this in a sandbox workspace first and confirm with your Intercom account manager that your plan (Starter, Pro, or Premium) supports historical timestamp imports. Behavior has varied between plans historically.

> [!WARNING]
> **Hard limit: 500 parts per Intercom Conversation.** If a Gladly Conversation has more than 500 timeline items, you must split it into multiple Intercom Conversations and link them via tags or a shared custom attribute (e.g., `gladly_original_conversation_id`). Design your splitter to cap at **~450 parts** so the live team has room to continue the thread after cutover. The 450 figure is an implementation choice, not an Intercom requirement — but it avoids hitting the ceiling during the first post-migration week.

## Migration Approaches Compared

### Custom API Scripts (DIY)

**How it works:** Build Python or Node.js ETL scripts that extract from Gladly's REST or Export API and load into Intercom's REST API.

**When to use it:** Teams with fewer than 5,000 conversation items, simple schemas, and a dedicated engineer available for 100–160 hours.

**Estimated cost:** $0 in tooling, but 100–160 hours of senior backend engineering time. At a loaded cost of $100–$150/hour, that is $10,000–$24,000 in opportunity cost.

**Pros:** Full control over mapping logic, no vendor dependency, handles edge cases you define.

**Cons:** High engineering investment. You own all error handling, retries, and the `Gladly-Limited-Data` truncation detection. Easy to miss edge cases on the first pass.

### Third-Party Migration Tool

**How it works:** Wizard-based tool (e.g., Help Desk Migration) that connects to both platforms via API and maps standard objects automatically.

**When to use it:** Teams with standard schemas, no custom timeline-splitting requirements, and moderate volumes (10,000–100,000 records).

**Estimated cost:** Typically $1,000–$10,000 depending on record volume and add-ons (delta sync, custom field mapping). Verify current pricing directly with the vendor.

**Pros:** Lower engineering effort, pre-built mapping for common objects, test migration before full run.

**Cons:** Limited control over how Gladly's continuous timeline is split into Intercom conversations. May not handle voice/SMS items, `Gladly-Limited-Data` truncation, or custom field transformations. Verify Gladly is listed as a supported source before committing.

### Managed Migration Service

**How it works:** A dedicated engineering team handles extraction, transformation (including timeline splitting), loading, validation, and delta sync.

**When to use it:** Teams with 50,000+ conversation items, voice/SMS history, custom attributes, or zero-downtime requirements.

**Estimated cost:** $5,000–$30,000+ depending on data volume, complexity, and SLA requirements.

**Pros:** Timeline-to-conversation splitting handled programmatically, truncation detection built-in, delta sync during cutover, validation included.

**Cons:** Higher cost than DIY. Requires vendor coordination.

| Criteria | DIY Scripts | Third-Party Tool | Managed Service |
|---|---|---|---|
| Engineering hours | 100–160 | 20–40 | 0–10 |
| Estimated cost | $10K–$24K (opportunity) | $1K–$10K (licensing) | $5K–$30K+ (service) |
| Timeline splitting | Manual logic | Limited | Automated |
| Truncation handling | Manual | Unknown | Built-in |
| Voice/SMS migration | Manual | Likely unsupported | Supported |
| Delta sync | Manual | Paid add-on | Included |
| Best for | <5K items | 10K–100K standard | 50K+ or complex |

## Step-by-Step Migration Architecture

The correct order-of-operations prevents broken relationships. Skip a step or reorder and you create orphaned conversations or duplicate contacts.

### Step 1: Export Gladly History

For historical loads, use Gladly's Export API to pull `customers.jsonl`, `conversation_items.jsonl`, `topics.jsonl`, and `agents.jsonl`. This avoids REST truncation limits. Reserve REST for targeted lookups and the final delta sync during cutover.

If you use REST (for smaller datasets or deltas), check the `Gladly-Limited-Data` header on every response:

```python
import requests
import base64

GLADLY_DOMAIN = "yourorg.gladly.com"
auth = base64.b64encode(b"email@company.com:api-token").decode()

def get_customer_conversations(customer_id):
    resp = requests.get(
        f"https://{GLADLY_DOMAIN}/api/v1/customers/{customer_id}/conversations",
        headers={"Authorization": f"Basic {auth}"}
    )
    resp.raise_for_status()
    # CRITICAL: Check for truncation
    if resp.headers.get("Gladly-Limited-Data") == "true":
        log_warning(f"Customer {customer_id}: >100 conversations, data truncated")
        # Fallback: use Export API data for this customer
        return get_from_export_api(customer_id)
    return resp.json()
```

### Step 2: Create the Intercom Schema

Pre-create all structural elements in Intercom before loading data:

- **Custom Data Attributes** (via the [Data Attributes API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Data-Attributes/)) — with correct types
- **Ticket types and ticket attributes** — if migrating Gladly Tasks as Tickets
- **Tags** (from Gladly Topics) — via `POST /tags`
- **Article Collections and Sections** — for knowledge base migration (see Step 6)
- **Teams and Teammate accounts** — agents must exist for `admin_id` attribution

Do this before loading any conversations. If teammates do not exist when you POST admin-authored notes, attribution will fail.

### Step 3: Load Contacts

Push Gladly Customer records to Intercom using `POST /contacts`. Choose one consistent identity key — either `email` or a stable `external_id` — and do not change it mid-project.

For large contact sets (10,000+), consider using Intercom's [CSV import](https://www.intercom.com/help/en/articles/15-import-users-from-a-csv-file) as the initial seed, then supplement with API calls for custom attributes and edge cases.

```python
import time

def create_intercom_contact(customer):
    resp = requests.post(
        "https://api.intercom.io/contacts",
        headers={
            "Authorization": "Bearer <token>",
            "Content-Type": "application/json",
            "Intercom-Version": "2.11"
        },
        json={
            "role": "user",
            "external_id": customer["gladly_id"],
            "email": customer["emails"][0],
            "name": customer["name"],
            "custom_attributes": {
                "gladly_customer_id": customer["gladly_id"]
            }
        }
    )
    if resp.status_code == 409:
        # Duplicate contact — look up existing and update
        existing = lookup_contact_by_external_id(customer["gladly_id"])
        return existing["id"]
    if resp.status_code == 429:
        retry_after = int(resp.headers.get("Retry-After", 1))
        time.sleep(retry_after)
        return create_intercom_contact(customer)  # Retry
    resp.raise_for_status()
    return resp.json()["id"]  # Store for conversation linking
```

Store the returned Intercom `id` in a mapping table alongside the Gladly `customerId`. You need this to associate conversations correctly.

### Step 4: Transform and Split Conversations

This is the hardest step. For each Gladly Customer:

1. **Group items by Gladly Conversation ID.** Each Gladly Conversation maps to one Intercom Conversation.
2. **Sort items ascending by timestamp** within each conversation.
3. **Check for truncation.** If `Gladly-Limited-Data` was flagged during extraction, verify you have the complete dataset from the Export API.
4. **Split any conversation with >450 items** into multiple Intercom Conversations. Tag overflow conversations with a shared `gladly_original_conversation_id` custom attribute and a `gladly_continuation: true` flag.
5. **Normalize unsupported channels.** Map voice calls, voicemails, and Instagram Direct items to internal notes with explicit channel markers.

```python
def split_conversation(items, max_parts=450):
    """Leave buffer below Intercom's 500-part hard limit.
    For active/open conversations, use max_parts=400 to give agents more headroom."""
    chunks = []
    for i in range(0, len(items), max_parts):
        chunks.append(items[i:i + max_parts])
    return chunks
```

### Step 5: Load Conversations into Intercom

For each group of items:

1. **Create the conversation** with `POST /conversations`, setting `created_at` to the original Gladly timestamp (Unix seconds). The first item's content becomes the conversation body — **plain text only**. HTML is not supported in the initial message.
2. **Add subsequent items as replies** via `POST /conversations/{id}/reply` with `message_type: "comment"` and the correct author type (`user` or `admin`).
3. **Add internal notes** (including migrated voice calls) via `POST /conversations/{id}/reply` with `message_type: "note"`.
4. **Close completed conversations** via `POST /conversations/{id}/parts` with `message_type: "close"`.
5. **Attach tags** mapped from the original Gladly Topics.

Implement exponential backoff with jitter on 429 responses. Treat rate limiting as normal operational behavior, not an error condition.

```python
import random

def reply_with_backoff(conversation_id, payload, max_retries=5):
    for attempt in range(max_retries):
        resp = requests.post(
            f"https://api.intercom.io/conversations/{conversation_id}/reply",
            headers={
                "Authorization": "Bearer <token>",
                "Content-Type": "application/json",
                "Intercom-Version": "2.11"
            },
            json=payload
        )
        if resp.status_code == 429:
            wait = (2 ** attempt) + random.uniform(0, 1)
            time.sleep(wait)
            continue
        if resp.status_code >= 500:
            time.sleep(2 ** attempt)
            continue
        resp.raise_for_status()
        return resp.json()
    raise Exception(f"Failed after {max_retries} retries for conversation {conversation_id}")

for conv_id, items in group_by(gladly_items, 'conversationId'):
    ordered = sort_by(items, 'timestamp')
    chunks = split_conversation(ordered, max_parts=450)

    for idx, chunk in enumerate(chunks, start=1):
        first = chunk[0]
        intercom_conv = create_conversation(
            contact_id=contact_map[first['customerId']],
            body=render_body(first),
            created_at=to_unix(first['timestamp'])
        )

        for item in chunk[1:]:
            reply_with_backoff(
                intercom_conv['id'],
                {
                    "type": map_author_type(item),
                    "admin_id": agent_map.get(item.get('agentId')),
                    "body": render_body(item),
                    "message_type": "note" if item['channel'] in ['PHONE', 'VOICEMAIL', 'INSTAGRAM'] else "comment",
                    "created_at": to_unix(item['timestamp']),
                    "attachment_urls": rehost_attachments(item.get('attachments', []))
                }
            )

        tag_conversation(intercom_conv['id'], map_topics(chunk))
        record_idempotency(conv_id, idx, intercom_conv['id'])
```

### Step 6: Migrate Answers to Articles

Extract Gladly Public Answers via the Help Center API (`/api/v1/orgs/{orgId}/help-center/{helpCenterId}/answer-titles`, returns up to 1,000 answers). Create corresponding Intercom Articles via the [Articles API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Articles/).

**Mapping details:**

- **Gladly Sections → Intercom Collections.** Create Collections first via `POST /help_center/collections`, then reference the `collection_id` when creating articles.
- **Gladly Answer body formatting.** Gladly Answers use HTML. Intercom Articles also accept HTML, but rendering differences exist — test formatting on 5–10 representative articles before the bulk load.
- **Gladly Audiences → Intercom Help Center segmentation.** If you operate multiple brands via Gladly Audiences, you need separate Intercom Help Centers or filtered Collections per brand.
- **URL redirects.** If your Gladly Help Center is public-facing, set up 301 redirects from old Gladly Answer URLs to new Intercom Article URLs. Without this, inbound links and search engine rankings break. Maintain a redirect map: `{gladly_answer_url → intercom_article_url}`.

Article tags are not managed through Intercom's Articles API — tag handling needs its own pass via the Tags API.

### Step 7: Validate

See the validation section below. Do not cut over until record counts, field-level spot checks, and agent UAT all pass.

## How Long Does a Gladly to Intercom Migration Take?

A Gladly to Intercom migration takes **2–4 weeks** for a typical mid-market team (20–50 agents, 50,000–150,000 conversation items). Enterprise migrations with voice history, multi-brand Audiences, and 500,000+ items can take 4–6 weeks. The schedule is driven less by API throughput and more by mapping decisions, long-thread handling, UAT, and cutover discipline.

| Phase | Duration | Exit Criteria |
|---|---|---|
| Planning and mapping | 2–3 days | Final object map, cutover model, field list, GDPR assessment |
| Intercom workspace setup | 1–2 days | Teams, inboxes, custom attributes, tags created |
| Script development or tool config | 3–5 days | API credentials, sandbox access confirmed |
| Test migration (10% sample) | 1–2 days | Complex high-volume customers validated in sandbox |
| Validation and adjustment | 1–2 days | Stakeholder review complete |
| Full historical load | 1–3 days | Record counts and spot checks pass |
| Delta sync and cutover | 1 day | Gladly set to read-only, routing switched to Intercom |
| Post-go-live monitoring | 3–5 days | Agent feedback collected, reconciliation complete |

### Risk Register

| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Silent data truncation (`Gladly-Limited-Data`) | High for >100 convos/customer | Data loss | Check header on every response; use Export API for bulk |
| Conversation part limit exceeded (>500) | Medium | Partial history loss | Pre-split at ~450 parts during transform |
| Timestamp rejection on `created_at` | Low–Medium | Wrong conversation dates | Test in sandbox; verify plan supports historical timestamps |
| Attachment URL expiration | Medium | Broken attachments | Download all to S3/GCS before loading into Intercom |
| Agent ID mismatch | Low | Misattributed conversations | Pre-create all teammates; build ID mapping table |
| Duplicate contacts | Medium | Inconsistent customer records | Lock identity strategy before first load; handle 409s as lookups |
| GDPR data-residency violation | Low–Medium | Regulatory exposure | Verify Gladly and Intercom hosting regions match; see GDPR section below |
| Intercom plan feature gating | Low | `created_at` or API features unavailable | Confirm plan-level feature access with Intercom before development |

### Rollback Plan

Intercom has no one-click "undo import" feature. Plan for this:

1. Tag all migrated records with a `migration_batch` identifier (e.g., `migration_batch_2025_07_15`) during import.
2. If rollback is needed, use the Intercom API to bulk-delete conversations and contacts by tag. Note: the [Search Conversations API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Conversations/searchConversations/) has its own pagination limits — plan for multiple passes if deleting 100,000+ records.
3. Keep Gladly in read-only mode (not decommissioned) until post-go-live validation is complete — typically 5–7 business days.

## GDPR, Data Residency, and Compliance Considerations

Migrating customer PII between platforms triggers data-protection obligations. Address these before writing any extraction code:

- **Data residency.** Gladly hosts data in AWS US regions. Intercom offers US, EU, and AU hosting ([Intercom: Data Hosting](https://www.intercom.com/help/en/articles/5765-data-hosting-at-intercom)). If your Gladly instance holds EU customer data and your Intercom workspace is US-hosted, the migration constitutes a cross-border data transfer under GDPR. You may need Standard Contractual Clauses (SCCs) or a Transfer Impact Assessment (TIA).
- **Data Processing Agreements (DPAs).** Ensure DPAs are in place with both Gladly (as data exporter) and Intercom (as data importer) before migration. Both platforms offer DPAs on request.
- **Data minimization.** Migration is an opportunity to exclude data you no longer need. Consider excluding conversations older than your retention policy, closed CSAT-only records, or PII for customers who have exercised deletion rights.
- **Right to erasure compliance.** If you have pending GDPR erasure requests in Gladly, process them before migration — do not migrate data that should have been deleted.
- **Encryption in transit.** Both Gladly and Intercom APIs use TLS 1.2+. If you stage data in intermediate storage (S3, GCS), ensure encryption at rest is enabled.

## What Do Customers and Agents Notice?

If executed correctly, **customers notice nothing**. The migration happens on the backend. No emails are sent, no conversations are reopened in a customer-facing way.

The key risks to customer experience:

- **History gaps.** If conversation history is truncated or not fully migrated, agents lose context and customers get asked to repeat themselves.
- **Duplicate contacts.** If Gladly records are not deduplicated before import, customers may see inconsistent interactions or receive duplicate messages.
- **Workflow interruption.** If routing rules and SLAs are not rebuilt before go-live, first-response times may spike during the first 24–48 hours.

The biggest adjustment for agents is the shift from Gladly's single-timeline view to Intercom's discrete conversation model. Agents accustomed to scrolling through one continuous profile will need to search across individual conversations to find a customer's full history.

**Change management checklist:**

- Brief agents on Intercom's conversation-centric model 1–2 weeks before cutover.
- Create a mapping document: Gladly Topics → Intercom Tags, Gladly Inboxes → Intercom Team Inboxes.
- Train agents on the splitting logic used during migration (e.g., "Each Gladly Conversation became a separate Intercom Conversation. Any single conversation with 450+ items was split into multiple linked records with a shared `gladly_original_conversation_id` attribute").
- Schedule a 30-minute live training session on cutover day.
- Assign a migration liaison (senior agent) to handle escalations during the first week.

For a zero-downtime approach to the cutover itself, see our guide on [zero-downtime help desk migrations](https://clonepartner.com/blog/blog/zero-downtime-help-desk-data-migration/).

## Edge Cases and Known Limitations

### Voice, SMS, and Instagram Direct

Gladly natively handles voice calls with recording, IVR routing, and voicemail. Intercom has no native voice channel. Voice items should be migrated as internal notes with structured metadata:

```json
{
  "message_type": "note",
  "type": "admin",
  "admin_id": "<admin_id>",
  "body": "[Migrated Voice Call] Duration: 4m 32s | Agent: Jane Smith | Recording: <s3_url> | Original Channel: PHONE | IVR Path: Support > Billing"
}
```

SMS content migrates as text-based conversation parts, but channel metadata (carrier, delivery receipts) is lost. Instagram Direct has no native Intercom message type and must also be stored as notes.

### The 500-Part Hard Limit in Practice

Intercom rejects any attempt to add a 501st part. But the risk extends beyond migration day. If an active Gladly conversation has 490 items at the time of migration and you load all 490 into one Intercom conversation, agents will hit the limit almost immediately after go-live. Your transformation script should forcefully split any active conversation nearing 400 parts to give agents headroom.

Retrieving a conversation later via the Intercom API (`GET /conversations/{id}`) returns only the 500 most recent parts. You cannot rely on a single GET response as proof that a very long thread imported fully. To verify import completeness, maintain your own import ledger with part counts per conversation.

### Merged Customer Profiles

Gladly supports customer profile merging. If a customer was merged, requests to the original customer ID return a `301` redirect with the new ID in the `Location` header. Your extraction script must follow these redirects or you will miss merged customer history. Merged profiles can also cause history to appear out of order — review ordering before cutover.

```python
def get_customer(customer_id):
    resp = requests.get(
        f"https://{GLADLY_DOMAIN}/api/v1/customers/{customer_id}",
        headers={"Authorization": f"Basic {auth}"},
        allow_redirects=True  # Follow 301 for merged profiles
    )
    if resp.history:  # Redirect occurred
        log_info(f"Customer {customer_id} merged into {resp.url.split('/')[-1]}")
    return resp.json()
```

### Duplicate Contacts

Gladly allows multiple emails and phone numbers per customer profile. Intercom deduplicates contacts on `external_id` first, then `email`. Before importing, deduplicate Gladly customer records and decide which email becomes the primary identifier in Intercom. Failing to do this creates duplicate contacts — one of the most common sources of post-migration complaints.

### Attachments and Inline Images

Gladly conversation items can include attachments and inline images. **Download all attachment files to cloud storage (S3 or GCS) before the load phase.** If you pass Gladly CDN URLs directly to Intercom, the images will break when your Gladly contract expires and the instance is decommissioned.

Intercom's conversation creation endpoint accepts up to 10 image attachment URLs per API call. Non-image files (PDFs, CSVs) may need to be linked as URLs in the message body.

### Multi-Brand (Audiences)

Gladly uses Audiences to segment content for different brands. If you operate multiple brands, you need separate Intercom Help Centers or Collections per brand, with articles mapped accordingly. Plan the URL redirect strategy per brand — each brand's existing Help Center URLs need individual 301 redirect mappings.

### Intercom Data Retention and Archival

Intercom does not automatically archive or delete old conversations, but your Intercom plan may impose [data retention limits](https://www.intercom.com/help/en/articles/9399-data-retention-at-intercom). If you are migrating 5+ years of history, confirm with Intercom that your plan supports the volume without additional storage fees. Intercom's reporting and search indices may also perform differently with very large historical datasets — test search performance in your sandbox after loading historical data.

## What Data Cannot Be Migrated from Gladly to Intercom?

Be explicit with stakeholders about what does not transfer:

- **Automations and routing rules.** Must be rebuilt as Intercom Workflows. Budget 1–2 days depending on complexity.
- **People Match configuration.** Gladly's identity resolution rules are not exportable.
- **Sidekick (AI) training data.** Guides, Journeys, and AI configuration do not export.
- **Voice call recordings as native channels.** Recording files can be referenced via URL in notes, but Intercom has no voice player.
- **CSAT survey responses tied to conversations.** Can be migrated as custom attributes on conversations, but the integration with CSAT providers (Delighted, SurveyMonkey, etc.) must be re-established.
- **Real-time analytics and dashboards.** Gladly reporting data does not transfer. Intercom Reporting starts fresh from go-live.
- **Conversation items beyond API caps.** Items beyond the 1,000-item REST limit per conversation require the Export API or bulk export jobs.
- **Instagram Direct channel metadata.** No native Intercom equivalent.
- **Nested topic hierarchies.** Intercom tags are flat. Nest levels are lost unless you encode them as path strings (e.g., `Billing > Refunds > Partial`).
- **Gladly webhooks.** Must be rebuilt as Intercom webhook subscriptions or Workflow triggers.

## Validation and Testing

Validation is not optional. A migration without validation is data dumping.

### Record-Count Reconciliation

| Object | Gladly Count (source) | Intercom Count (target) | Match? |
|---|---|---|---|
| Customers → Contacts | Count via Reporting API or Export | Count via [Search Contacts API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Contacts/searchContacts/) | Must match |
| Conversations | Count via customer conversation lists | Count via [Search Conversations API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Conversations/searchConversations/) | Must match (may exceed source if splits occurred) |
| Conversation Items → Parts | Sum of all timeline items | Sum of all conversation parts from import ledger | Must match (±1% for splits) |
| Topics → Tags | Count via Topics API | Count via Tags API | Must match |
| Answers → Articles | Count via Public Answers API | Count via Articles API | Must match |

Do not rely on top-level record counts alone. A successful export might show 100,000 customers and Intercom might show 100,000 contacts, but that does not mean timeline data is intact.

**Note on Intercom Search API constraints:** The [Search Conversations API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Conversations/searchConversations/) returns paginated results and is subject to rate limits. For workspaces with 500,000+ conversations, full verification via API can take hours. Plan your validation script to run overnight if needed, and maintain your own import ledger as the primary reconciliation source.

### Specific Audit Checks

- **Truncation Audit:** Query your extraction logs for the `Gladly-Limited-Data` header. Ensure every flagged record triggered a successful fallback to the Export API or paginated sub-query.
- **Part Limit Audit:** Query your transformation logs for any timeline chunk containing exactly 500 items. This is a red flag that your splitting logic failed and Intercom rejected subsequent messages.
- **Attachment Sampling:** Randomly sample 100 historical conversations that contained attachments. Click the links to verify they resolve to your cloud storage (S3/GCS), not Gladly's CDN.
- **Split-Conversation Audit:** Query Intercom for all conversations tagged `gladly_continuation: true`. Verify each has a corresponding parent conversation with a matching `gladly_original_conversation_id`.

### Field-Level Spot Checks

Sample 50–100 records across different customer segments (high-volume, low-volume, multi-channel). For each:

1. Verify conversation count matches (accounting for any splits).
2. Verify first and last message timestamps match.
3. Verify agent attribution on replies.
4. Verify tags/topics are correctly mapped.
5. Verify attachments are accessible via S3/GCS URLs.

### Agent UAT

Have 3–5 agents search for known customers and verify:

- Can they find the customer's full history?
- Are conversations in the correct chronological order?
- Are internal notes present and attributed to the correct agent?
- Do knowledge base articles (Answers → Articles) render correctly?
- Do Help Center URLs redirect correctly from old Gladly paths?

For a comprehensive QA framework, see our [help desk data migration QA checklist](https://clonepartner.com/blog/blog/help-desk-data-migration-qa-checklist/).

## Build In-House or Use a Managed Service?

### When in-house is the right call

- Fewer than 5,000 total conversation items
- No voice, SMS, or Instagram Direct history to migrate
- No customers with >100 conversations (no `Gladly-Limited-Data` truncation risk)
- A backend engineer available for 100–160 hours with no competing priorities
- You have done an API-to-API migration before
- No cross-border data-residency concerns

### When in-house is not the right call

- 50,000+ conversation items
- Voice recordings, SMS, or WhatsApp history that needs preservation
- High-value customers with long timelines hitting Gladly's API truncation limits
- Zero-downtime requirement with delta sync
- Cross-region GDPR data transfer requirements
- No engineer available for 3+ weeks of dedicated migration work
- The cost of a failed migration (re-migration, agent downtime, customer complaints) exceeds the cost of a managed service

The hidden cost of DIY is not the initial build — it is the debugging. Missed `Gladly-Limited-Data` headers, conversations that silently exceed 500 parts, timestamp mismatches, duplicate contacts from multi-email customers — these issues surface during validation and require 2–3x the expected effort to resolve.

Building a script to hit an API is straightforward. Building a deterministic algorithm to split continuous omnichannel timelines into discrete conversations under a 500-part ceiling without losing historical attribution is a different class of engineering problem.

> Need to migrate from Gladly to Intercom without losing customer history? Book a free 30-minute migration planning call.
>
> [Talk to us](https://cal.com/clonepartner/meet?duration=30)

## Frequently asked questions

### How long does a Gladly to Intercom migration take?

A Gladly to Intercom migration takes 2–4 weeks for a typical mid-market team with 50,000–150,000 conversation items. This includes planning, schema mapping, test migration, full migration, delta sync, and post-go-live validation. Enterprise migrations with voice history and 500,000+ items can take 4–6 weeks.

### What is the biggest risk in a Gladly to Intercom migration?

Silent data truncation. Gladly's API returns at most 100 conversations per customer and 1,000 items per conversation. If your extraction script does not check the Gladly-Limited-Data response header, you will lose customer history without any error message. This is the most common cause of post-migration data loss.

### What data cannot be migrated from Gladly to Intercom?

Gladly automations, routing rules, People Match configuration, Sidekick AI training data, SLA policies, and real-time analytics cannot be migrated and must be rebuilt manually in Intercom. Voice call recordings can be preserved as linked URLs in internal notes but not as native Intercom voice interactions.

### Can Gladly conversation history be preserved in Intercom?

Yes, but it requires transformation. Gladly's continuous customer timelines must be split into discrete Intercom Conversations, each with a maximum of 500 parts. Intercom's Create Conversation endpoint accepts a created_at timestamp for historical imports. Voice and SMS items migrate as internal notes since Intercom has no native voice channel.

### How much does a Gladly to Intercom migration cost?

DIY API scripting costs 100–160 engineer-hours ($15,000–$30,000 at loaded engineering rates). Third-party migration tools typically charge $2,000–$8,000 for 50K–150K records. Managed migration services range from $5,000–$20,000 depending on volume, complexity, and whether voice/SMS history is included.
