Skip to content

Crisp to Gorgias Migration Guide (2026): APIs, Mapping & Edge Cases

A technical guide to migrating from Crisp to Gorgias: API constraints, data model mapping, rate limits, edge cases, and step-by-step ETL architecture for 2026.

Raaj Raaj · · 20 min read
Crisp to Gorgias Migration Guide (2026): APIs, Mapping & Edge Cases
TALK TO AN ENGINEER

Planning a migration?

Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.

Schedule a free call
  • 1,500+ migrations completed
  • Zero downtime guaranteed
  • Transparent, fixed pricing
  • Project success responsibility
  • Post-migration support included

Migrating from Crisp to Gorgias is an API project, not a CSV import. Crisp does not support native CSV exports for conversation data — every message, attachment, and agent note must be extracted through the Crisp REST API, structurally transformed from a chat-session model to a ticket-thread model, and loaded into Gorgias while respecting tight rate limits on both sides.(help.crisp.chat)

E-commerce brands typically initiate this move when they outgrow Crisp's chat-first widget architecture and need Gorgias's deep Shopify, BigCommerce, or Magento integrations. For a broader look at the business drivers behind the switch, see Why Top E-commerce Teams are Migrating to Gorgias.

This guide covers the exact API constraints, object mapping, edge cases, and step-by-step architecture you need before writing your first line of migration code.

Why E-commerce Teams Move from Crisp to Gorgias

Crisp is a chat-first customer messaging platform. It works well for startups running lean support across chat, email, and social. But as e-commerce teams scale on Shopify or BigCommerce, they hit a ceiling: Crisp lacks native deep e-commerce integrations, revenue-per-ticket attribution, and the advanced ticket routing that Gorgias provides out of the box.(gorgias.com)

The core driver is almost always Shopify integration depth. Gorgias lets agents view, edit, refund, and cancel orders directly inside the ticket sidebar without switching tabs. Crisp has no equivalent. For DTC brands where the majority of support tickets are order-related, this alone justifies the switch.

Other triggers include:

  • Automation and rules: Gorgias's rule engine auto-tags, auto-closes, and auto-responds based on intent detection and order data — capabilities that require custom bot scripting in Crisp.
  • Revenue tracking: Gorgias attributes revenue to support interactions, which matters for teams justifying headcount.
  • AI agents: Gorgias offers AI-resolved ticket automation billed per resolution, replacing the need for separate chatbot tooling.

For a technical deep dive into Gorgias's architecture, see Mastering Gorgias: The 2026 Technical Guide.

The Data Model Mismatch: Chat Sessions vs. Tickets

This is where most DIY migrations break. Crisp is chat-centric. Gorgias is ticket-centric. The two platforms model the same customer interaction in fundamentally different ways.

In Crisp, every interaction lives under a Conversation identified by a session_id. Messages — from a visitor, operator, or bot — are children of that session. A single conversation can span weeks or months if the visitor returns to the same chat widget session. Crisp conversations can contain up to approximately 10,000 messages before the API rejects additions.(docs.crisp.chat)

In Gorgias, the atomic unit is a Ticket. Each ticket represents a discrete support interaction, contains one or more messages, and is linked to exactly one customer. Tickets carry a status — either Open or Closed (Gorgias uses only two statuses) — and can be tagged, assigned to agents, and associated with e-commerce order data.

The translation problem: A single long-running Crisp conversation may need to become one Gorgias ticket, or you may want to split it into multiple tickets based on resolution state. There is no automatic mapping. You must make an architectural decision before you start loading data.

The status model changes too. Crisp supports pending, unresolved, and resolved. Gorgias only has open and closed. If you need exact historical semantics, Crisp's pending state usually has to survive as a tag or custom field rather than a native status.(docs.crisp.chat)

Object Mapping Table

Crisp Object Crisp API Path / Field Gorgias Object Gorgias API Path / Field Notes
People Profile /website/{id}/people/profiles Customer POST /api/customers Match on email. Create if not exists. Overflow profile data goes into customer.data.
Conversation /website/{id}/conversations (by session_id) Ticket POST /api/tickets One conversation = one ticket (typical). Store session_id in external_id for traceability.
Message (text) /website/{id}/conversation/{session_id}/messages Message POST /api/tickets/{id}/messages Set sent_datetime to prevent Gorgias from re-sending.
Message (note) type: "note" Internal Note channel: "internal-note" Gorgias internal notes are a message channel.
Message (file) type: "file" with content.url Attachment Upload via POST /api/upload, attach to message body_html Must download from Crisp, re-upload to Gorgias.
Segments segments [] on People Profile Tags tags: [{"name": "..."}] on Ticket Pipe-separated in Crisp, array in Gorgias. Normalize names before load.
Operator Workspace operators User/Agent POST /api/users Map by email. Handle inactive operators explicitly.
Conversation State resolved / unresolved / pending Ticket Status open / closed Gorgias only has two states. Map pending to open + a preservation tag.
Conversation Metas get_conversation_metas() Ticket meta + external_id JSON key-value on ticket Crisp people notepad has no first-class Gorgias equivalent — store in customer.data or emit a synthetic internal note.

Why Native CSV Export Fails for Crisp Conversations

This is the first thing teams discover — and it stops most non-technical migration plans dead.

Crisp's dashboard allows CSV export for contact profiles only, not for conversation data. Crisp's official documentation states explicitly that conversation exports are not available as a native CSV from the Crisp app.(help.crisp.chat) The contact CSV export is hard-capped at 200,000 profiles. If you have more, the UI export fails entirely and you must use the GET /website/{website_id}/people/profiles endpoint to paginate through your customer base.

This means there is no "export all, import all" path. You must use the Crisp REST API to extract conversations and messages programmatically, or use a third-party tool that does it for you.

Warning

Do not assume you can export Crisp chat history from the dashboard. Conversation data requires API extraction. Plan your migration timeline accordingly — API extraction at scale takes days, not hours.(help.crisp.chat)

API Constraints: Rate Limits and Pagination

Both Crisp and Gorgias enforce rate limits that directly constrain migration throughput. Misunderstanding these limits is the number one cause of failed DIY migration scripts.

Crisp API Rate Limits

Crisp uses a multi-level rate-limit system based on client IP and user identifier. There are four layers:

Limiter Scope Applies To
Load Balancers IP Address All tiers
API Global IP + User ID user and website tiers
API Route IP + User ID (per-route) user and website tiers
Plugin Quota Plugin ID (daily) plugin tier only

Plugin tokens are exempt from API Global and API Route limits but subject to a daily quota that resets every 24 hours. For migration, you want a plugin token with a production-tier quota. Development tokens have lower quotas and can only target a single trusted workspace. Crisp does not publicly document exact numeric limits — they state the limits are "quite permissive" but reserve the right to change them.

When rate-limited, Crisp returns 429 Too Many Requests or 420 Enhance Your Calm. Your extraction script must implement exponential backoff and respect any Retry-After headers in the response.

Gorgias API Rate Limits

Gorgias uses a leaky bucket algorithm with account-scoped limits that vary by authentication method and plan tier:(developers.gorgias.com)

Auth Type Rate Limit
OAuth2 apps 80 requests per 20-second window
API key integrations 40 requests per 20-second window
Starter/Basic plans ~2 req/s
Pro/Advanced plans ~10 req/s
Enterprise Custom (negotiable)

When the limit is exceeded, the API returns 429 Too Many Requests. Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After headers. Your migration script must read the Retry-After header and implement exponential backoff.

Gorgias Pagination

Gorgias uses cursor-based pagination across all list endpoints (offset-based pagination was removed in February 2024). The limit parameter defaults to 30 items and has a strict maximum of 100 per request. You follow next_cursor values until they return null. Do not attempt to batch 500 messages in a single payload — the API will reject it.

Gorgias list endpoints do not support server-side date filtering, so any filtering by creation or update timestamp must happen client-side after fetching.(developers.gorgias.com)

Warning

Failure to engineer a resilient retry mechanism for Gorgias's rate limits is the leading cause of incomplete data migrations. For recovery strategies, see Helpdesk Migration Failed? The Engineer's Rescue Guide.

Migration Approaches: Choose the Least-Wrong Path

There are five paths to evaluate. The right choice depends on your engineering bandwidth, data volume, and tolerance for risk.

1. Native CSV Export/Import (Contact Seeding Only)

Export contact profiles from Crisp, clean the file, and manually create customers and tags in Gorgias. This is only viable for customer seeding or very small archives where conversation history is intentionally out of scope. Crisp does not natively export conversations as CSV, so you lose thread structure, message authorship, attachments, and note continuity.(help.crisp.chat)

2. Custom API-to-API Script (Python/Node.js)

Write extraction scripts against the Crisp REST API, transform the data locally, and push it into Gorgias via their REST API.

When to use: You have a dedicated engineer with 2–4 weeks to build, test, and validate. Your dataset is small enough (under 50K conversations) that rate limits won't extend the migration to weeks.

Pros: Full control over transformation logic, timestamp preservation via sent_datetime, and edge case handling. No third-party dependency.

Cons: You must build retry logic, rate limit handling, pagination, attachment download/re-upload, deduplication, and idempotency yourself. Error recovery is entirely on you.

3. Third-Party Self-Serve Tools (e.g., Help Desk Migration)

Self-serve platforms like Help Desk Migration offer a UI-based mapping interface. You connect both accounts, map fields, run a demo migration, and then execute.(help-desk-migration.com)

When to use: You want a faster path and your data is relatively standard — contacts, conversations, messages without complex custom metadata or heavy attachment structures.

Pros: Faster setup, no code required, demo migration included for validation.

Cons: Less control over transformation logic. May not handle edge cases well (inline images, bot messages, custom data fields). Pricing scales with record count. Help Desk Migration documents caveats around inline images, large attachments, and comment-heavy tickets.

Briskport takes a different approach: it exports Crisp to PostgreSQL in real time with historical retrieval in beta, making it better as an extraction layer than a direct Crisp-to-Gorgias loader.(briskport.com)

4. Custom ETL Pipeline (Warehouse-Backed)

Land Crisp data into a warehouse or object store, normalize it there, then run a controlled load into Gorgias with workers, checkpoints, and replay support.

When to use: Enterprise compliance requirements, auditability needs, or when you need repeated rehearsal runs before cutover.

Pros: Best observability and repeatability. Cons: More infrastructure than most teams expect, and still constrained by target API write limits.

5. Middleware Platforms (Make, Zapier)

Trigger on new or updated objects and push them into Gorgias with no-code flows. Crisp has a verified Make app, and Zapier exposes Gorgias Create Ticket and Create Ticket Message actions.(make.com)

When to use: Very small deltas, temporary coexistence during cutover, or post-migration automations. Not a viable primary migration path for historical data.

Cons: Weak replay, weak idempotency, poor ergonomics for high-volume history, and ordering issues. Make's Gorgias connector is community-maintained rather than vendor-official.

Comparison Table

Factor Custom Script Self-Serve Tool Custom ETL Managed Service
Engineering effort 2–4 weeks Days 2–4 weeks Zero
Attachment handling Manual build Varies Manual build Included
Timestamp preservation Full control Depends on tool Full control Full control
Rate limit management Manual build Built-in Manual build Built-in
Edge case handling Manual Limited Manual Full
Cost Engineering salary Per-record pricing Infrastructure + salary Fixed project fee
Best for Small data, strong dev team Standard data, fast timeline Enterprise compliance Large/complex data, no dev bandwidth
Tip

Small business (under 10K conversations, under 5K contacts): A self-serve tool or careful custom script works. Enterprise (100K+ conversations, attachments, multiple operators): A managed service or a very well-tested custom ETL pipeline is the only safe bet.

Step-by-Step API Migration Architecture

Here is the technical workflow for an API-based migration, whether you build it yourself or want to understand what a managed service does under the hood.

Step 1: Pre-Migration Audit and Configuration Freeze

Before touching an API key, audit your Crisp workspace. Count total contacts, conversations, messages, and attachments. Identify spam, old closed sessions nobody searches, and inactive operators. Purge unnecessary data before migration to reduce API load and speed up the transfer.

Freeze your Crisp configuration during the migration window — no new segments, no operator changes, no new custom fields. On the Gorgias side, freeze or scope rules during the import window. Gorgias rules apply across all stores and channels, and API-channel tickets can still trigger some rule behavior like auto-tagging.(docs.gorgias.com)

Generate a Crisp plugin token via the Marketplace (development for testing, production for the real run). Generate a Gorgias API key from Settings → REST API. Plugin tokens give you higher daily quotas on Crisp.

Step 2: Extract from Crisp

Contacts/People Profiles: Paginate through GET /v1/website/{website_id}/people/profiles using page numbers. Extract email, name, segments, and custom data for each profile.

Conversations: Paginate through GET /v1/website/{website_id}/conversations page by page. Crisp uses classic page-number pagination for conversation lists. For each conversation, capture the session_id, state (resolved/unresolved/pending), assigned operator, and metadata.

Messages per Conversation: For each session_id, call GET /v1/website/{website_id}/conversation/{session_id}/messages. Messages include type (text, file, note, animation, etc.), content, timestamp, and sender identity (user or operator). Message paging uses timestamp_before.(docs.crisp.chat)

Attachments: Download file attachments from Crisp immediately during extraction. Crisp stores files on AWS S3, and URLs will eventually expire after your account is closed. For email-origin messages, use the original-message endpoint if you need source HTML and headers rather than a simplified body.

# Pseudo-code: Extract conversations from Crisp
import crisp_api
 
client = crisp_api.Crisp()
client.authenticate_tier("plugin", IDENTIFIER, KEY)
 
page = 1
all_conversations = []
 
while True:
    convos = client.website.list_conversations(WEBSITE_ID, page)
    if not convos:
        break
    all_conversations.extend(convos)
    page += 1
 
# For each conversation, fetch messages and files
for convo in all_conversations:
    session_id = convo["session_id"]
    messages = client.website.get_messages_in_conversation(
        WEBSITE_ID, session_id
    )
    convo["messages"] = messages

Step 3: Transform

This is where the data model translation happens:

  1. Map People Profiles → Gorgias Customers: Match on email. Build a lookup dict of crisp_people_id → gorgias_customer_id after creating or matching customers in Gorgias.
  2. Map Conversations → Tickets: Each Crisp conversation becomes one Gorgias ticket. Set channel to "chat" and via to "api". Map resolvedclosed, unresolved/pendingopen. Store session_id in external_id for idempotency and audit trail.
  3. Map Messages → Ticket Messages: For each message, set sent_datetime to the original Crisp message timestamp. Set from_agent based on the Crisp from field (operator = true, user = false).
  4. Map Segments → Tags: Crisp segments are pipe-separated strings on the people profile. Convert each segment to a {"name": "segment_value"} object in the Gorgias ticket tags array.
  5. Map Notes → Internal Notes: Crisp messages with type: "note" become Gorgias messages with channel: "internal-note".
  6. Generate Ticket Subjects: Crisp conversations don't have a "subject" field. Generate one from the first message or a truncated preview. Gorgias enforces a 998-character limit on ticket subjects.
Danger

If you omit sent_datetime on imported messages, Gorgias will attempt to send them to your customers. This is the single most common and destructive mistake in Gorgias migrations. Always set sent_datetime for every historical message. Also consider setting imported: true on messages to explicitly flag them as historical.(developers.gorgias.com)

Step 4: Load into Gorgias

Dependency order matters. A stable sequence is: create customer → create ticket with one seed message → append remaining messages in chronological order → upload and attach files → apply tags → assign agent if mapped.

Gorgias ticket creation requires a messages array and caps that array at 500 items, so a one-message seed plus append loop is safer than trying to cram a long Crisp session into a single create-ticket payload.(developers.gorgias.com)

Create Customers first:

# POST https://{domain}.gorgias.com/api/customers
payload = {
    "email": "customer@example.com",
    "name": "Jane Doe",
    "channels": [{"type": "email", "address": "customer@example.com"}]
}

Create Tickets with a seed message:

# POST https://{domain}.gorgias.com/api/tickets
payload = {
    "customer": {"email": "customer@example.com"},
    "channel": "chat",
    "via": "api",
    "status": "closed",
    "external_id": "crisp_session_abc123",
    "tags": [{"name": "migrated-from-crisp"}, {"name": "vip-segment"}],
    "messages": [{
        "channel": "chat",
        "via": "api",
        "from_agent": False,
        "sender": {"email": "customer@example.com"},
        "body_text": "Hi, I need help with my order.",
        "body_html": "<p>Hi, I need help with my order.</p>",
        "sent_datetime": "2025-06-15T14:22:00+00:00",
        "created_datetime": "2025-06-15T14:22:00+00:00"
    }]
}

Append subsequent messages:

# POST https://{domain}.gorgias.com/api/tickets/{ticket_id}/messages
message_payload = {
    "channel": "chat",
    "via": "api",
    "from_agent": True,
    "sender": {"email": "agent@yourstore.com"},
    "body_text": "Sure, let me look into that.",
    "sent_datetime": "2025-06-15T14:25:00+00:00"
}

Step 5: Handle Attachments

Crisp stores file attachments as URLs within the message content object. Crisp also exposes a separate conversation file-listing endpoint. To migrate attachments:

  1. Download the file from the Crisp URL
  2. Upload to Gorgias via POST /api/upload?type=attachment
  3. Embed the returned Gorgias URL in the message body_html

This is an N+2 API call per attachment (download, upload, create message), which makes attachment-heavy migrations significantly slower. Upload files before creating the message that references them.

Step 6: Rate Limit Handling

Your script must intercept 429 status codes on both sides. Here is a structural example:

import time
import requests
 
def gorgias_request(method, url, **kwargs):
    """Make a Gorgias API request with automatic retry on 429."""
    while True:
        response = requests.request(method, url, **kwargs)
        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 5))
            time.sleep(retry_after)
            continue
        response.raise_for_status()
        return response.json()

Log every source-to-target ID pair — customer, ticket, message, attachment, and operator. If the job dies halfway through, resume by external_id lookup and manifest state, not by blind re-creation.

Edge Cases That Break Migrations

These are the failure modes that cause silent data loss or agent pain. If your migration plan does not account for each of these, it is incomplete.

Inactive or Deleted Operators

Crisp conversations reference operator user IDs. If that operator no longer exists in Gorgias, the API will reject the payload when you try to assign a historical message to them. You have two choices: create a deactivated placeholder agent (set active: false after creation), or attribute those messages to a generic "Legacy Agent" sender. Gorgias documents that if an internal note sender is not an existing user, the note can appear as sent by Gorgias Bot.(developers.gorgias.com)

Pre-create matching users if authorship matters. Preserve the original Crisp operator identity in message metadata either way.

Duplicate Customer Records

Crisp identifies contacts primarily by email but also supports anonymous sessions with no email. Gorgias deduplicates on email and will return 409 conflicts for identifiers already in use.(developers.gorgias.com) Anonymous Crisp conversations either get dropped or assigned to a placeholder customer — decide this before migration, not during.

Crisp also often creates duplicate profiles if a user chats anonymously and later provides an email. Deduplicate these records based on email before pushing them to Gorgias.

Inline Images vs. File Attachments

Crisp has distinct message types: file (explicit attachment) and text with embedded image URLs. Both need different handling on the Gorgias side. Images pasted directly into Crisp chats are embedded as markdown or HTML <img> tags. Your script must parse the message body, extract the image URL, download the asset, upload it to Gorgias, and rewrite the HTML body with the new Gorgias-hosted URL. Text messages with inline image URLs render as broken links in Gorgias unless you download and re-host the images.

Gorgias Ticket Subject Length

Gorgias enforces a 998-character limit on ticket subjects. Crisp conversations don't have a "subject" field — you need to generate one, typically from the first message or a truncated preview.

Conversation Message Limits

Crisp caps conversations at roughly 10,000 messages. If you have conversations approaching this limit, they may need to be split into multiple Gorgias tickets.

Bot Messages and System Events

Crisp logs chatbot interactions, automated triggers, and system events as messages. Decide whether to import these as messages, internal notes, or skip them entirely. Importing bot-generated "typing" indicators as ticket messages clutters the Gorgias UI.

Payload Size Limits

Gorgias can reject oversized payloads with 413 errors, and message body_text or body_html is limited to 1 MB. Keep one-to-one message granularity and queue writes rather than batching.(developers.gorgias.com)

Rich Message Types

Crisp supports carousels, pickers, and field message types that have no Gorgias equivalent. These must be converted to plain text or HTML.

For more on diagnosing broken migrations, see Helpdesk Migration Failed? The Engineer's Rescue Guide.

Validation and Testing

Never run a migration without a validation plan. Here is the minimum.

Record Count Comparison

  • Total conversations in Crisp vs. total tickets in Gorgias
  • Total contacts in Crisp vs. total customers in Gorgias
  • Total messages per conversation vs. messages per ticket (sample 50 randomly)
  • Total attachments expected vs. attachments that resolve

Field-Level Validation

  • Timestamps match original Crisp values (check created_datetime on the Gorgias ticket and message)
  • Customer email matches across systems
  • Tags and segments mapped correctly
  • Attachments are accessible (URLs resolve)
  • Internal notes remain hidden from the customer view

Sampling Strategy

Pull 5% of migrated tickets at random. For each, manually compare the Gorgias ticket against the original Crisp conversation. Verify message order, sender attribution, and note visibility. Focus sampling on ugly records: long threads, email-origin conversations, deleted operators, and sessions with file attachments.

Agent UAT

Have 2–3 support agents review their own historical conversations in Gorgias. They will spot issues — wrong agent attribution, missing context, broken formatting — that automated checks miss.

Rollback Plan

Before migration, tag all imported records with migrated-from-crisp. If validation fails, you can bulk-delete by tag in Gorgias and re-run. Store the Crisp session_id in Gorgias's external_id field for traceability.

Post-Migration Tasks

Getting the data in is half the job. Here is what comes after.

  • Rebuild automations: Crisp triggers, bots, and routing rules do not migrate. Rebuild them as Gorgias Rules from scratch. Map each Crisp automation to its Gorgias equivalent before cutover. Recreate only the workflows that still make sense in a ticket-first model.(docs.gorgias.com)
  • Connect e-commerce stores: Wire up your Shopify, BigCommerce, or Magento store to Gorgias and test order actions end to end. This is usually the whole reason for the migration — do not save it for last.
  • Swap the widget: Replace the Crisp chat widget with the Gorgias chat widget on your storefront. Coordinate this with DNS changes if you use email forwarding.
  • Agent training: Gorgias's two-status model (Open/Closed) is simpler than most helpdesks, but the macro system, views, and rule engine require onboarding. Make sure agents understand that Crisp sessions are now tickets, that pending may live as a tag, and that imported notes may show mapped users.
  • Monitor for 2 weeks: Watch for duplicate customer creation, missing attachments, rules touching imported history, and any Crisp conversations that arrived during the cutover window.

For a structured approach to keeping support running during migration, see Zero-Downtime Helpdesk Migration. For the broader post-migration launch sequence, see the Helpdesk Migration Checklist.

What You'll Lose in the Move

Some data does not survive the platform boundary:

  • Crisp chatbot flow state: Bot conversation trees, triggers, and automation scenarios must be rebuilt in Gorgias's rule engine from scratch.
  • Visitor browsing data: Crisp tracks page views and visitor activity. Gorgias does not store pre-conversation browsing behavior.
  • Custom Crisp plugins and widgets: Crisp Marketplace plugins have no Gorgias equivalent. Evaluate replacements from the Gorgias app store.
  • Conversation threading within a single session: If a Crisp conversation used threads (splitting topics within one session), Gorgias has no equivalent. You will need to flatten or split.
  • Rich message types: Crisp carousels, pickers, and field message types must be converted to plain text or HTML.
  • Crisp people notepad: No first-class equivalent in Gorgias's customer create API. Store it in customer.data or emit a synthetic internal note on the first migrated ticket.

Migration Script Reference (Python)

For teams building in-house, here is the structural skeleton. This is not production-ready code — it is an architecture reference.

import time
import requests
from crisp_api import Crisp
 
# --- Config ---
CRISP_WEBSITE_ID = "your-website-id"
GORGIAS_DOMAIN = "yourstore.gorgias.com"
GORGIAS_API_KEY = "your-api-key"
GORGIAS_EMAIL = "admin@yourstore.com"
 
crisp = Crisp()
crisp.authenticate_tier("plugin", "<identifier>", "<key>")
 
def gorgias_post(endpoint, payload):
    """POST to Gorgias with retry on 429."""
    url = f"https://{GORGIAS_DOMAIN}/api/{endpoint}"
    auth = (GORGIAS_EMAIL, GORGIAS_API_KEY)
    while True:
        resp = requests.post(url, json=payload, auth=auth)
        if resp.status_code == 429:
            wait = int(resp.headers.get("Retry-After", 5))
            time.sleep(wait)
            continue
        resp.raise_for_status()
        return resp.json()
 
# --- Phase 1: Extract & Create Customers ---
page = 1
customer_map = {}  # crisp_email -> gorgias_customer_id
while True:
    profiles = crisp.website.list_people_profiles(CRISP_WEBSITE_ID, page)
    if not profiles:
        break
    for profile in profiles:
        email = profile.get("email")
        if not email:
            continue
        gorgias_customer = gorgias_post("customers", {
            "email": email,
            "name": profile.get("person", {}).get("nickname", ""),
        })
        customer_map[email] = gorgias_customer["id"]
    page += 1
 
# --- Phase 2: Extract Conversations & Load as Tickets ---
page = 1
while True:
    conversations = crisp.website.list_conversations(CRISP_WEBSITE_ID, page)
    if not conversations:
        break
    for convo in conversations:
        session_id = convo["session_id"]
        meta = crisp.website.get_conversation_metas(
            CRISP_WEBSITE_ID, session_id
        )
        messages = crisp.website.get_messages_in_conversation(
            CRISP_WEBSITE_ID, session_id
        )
        # Transform messages
        gorgias_messages = []
        for msg in messages:
            gorgias_msg = {
                "channel": "internal-note" if msg["type"] == "note" else "chat",
                "via": "api",
                "from_agent": msg["from"] == "operator",
                "body_text": msg.get("content", ""),
                "sent_datetime": msg["timestamp"],  # CRITICAL
            }
            if msg["from"] == "operator":
                gorgias_msg["sender"] = {
                    "email": meta.get("assigned_operator_email", "bot@yourstore.com")
                }
            else:
                gorgias_msg["sender"] = {
                    "email": meta.get("email", "unknown@example.com")
                }
            gorgias_messages.append(gorgias_msg)
 
        # Create ticket with first message, append rest
        if gorgias_messages:
            ticket = gorgias_post("tickets", {
                "customer": {"email": meta.get("email", "unknown@example.com")},
                "channel": "chat",
                "via": "api",
                "status": "closed" if convo.get("state") == "resolved" else "open",
                "external_id": session_id,
                "tags": [{"name": s} for s in meta.get("segments", [])],
                "messages": [gorgias_messages[0]],
            })
            for msg in gorgias_messages[1:]:
                gorgias_post(f"tickets/{ticket['id']}/messages", msg)
    page += 1
 
print("Migration complete. Run validation checks.")
Info

This script is a structural reference. Production code must add: error logging per record, idempotency checks (skip if external_id exists), attachment download/upload, and a progress checkpoint system so you can resume after failures.

Best Practices Checklist

  • Back up Crisp data to a local JSON dump before starting any writes to Gorgias
  • Run a test migration with 100–1,000 conversations first — validate every field before scaling
  • Set sent_datetime on every imported message without exception
  • Store session_id in external_id on Gorgias tickets for audit trail and idempotency
  • Tag all imported records with migrated-from-crisp for easy identification and rollback
  • Monitor Gorgias rate limit headers — read the Retry-After value, do not guess
  • Handle anonymous contacts — decide skip vs. placeholder before migration, not during
  • Coordinate widget swap with your development team — the delta between bulk migration and widget cutover is where data gets lost
  • Freeze Crisp configuration during migration — no new segments, no operator changes
  • Freeze or scope Gorgias rules during import to prevent auto-actions on historical data
  • Rebuild Gorgias rules and macros manually — they do not transfer from Crisp
  • Log every source-to-target ID pair for resumability and debugging

When to Use a Managed Migration Service

Build in-house when your dataset is small, your conversations are text-only, and you have an engineer who can commit 2–4 weeks without derailing your product roadmap. Outsource when:

  • You have 100K+ conversations and rate limit math means your script will run for weeks
  • Your conversations contain thousands of file attachments requiring download/re-upload pipelines
  • You need zero data loss and cannot afford to debug edge cases in production
  • Your engineering team is shipping product and cannot absorb a multi-week infrastructure project
  • You need delta migration — a point-in-time sync of conversations that arrived between the initial migration run and the final widget cutover

The hidden cost of DIY is not the script — it is the debugging. Rate limit failures at 3 AM, orphaned messages from a crashed script, duplicate customers from a retry loop without idempotency. These edge cases consume far more engineering time than the initial build.

How ClonePartner Handles Crisp to Gorgias Migrations

ClonePartner runs engineer-led, zero-downtime helpdesk migrations. For Crisp to Gorgias, here is what that means in practice:

  • Full API extraction that bypasses Crisp's 200K contact CSV export limit by pulling directly from the REST API with managed quotas.
  • Structural transformation from Crisp's chat-session model to Gorgias's ticket-thread model, preserving original timestamps, agent attribution, and attachment links.
  • Rate limit management with built-in exponential backoff against both Crisp and Gorgias 429 responses — no data is dropped.
  • Delta migration at cutover: we run a point-in-time delta sync to capture conversations that arrived between the initial bulk migration and the widget swap. This closes the gap without the complexity of a real-time sync pipeline.
  • Validation and QA with record-count comparison, field-level sampling, and agent-facing UAT before signoff.

The typical Crisp-to-Gorgias migration completes in days, not weeks. Your engineering team stays focused on product.

Frequently Asked Questions

Can I export Crisp conversations as CSV?
No. Crisp only supports CSV export for contact profiles, capped at 200,000. Conversation and message data must be extracted via the Crisp REST API or a third-party tool that uses it.
What are the Gorgias API rate limits for data migration?
Gorgias uses a leaky bucket algorithm. OAuth2 apps get 80 requests per 20-second window; API key integrations get 40 requests per 20 seconds. Exceeding the limit returns a 429 error with a Retry-After header you must respect.
Will Gorgias resend imported messages to customers?
Yes, if you don't set the sent_datetime field. Any message created via the Gorgias API without sent_datetime is treated as new and Gorgias will attempt to deliver it. Always set sent_datetime for historical imports.
How do Crisp conversations map to Gorgias tickets?
Each Crisp conversation (identified by session_id) typically becomes one Gorgias ticket. Messages become ticket messages, segments map to tags, and private notes become internal-note channel messages. Crisp's three-state model (pending/unresolved/resolved) must be flattened to Gorgias's two states (open/closed).
Can Make or Zapier migrate all historical Crisp chats to Gorgias?
Not well. Both platforms expose useful connectors, but they lack the replay logic, idempotency, and throughput needed for high-volume historical backfills. They are better suited for small deltas or post-migration automations.

More from our Blog

Why Top E-commerce Teams are Migrating to Gorgias
Gorgias

Why Top E-commerce Teams are Migrating to Gorgias

Fast-growing e-commerce brands in the US and Europe are migrating to Gorgias to centralize omnichannel support, automate high-volume customer queries, and deliver faster resolutions. With e-commerce-trained AI, deep store integrations, and revenue-driven support features, Gorgias helps teams scale without increasing headcount.

Raaj Raaj · · 7 min read
Mastering Gorgias: The 2026 Technical Guide to Turning Customer Support into a Profit Engine
Gorgias

Mastering Gorgias: The 2026 Technical Guide to Turning Customer Support into a Profit Engine

This blog is a comprehensive 2026 technical guide to the Gorgias helpdesk , detailing how e-commerce brands can transform customer support into a profit engine. It provides an expert-driven walkthrough of the complete Gorgias setup , advanced automations , and AI features . The guide also emphasizes the critical role of expert helpdesk migration to preserve historical data and maximize the platform's potential .

Raaj Raaj · · 9 min read
Zero-Downtime Helpdesk Migration: How to Keep Support Running During the Move
Help Desk

Zero-Downtime Helpdesk Migration: How to Keep Support Running During the Move

This guide details the 3-stage technical process for a zero-downtime helpdesk migration. Learn how to use an initial bulk data transfer, a continuous delta migration (Change Data Capture), and a seamless final cutover to move platforms without any service interruption. Discover how an engineer-led approach can guarantee a 100% accurate, 50x faster migration.

Raaj Raaj · · 6 min read