---
title: "Salesforce Service Cloud to Front: ETL Migration Guide"
slug: salesforce-service-cloud-to-front-etl-migration-guide
date: 2026-10-20
author: Roopendra Talekar
categories: [Salesforce Service Cloud, Front, Migration Guide]
excerpt: "A technical guide to extracting Salesforce Service Cloud Cases, EmailMessages, and attachments and loading them into Front via the Import Message API."
tldr: "No native Salesforce-to-Front importer exists. Extract via Bulk API 2.0, flatten Cases into conversation threads, load via Front's Import Message API under tight per-company rate limits."
canonical: https://clonepartner.com/blog/salesforce-service-cloud-to-front-etl-migration-guide
---

# Salesforce Service Cloud to Front: ETL Migration Guide


# Salesforce Service Cloud to Front: ETL Migration Guide

> [!NOTE]
> **TL;DR — Salesforce Service Cloud to Front Migration**
>
> There is no native Salesforce-to-Front importer. This migration requires a custom ETL pipeline: extract Cases, EmailMessages, CaseComments, and ContentVersions via Salesforce Bulk API 2.0 and REST API, flatten the relational model into chronological conversation threads, and load via Front's Import Message API (`POST /inboxes/{inbox_id}/imported_messages`) — one message per request, under tight per-company rate limits. The hardest parts are attachment extraction (ContentDocumentLink joins that burn API calls), threading (import the first message, retrieve the `conversation_id`, then thread remaining messages), and throughput (Front caps at 50–200 rpm depending on plan). Most data migrations complete within 1–5 business days.

Migrating from **Salesforce Service Cloud to Front** means converting an enterprise relational data model — Cases, EmailMessages, CaseComments, ContentVersions, Contacts, Accounts — into Front's conversation-centric inbox architecture, much like the architectural shift required in a [Salesforce to Zendesk migration](https://clonepartner.com/blog/blog/salesforce-service-cloud-to-zendesk-migration-technical-guide). Front collapses all of that into a flat, chronological message thread inside a conversation.

Front's built-in importers only cover Freshdesk, Zendesk, and Help Scout — and even those are limited to roughly 9,000 tickets and are not actively maintained. For Salesforce data, the only viable route is a custom ETL pipeline using Front's Import Message API. This guide covers the exact object mapping, SOQL queries, transformation logic, API constraints on both sides, threading strategy, error handling, and the failure modes that appear in real migrations. For a detailed look at exporting from Salesforce, see [How to Export Data from Salesforce Service Cloud](https://clonepartner.com/blog/blog/how-to-export-data-from-salesforce-service-cloud-methods-limits). For target-side preparation, keep the [Front Migration Checklist](https://clonepartner.com/blog/blog/front-migration-checklist) nearby.

All API-specific claims reflect documentation as of mid-2026. Verify rate limits and field constraints against current platform docs before implementation.

## Salesforce Service Cloud to Front: Data Model Mapping

**A Salesforce Service Cloud Case maps to a Front Conversation** — but the mapping is not 1:1. Salesforce treats a support ticket as a primary record surrounded by related objects for emails, notes, and files. Front treats the conversation thread itself as the primary record, with messages and comments nested inside it.

| Salesforce Object | Front Equivalent | Mapping Notes |
| --- | --- | --- |
| Case | Conversation | One Case becomes one Conversation. Subject maps directly. |
| EmailMessage (Incoming=true) | Inbound message | Import as type `email` with sender set to the customer. |
| EmailMessage (Incoming=false) | Outbound message | Import as type `email` with sender set to the agent. |
| CaseComment (IsPublished=true) | Message | Customer-visible comments must be imported as messages, not internal comments. Plain text only — no HTML variant exists. |
| CaseComment (IsPublished=false) | Internal comment | Use `POST /conversations/{id}/comments` after the conversation exists. |
| ContentVersion / Attachment | Message attachment | Download binary from Salesforce REST API, re-upload to Front via `multipart/form-data`. 25 MB per message limit. |
| Contact | Contact | Match by email handle. Front enforces unique email per contact. |
| Account | Account | Match by domain. Front links contacts to accounts via domain. |
| Case Owner (User) | Teammate (assignee) | Match by email. Use `assignee_id` on the imported message or PATCH after import. |
| Case Status | Conversation status | Map Closed → `archived`, any open status → `open`. |
| Case Priority / Custom Fields | Tags or custom fields | No direct equivalent — use Front tags or conversation custom fields (plan-dependent). |

> [!WARNING]
> **CaseComment.CommentBody is limited to 4,000 bytes** (not characters) when read via API. HTML-encoded entities count against this limit — `&amp;` burns 5 bytes for 1 visible character. Salesforce silently truncates comments exceeding this limit at the source (a data loss risk we also highlight in our [Intercom to Salesforce migration guide](https://clonepartner.com/blog/blog/how-to-migrate-from-intercom-to-salesforce-service-cloud-2026)). If your org stores long replies in CaseComments instead of EmailMessages, some content may already be lost before extraction begins.

The **`IsPublished` flag** on CaseComment is critical to get right. Front comments are private to teammates — visible only internally. If you load every Salesforce CaseComment as a Front comment, any customer-visible notes disappear from the message timeline agents see. Internal notes become Front comments; published notes become imported messages. ([developer.salesforce.com](https://developer.salesforce.com/docs/platform/field-reference/references/field-reference/salesforce-field-reference-casecomment.html))

> [!TIP]
> If Salesforce remains your CRM after the move, do not force every CRM field into Front. Front's native Salesforce integration can display and update Salesforce records from the inbox, log conversation threads, and run one-way contact and account syncs (supporting up to 1M synced contacts and 500K synced accounts). Store what agents need inline and link back to Salesforce for deeper CRM context instead of flattening every relationship into Front custom fields. ([help.front.com](https://help.front.com/en/articles/2305))

## Why There Is No Native Import Path

Front does not offer a Salesforce Service Cloud importer. Its three built-in importers (Freshdesk, Zendesk, Help Scout) are limited, and Front itself states they are "not actively maintained" — recommending partner services for larger migrations. CSV import is not an option for conversation data; Front has no bulk CSV conversation import feature.

The only API endpoint designed for historical data ingestion is the **Import Message** endpoint (`POST /inboxes/{inbox_id}/imported_messages`). It accepts one message per request, returns `202 Accepted` asynchronously, and deduplicates by `external_id`. Every EmailMessage and every published CaseComment requires its own API call. ([help.front.com](https://help.front.com/en/articles/2046))

A Salesforce org with 10,000 Cases averaging 6 EmailMessages each requires roughly **60,000 API calls** just for message bodies — before contacts, accounts, attachments, or internal comments.

## Step 1: Extract Data from Salesforce

Extraction uses two Salesforce APIs in combination. **Bulk API 2.0** handles high-volume flat object queries (Cases, Contacts, Accounts). **REST API** handles EmailMessages, CaseComments, and binary file downloads. Bulk API 2.0 is designed for operations above roughly 2,000 records, but it does not support parent-to-child relationship subqueries — so you must extract objects separately and join them locally during transformation. ([developer.salesforce.com](https://developer.salesforce.com/docs/platform/api-asynch/guide/queries.html))

For a deep dive on extraction methods and limits, see [How to Export Data from Salesforce Service Cloud](https://clonepartner.com/blog/blog/how-to-export-data-from-salesforce-service-cloud-methods-limits).

### Core SOQL Queries

**Cases:**

```sql
SELECT Id, CaseNumber, Subject, Status, Priority, Origin,
       AccountId, ContactId, OwnerId, CreatedDate, ClosedDate,
       Description, Type
FROM Case
WHERE CreatedDate >= 2024-01-01T00:00:00Z
```

**EmailMessages:**

```sql
SELECT Id, ParentId, Subject, TextBody, HtmlBody,
       FromAddress, ToAddress, CcAddress, BccAddress,
       MessageDate, Incoming, HasAttachment,
       IsExternallyVisible, CreatedById
FROM EmailMessage
WHERE ParentId IN (SELECT Id FROM Case WHERE CreatedDate >= 2024-01-01T00:00:00Z)
```

**CaseComments:**

```sql
SELECT Id, ParentId, CreatedDate, CreatedById,
       CommentBody, IsPublished
FROM CaseComment
WHERE ParentId IN (SELECT Id FROM Case WHERE CreatedDate >= 2024-01-01T00:00:00Z)
```

**ContentDocumentLinks (for attachments):**

```sql
SELECT ContentDocumentId, LinkedEntityId
FROM ContentDocumentLink
WHERE LinkedEntityId IN :caseOrEmailIds
```

**ContentVersions (file metadata):**

```sql
SELECT Id, ContentDocumentId, Title, FileExtension,
       ContentSize, Checksum, CreatedDate
FROM ContentVersion
WHERE ContentDocumentId IN :docIds
AND IsLatest = true
```

**EmailMessageRelations (for CC/BCC participant mapping):**

```sql
SELECT Id, EmailMessageId, RelationId, RelationAddress,
       RelationObjectType, Type
FROM EmailMessageRelation
WHERE EmailMessageId IN :emailMessageIds
```

`EmailMessageRelation` is required when you need canonical participant records for CC'd and BCC'd contacts — the rendered `ToAddress` and `CcAddress` strings on `EmailMessage` contain semicolon-delimited addresses that must be parsed, while `EmailMessageRelation` provides structured references to the underlying Contact or User records. Omitting this join causes CC/BCC participants to appear as raw email strings rather than linked Front contacts.

### The Attachment Extraction Trap

Extracting attachments from Salesforce is the most API-expensive part of the migration. **ContentDocumentLink** is a junction object connecting files to parent records — skipping this join is the single most common reason attachment migrations fail, leaving orphaned files that cannot be associated with their parent Case or EmailMessage.

Bulk API 2.0 cannot export binary content from `ContentVersion.VersionData`. Each file must be downloaded individually via the REST API:

```
GET /services/data/vXX.0/sobjects/ContentVersion/{id}/VersionData
```

> [!CAUTION]
> **API Limit Warning:** Salesforce Enterprise Edition orgs have a base allocation of 100,000 REST API calls per day plus 1,000 per user license. Bulk API 2.0 query jobs have a separate allocation of 10,000 per 24-hour rolling window. If you have 200,000 attachments, attempting to download them all in a single day will exhaust your limits and disrupt other integrations on your production org. Batch file downloads over several days or use a dedicated extraction tool.

### Salesforce Extraction Limits at a Glance

| Constraint | Limit |
| --- | --- |
| Daily REST API calls | 100,000 base + 1,000 per user license (Enterprise Edition) |
| Bulk API 2.0 query jobs | 10,000 per 24-hour rolling window |
| Bulk API 2.0 query results | 1 TB per 24-hour rolling window |
| Concurrent long-running requests | 25 (production), 5 (developer/trial) |

### Timezone Normalization

Salesforce stores `CreatedDate` and `MessageDate` in UTC, but org-level timezone settings can affect how these values are displayed in the UI — and some legacy integrations write timestamps in local time. Before loading into Front, normalize all timestamps to UTC and convert to Unix epoch seconds. Front's `created_at` field accepts Unix timestamps and stores them as UTC. A mismatch causes messages to appear out of chronological order within a conversation thread.

```python
from datetime import datetime, timezone

def sf_datetime_to_unix(sf_datetime_str: str) -> int:
    """Convert Salesforce ISO 8601 datetime string to UTC Unix timestamp."""
    dt = datetime.fromisoformat(sf_datetime_str.replace('Z', '+00:00'))
    return int(dt.astimezone(timezone.utc).timestamp())
```

## Step 2: Transform Relational Data into Conversation Threads

Transformation converts Salesforce's multi-object relational model into Front's flat conversation-message model. As with other flat-architecture targets like [eDesk](https://clonepartner.com/blog/blog/salesforce-service-cloud-to-edesk-migration-technical-guide), this is where most migrations break.

### Merging EmailMessages and CaseComments into a Single Timeline

Front expects a chronological feed. If you import messages out of order, the conversation history becomes unreadable. The transformation logic must:

1. **Collect all EmailMessages and CaseComments for each Case**, grouped by `ParentId`.
2. **Sort by `MessageDate` (for emails) or `CreatedDate` (for comments)** to build a unified timeline.
3. **Determine message direction.** `EmailMessage.Incoming=true` → inbound (sender is the customer). `Incoming=false` → outbound (sender is the agent).
4. **Split CaseComments by `IsPublished`.** Published comments become imported messages. Unpublished comments are loaded as internal Front comments via a separate endpoint after the conversation exists.
5. **Identify the first message.** If the Case was created via email, the oldest EmailMessage becomes the first message. If it was created via a web form, the `Case.Description` may serve as the initial message body.

### HTML Body Sanitization

**Prefer `HtmlBody` over `TextBody`** when extracting EmailMessages. HTML preserves formatting, inline images, and reply chains. `TextBody` is a stripped representation that loses structure. Front's imported messages accept `body_format` of `html` or `markdown`, so use `html` when HtmlBody is available and fall back to `markdown` when it is not. ([developer.salesforce.com](https://developer.salesforce.com/docs/platform/field-reference/references/field-reference/salesforce-field-reference-emailmessage.html))

Salesforce `HtmlBody` fields often contain artifacts that must be cleaned before loading into Front:

- **Inline image references** using the `refid://` protocol — these will not render in Front. Replace with direct URLs or base64-encoded `data:` URIs.
- **Salesforce-specific CSS classes** (`sfdcBody`, `htmlDetailBody`) — strip these to prevent broken rendering.
- **`<style>` elements** that conflict with Front's email rendering engine.
- **Silent truncation** — Salesforce HtmlBody is capped at 131,072 characters per the [Salesforce EmailMessage field reference](https://developer.salesforce.com/docs/platform/field-reference/references/field-reference/salesforce-field-reference-emailmessage.html). Emails exceeding this limit are truncated at the source without warning. The `TextBody` equivalent is capped at 32,000 characters.

### `metadata.thread_ref` and In-Reply-To Headers

When importing email replies, Front's Import Message API accepts an optional `metadata.thread_ref` field that corresponds to the RFC 2822 `Message-ID` header value of the original email. If your Salesforce EmailMessage records retain the original `MessageIdentifier` field (populated when Email-to-Case processes inbound mail), populate `thread_ref` with that value. This allows Front to apply its native threading logic in addition to the explicit `conversation_id` parameter, reducing the risk of threading errors if messages arrive out of order during the import. ([dev.frontapp.com](https://dev.frontapp.com/reference/import-inbox-message))

### Making Reruns Idempotent

Front rejects imports with a previously-used `external_id`. Use stable, source-derived identifiers: `sf-email-{EmailMessage.Id}` for emails and `sf-comment-{CaseComment.Id}` for published comments. This ensures retries do not create duplicate history. If you need to re-run the migration after a failed attempt, either use a different inbox or delete the previously imported conversations first. ([dev.frontapp.com](https://dev.frontapp.com/reference/import-inbox-message))

### Status and Priority Mapping

Front conversations have three core statuses: **open**, **archived**, and **deleted**. Salesforce Cases have a configurable picklist (New, Working, Escalated, Closed, etc.). The mapping is necessarily lossy:

| Salesforce Case Status | Front State | Method |
| --- | --- | --- |
| Any open status (New, Working, Escalated) | `open` | Default on import |
| Closed | `archived` | Use `is_archived` metadata flag during import, or PATCH afterward |
| Custom statuses | Tags | Apply as Front tags during or after import |

Case Priority, Origin, and Type have no native Front equivalent. Map these to **tags** or **conversation custom fields** (available on Scale plans and above).

## Step 3: Load into Front via the Import Message API

### Required OAuth Scopes

Before implementation, configure your Front API token or OAuth app with the following scopes. Missing scopes return `403 Forbidden` without a descriptive error message:

| Operation | Required Scope |
| --- | --- |
| Import messages | `messages:write` |
| Create/update contacts | `contacts:write` |
| Create/update accounts | `accounts:write` |
| Post internal comments | `comments:write` |
| PATCH conversation metadata | `conversations:write` |
| List teammates (for owner mapping) | `teammates:read` |
| List inboxes | `inboxes:read` |

Front's sandbox environment (`api2.frontapp.com` with a dedicated sandbox token) is available for testing import pipelines before production load. Run a complete migration against a sandbox with a representative 50–100 Case sample before touching production.

### Load Order

The dependency chain dictates the loading sequence:

1. **Contacts** — Create or update via `POST /contacts` with the customer's email handle. Front enforces unique handles; duplicates return `409 Conflict`.
2. **Accounts** — Create accounts and link contacts by domain. (If Salesforce remains your CRM, Front's native Salesforce sync handles this automatically.)
3. **First message per Case** — Import via `POST /inboxes/{inbox_id}/imported_messages`. This creates both the message and the conversation.
4. **Retrieve the conversation_id** — The Import endpoint returns `202 Accepted` asynchronously. Poll `GET /messages/alt:uid:{message_uid}` to retrieve the conversation reference. Add a 1–2 second delay before querying.
5. **Remaining messages per Case** — Import with the `conversation_id` parameter to thread into the existing conversation, sorted by date ascending.
6. **Internal comments** — Load unpublished CaseComments via `POST /conversations/{id}/comments`.
7. **Attachments** — Include as `multipart/form-data` in the import call. 25 MB per message limit.
8. **Post-import updates** — PATCH conversations with `assignee_id`, `status_id`, tags, custom fields, and links back to the source Salesforce Case.

> [!WARNING]
> **Front's import endpoint returns `202 Accepted` asynchronously.** The message and conversation are not immediately queryable. If your pipeline threads messages by `conversation_id`, you must poll or add a delay before importing the next message in the same thread. Racing this step creates orphaned conversations — messages that should be threaded together end up in separate conversations.

### Sample Import Payload

```json
{
  "sender": {
    "handle": "customer@example.com",
    "name": "Jane Doe"
  },
  "to": ["support@yourcompany.com"],
  "subject": "Login issue with production database",
  "body": "<p>I am unable to access the production database since the update.</p>",
  "body_format": "html",
  "external_id": "sf-email-02sXXXXXXXXXXXXX",
  "created_at": 1704067200,
  "type": "email",
  "metadata": {
    "is_inbound": true,
    "is_archived": true,
    "should_skip_rules": true,
    "thread_ref": "<CAOriginalMessageID@mail.example.com>"
  }
}
```

The **`created_at`** field accepts a Unix timestamp, allowing Front to backdate the message to its original Salesforce `MessageDate`. The **`external_id`** enables deduplication across retries. Set **`should_skip_rules`** to `true` to prevent historical imports from triggering Front's assignment rules, tag automations, and notifications. Set **`is_archived`** to `true` for closed Cases to avoid cluttering the open inbox. The optional **`thread_ref`** field accepts the original RFC 2822 `Message-ID` header to reinforce threading logic. ([dev.frontapp.com](https://dev.frontapp.com/reference/import-inbox-message))

### Attachment Handling

When a message has attachments, switch from `application/json` to `multipart/form-data`. Include the JSON metadata as one part and append file binaries as attachment parts. Front enforces a strict **25 MB limit** on total message size including attachments.

Salesforce `ContentVersion` supports files up to 2 GB, so oversized files are a real edge case. If a Case contains attachments exceeding Front's limit, your ETL script must catch the `413 Payload Too Large` error, host the files externally (e.g., Amazon S3), and insert download links into the message body instead.

> [!WARNING]
> **Partial custom-field updates clobber data.** Front's API erases omitted custom fields when you update a conversation. Always send the full custom-fields object, not just the fields you want to change. ([dev.frontapp.com](https://dev.frontapp.com/reference/update-conversation))

## API Rate Limits: Both Sides

Rate limits are the primary throughput bottleneck. Both platforms enforce strict constraints, but Front's limits are tighter and more impactful on the import side.

### Front API Limits

| Front Plan | Rate Limit | Per-Resource Cap |
| --- | --- | --- |
| Starter | 50 req/min | 5 req/sec per resource type |
| Growth | 100 req/min | 5 req/sec per resource type |
| Scale | 200 req/min | 5 req/sec per resource type |

Front's rate limit is **per company, not per token** — every integration, API token, and OAuth app on the account draws from the same pool. A migration script running at full speed starves live integrations (Slack notifications, Zapier automations, CRM syncs). Partner OAuth integrations get a separate 120 rpm limit, which is why partner-led migrations avoid impacting your team's live workflows.

Exceeding the limit returns `429 Too Many Requests` with a `Retry-After` header. Exhausting the burst buffer triggers a cooldown period of roughly 10 minutes.

### Throughput Math

On Front's Growth plan (100 rpm), importing 10,000 Cases with 6 messages each:

- **60,000 import calls** ÷ 100 rpm = **600 minutes** (~10 hours), assuming zero overhead.
- Add contact creation, conversation status PATCHes, internal comments, and attachment uploads → realistic throughput is **40–60 effective imports per minute** after backoff and retries.
- **Total wall-clock time: 16–25 hours** for the import side alone.

On Scale (200 rpm), the same volume compresses to roughly 8–13 hours. Rate limit add-ons (300 additional rpm per add-on) can further reduce this.

### Error-Handling Decision Matrix

Build explicit handling for each HTTP error code into your loading script. Do not treat all non-200 responses identically.

| HTTP Status | Cause | Correct Action |
| --- | --- | --- |
| `202 Accepted` | Message queued, not yet written | Poll `GET /messages/alt:uid:{uid}` after 1–2 second delay |
| `400 Bad Request` | Malformed payload, invalid field type | Log full request body, skip record, flag for manual review |
| `403 Forbidden` | Missing OAuth scope or inbox access | Check token scopes; verify inbox_id is accessible to the token |
| `404 Not Found` | `conversation_id` or `inbox_id` does not exist | Verify conversation was successfully created before threading |
| `409 Conflict` | `external_id` already used | Record already imported; skip silently or verify idempotency |
| `413 Payload Too Large` | Attachment exceeds 25 MB | Strip attachment, upload to external storage, insert download link in body |
| `429 Too Many Requests` | Rate limit exceeded | Read `Retry-After` header; apply exponential backoff with jitter |
| `500 / 503` | Front server error | Retry with exponential backoff (max 3 attempts); log if persistent |

For `429` responses specifically: implement token-bucket rate limiting in your script rather than reacting to `429s` after the fact. Track the `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers returned on every Front API response to proactively throttle before the limit is reached.

## Validation Methodology

Spot-checking is insufficient for production migrations. Use a structured validation protocol before cutover.

### Record-Count Parity

After the initial load, compare record counts between source and target:

```python
# Salesforce side (run via REST API)
sf_counts = {
    'cases': query("SELECT COUNT() FROM Case WHERE ..."),
    'emails': query("SELECT COUNT() FROM EmailMessage WHERE ..."),
    'comments': query("SELECT COUNT() FROM CaseComment WHERE IsPublished=true AND ...")
}

# Front side (count via GET /conversations with filters)
front_counts = {
    'conversations': count_front_conversations(inbox_id=TARGET_INBOX),
    'messages': sum(get_message_count(conv_id) for conv_id in conversation_ids)
}
```

Discrepancies greater than 0.5% warrant investigation before proceeding to delta sync.

### Checksum-Based Attachment Validation

Salesforce `ContentVersion.Checksum` stores the MD5 hash of the file content. After downloading and re-uploading to Front, compute the MD5 of the downloaded binary before upload and log it against the source checksum. A mismatch indicates a corrupted download — retry the extraction rather than loading a corrupted file.

```python
import hashlib

def validate_attachment(local_path: str, sf_checksum: str) -> bool:
    with open(local_path, 'rb') as f:
        computed = hashlib.md5(f.read()).hexdigest()
    return computed.lower() == sf_checksum.lower()
```

### Threading Validation

For a random sample of 100 Cases with 3+ messages, verify that:
- The Front conversation contains the expected message count
- Messages are ordered chronologically by `created_at`
- The first message `sender.handle` matches the Salesforce `EmailMessage.FromAddress` on the oldest inbound email

## Edge Cases and Failure Modes

### Auto-Response Emails in Email-to-Case

If your Salesforce org uses **case auto-response rules**, those auto-generated emails are stored as EmailMessages linked to the Case. Unless you filter them, they get imported into Front as regular messages in the conversation. Add `WHERE IsExternallyVisible = true` to your EmailMessage query, or filter by `Status` values specific to your org's configuration.

### Conversation Ownership Without Matching Teammates

If a Salesforce Case Owner's email does not match any Front teammate, the `assignee_id` parameter silently fails — no error, just no assignment. Build a teammate lookup map before migration: extract all Case Owner emails from Salesforce, list all Front teammates via `GET /teammates`, and flag mismatches. Unmatched owners should fall back to a default teammate or be left unassigned.

### LiveChatTranscript and Messaging Records

Salesforce stores live chat interactions in `LiveChatTranscript` — a single `Body` text field containing the full conversation, not individual messages. Migrating chat history requires parsing that monolithic text block into discrete messages with imputed timestamps. This is lossy by nature (a schema translation challenge we also detail in our [Freshchat to Salesforce migration guide](https://clonepartner.com/blog/blog/freshchat-to-salesforce-service-cloud-migration-technical-guide)). `MessagingSession` and `ConversationEntry` objects follow different extraction patterns and are a separate workstream.

### Salesforce Knowledge Articles

Salesforce Knowledge articles (`KnowledgeArticleVersion`) can be migrated to Front's Knowledge Base via a separate API, but the content model differs significantly. Treat this as a distinct workstream from conversation migration.

## What Cannot Be Migrated

Some Salesforce Service Cloud artifacts have no Front equivalent and must be rebuilt manually in the target platform:

- **Automation rules** — Process Builder, Flows, Assignment Rules, Escalation Rules → rebuild as Front Rules
- **Macros and email templates** — Quick Text, Email Templates → Front Message Templates
- **SLA policies** — Entitlement Processes, Milestones → Front SLA rules (different model)
- **Dashboards and reports** — Salesforce Reports → Front Analytics (fresh start; historical metrics do not transfer)
- **Omni-Channel routing** — rebuild using Front's assignment rules and load balancing
- **Approval processes** — no native Front equivalent

## How Long Does a Salesforce Service Cloud to Front Migration Take?

**The data migration itself is typically completed within 1–5 business days**, depending on data volume, complexity, and API rate limits. Small datasets under 10,000 records can finish in under 24 hours.

| Volume (Cases) | Estimated Migration Time | Primary Bottleneck |
| --- | --- | --- |
| 1–500 | 1–2 business days | Setup and mapping; limited API pressure |
| 500–5,000 | 3–7 business days | Front rate limits (100–200 rpm); attachment volume |
| 5,000–50,000 | 7–13 business days | Front rate limits; Salesforce daily API consumption; attachment extraction |
| 50,000+ | Custom scoping required | Multi-day Salesforce extraction; may require rate limit add-ons on Front |

These figures describe the ETL data migration only. They do not include your internal Front rollout: configuring inboxes, building rules, training agents, and setting up integrations. That effort is measured in weeks or months. Start your migration scoping at least **3–4 months** before any internal go-live deadline or Salesforce contract expiration to leave room for both workstreams.

## Planning the Cutover

A zero-downtime cutover requires a **delta sync** strategy. A full extraction and load for hundreds of thousands of Cases takes days, and your agents must continue working in Salesforce during the historical data load.

The standard protocol:

1. **Initial sync** — Extract all closed Cases and historical data up to a specific timestamp. Load into Front.
2. **Validation** — Record-count parity checks, checksum-based attachment validation, field-level spot checks, and threading verification on a representative sample.
3. **Delta sync** — Extract only Cases modified since the initial sync timestamp. Transform and load the updates.
4. **Cutover** — Pause inbound email routing to Salesforce, redirect mail forwarding to Front, run one final delta sync to catch messages received during the DNS propagation window, and log agents into Front.

A good migration leaves agents with **complete, searchable conversation history in Front without turning Front into a brittle copy of Salesforce**. Customer-visible history is preserved as readable messages, internal notes stay private, key case metadata is searchable via tags and custom fields, oversized files have a documented fallback path, and agents can still jump back to Salesforce when they need deeper CRM context. For more on Front's architecture and capabilities, see our [Front technical guide](https://clonepartner.com/blog/blog/ultimate-guide-front-2026).

At ClonePartner, we execute this end-to-end: one fixed price per project starting at $500, no hourly billing, no per-record metering. We run unlimited sample migrations until the data mapping is right, followed by the full migration and delta syncs. We have completed 1,500+ successful migrations, with one dedicated migration engineer owning each project. Our infrastructure is secured by SOC 2 Type II and ISO 27001 safeguards.

> Need to move Salesforce Service Cloud cases to Front with full conversation history? Book a free 30-minute scoping call. We'll review your data model, map the extraction path, and provide a fixed-price proposal.
>
> [Talk to us](https://clonepartner.com/talk-to-us?duration=30&utm_source=blog&utm_medium=button&utm_campaign=demo_bookings&utm_content=cta_click&utm_term=demo_button_click)

## Frequently asked questions

### Can I import Salesforce Service Cloud cases into Front natively?

No. Front has no native Salesforce importer. Its built-in importers only cover Freshdesk, Zendesk, and Help Scout, and even those are limited and not actively maintained. Salesforce data must be imported via Front's Import Message API using a custom ETL pipeline.

### How long does a Salesforce Service Cloud to Front migration take?

The data migration itself is typically completed within 1–5 business days, depending on data volume, complexity, and API rate limits. Small datasets under 10,000 records can finish in under 24 hours. Larger volumes (5,000+ cases) are a custom engagement that may take 7–13+ business days.

### How do you handle attachments when migrating from Salesforce to Front?

Salesforce stores files as ContentVersion records linked via ContentDocumentLink. Each file must be downloaded individually via the Salesforce REST API, then included as multipart/form-data in Front's import call. Front caps attachments at 25 MB per message — files exceeding this must be hosted externally and linked in the message body.

### How should Salesforce CaseComments map to Front?

Published CaseComments (IsPublished=true) should be imported as messages within a Front conversation so they remain visible to agents. Unpublished CaseComments map to Front's internal comments endpoint. Note that CaseComment.CommentBody is limited to 4,000 bytes and has no HTML variant — only plain text.

### What are Front's API rate limits for importing messages?

Front's rate limits are per company, not per token: 50 requests/min on Starter, 100 on Growth, and 200 on Scale, with a per-resource burst cap of 5 requests per second. Exceeding the limit returns a 429 error with a Retry-After header. Partner OAuth integrations get a separate 120 rpm limit.
