---
title: "HubSpot Service Hub to Crisp Migration: A Technical Guide"
slug: hubspot-service-hub-to-crisp-migration-a-technical-guide
date: 2026-07-22
author: Raaj
categories: [Migration Guide, Hubspot Service Hub]
excerpt: "A technical guide to migrating from HubSpot Service Hub to Crisp — covering data model mapping, API extraction, rate limits, and step-by-step process."
tldr: HubSpot Service Hub to Crisp is a data-model translation from CRM-centric tickets and fragmented engagements to Crisp's conversation-first model. No native import path exists — you need a custom API script or managed service.
canonical: https://clonepartner.com/blog/hubspot-service-hub-to-crisp-migration-a-technical-guide/
---

# HubSpot Service Hub to Crisp Migration: A Technical Guide


# HubSpot Service Hub to Crisp Migration: A Technical Guide

> [!NOTE]
> **TL;DR — HubSpot Service Hub to Crisp Migration**
>
> A HubSpot Service Hub to Crisp migration is a **data-model translation** from a CRM-centric, ticket-and-engagement architecture to a conversation-first messaging platform. HubSpot tickets, pipelines, engagement objects (emails, notes, calls), contacts, companies, and custom objects do not map 1:1 to Crisp's flatter model of conversations, contacts, and key-value custom data. The biggest structural challenge: HubSpot fragments conversation content across 3–5 separate API endpoints (Tickets, Emails, Notes, Calls, Associations), while Crisp treats each conversation as a single threaded unit. Crisp has no native HubSpot import tool — their open-source `crisp-import-conversations` script supports Zendesk, Gorgias, Help Scout, Tidio, GrooveHQ, and WHMCS, but not HubSpot. You need a custom adapter or a managed migration service. Realistic timeline: **1–3 weeks** for teams under 50K tickets (roughly 40% extraction, 25% transformation, 20% loading, 15% validation); 3–6 weeks for larger datasets with complex custom objects and attachment-heavy histories.

## Why Teams Migrate from HubSpot Service Hub to Crisp

A HubSpot Service Hub to Crisp migration moves your support operation from a full CRM-integrated service layer to a lightweight, conversation-first messaging platform. This is a simplification move — you're trading depth for speed, and ecosystem complexity for operational clarity.

Teams make this switch for specific reasons:

- **Cost:** <cite index="49-7">Crisp offers four core plans: Free, Mini (€45/mo), Essentials (€95/mo), and Plus (€295/mo) — all billed per workspace per month.</cite> <cite index="49-8">Each plan includes a fixed number of agents, and only the highest plan allows adding extra seats (€10/agent/mo).</cite> Compare this to HubSpot Service Hub Professional at $100/seat/month.
- **Simplicity:** <cite index="61-4,61-5">Crisp's built-in CRM tracks contacts with conversation history, custom attributes, tags, and segments. It's not a replacement for HubSpot, Pipedrive, or Salesforce — it's a lightweight contact tracker that provides context during conversations.</cite> Teams that don't need HubSpot's full CRM gravity find it faster to resolve conversations in Crisp.
- **Multichannel unification:** <cite index="62-2,62-3">Crisp's all-in-one multichannel platform allows companies to centralize more than 10 channels in one inbox. WhatsApp, Messenger, Emails, Live chat, Phone calls, or even Viber or Line are available from one unified inbox.</cite>
- **Hybrid setups and agency use cases:** <cite index="64-4">The tradeoff is ecosystem dependency: Service Hub works best as part of the full HubSpot suite, and using it standalone feels incomplete compared to Crisp's self-contained platform.</cite> Teams that don't use HubSpot CRM, Marketing Hub, or Sales Hub alongside Service Hub see diminishing returns. For these teams, the cleanest architecture is often Crisp for the support inbox while retaining HubSpot as the CRM of record — Crisp's HubSpot integration supports two-way contact sync, can surface HubSpot deals and list memberships in the Crisp sidebar, and can report Crisp conversations back into HubSpot activity. ([help.crisp.chat](https://help.crisp.chat/en/article/how-to-connect-hubspot-with-crisp-1klykju/))

### Cost Comparison by Team Size

| Team Size | HubSpot Service Hub Professional | Crisp Essentials | Crisp Plus | Annual Savings (Essentials) |
|---|---|---|---|---|
| 4 agents | $400/mo ($4,800/yr) | €95/mo (€1,140/yr) | €295/mo (€3,540/yr) | ~€3,500/yr |
| 10 agents | $1,000/mo ($12,000/yr) | €95/mo (€1,140/yr) | €295/mo (€3,540/yr) | ~€10,500/yr |
| 25 agents | $2,500/mo ($30,000/yr) | N/A (Essentials caps agents) | €295 + €150/mo extra seats (€5,340/yr) | ~€24,000/yr |
| 50 agents | $5,000/mo ($60,000/yr) | N/A | €295 + €400/mo extra seats (€8,340/yr) | ~€50,000/yr |

Note: Crisp Essentials and Plus include a fixed number of seats (4 and 10 respectively). Only Plus allows adding extra seats at €10/agent/mo. Currency conversion fluctuates; figures use approximate USD/EUR parity for comparison.

### Core Architecture Differences

| Dimension | HubSpot Service Hub | Crisp |
|---|---|---|
| **Data model** | CRM-centric: Tickets, Contacts, Companies, Deals, Engagements, Custom Objects — all linked via Associations API | Conversation-first: Conversations, Contacts, Segments — linked via session IDs |
| **Conversation storage** | Fragmented — emails, notes, calls are separate engagement objects at different API endpoints | Unified — all messages live inside a single conversation thread |
| **Custom fields** | Structured custom properties on any object; Custom Objects on Enterprise | Key-value custom data at conversation level and contact level |
| **Pipelines** | Multi-pipeline ticket system with stages, SLAs, automations | No native pipeline equivalent; conversations have statuses (open, pending, resolved) |
| **Ticketing** | Core feature on all paid tiers | Only available on Plus plan (€295/mo) |
| **Automation** | Workflow engine with branching, delays, custom code actions | Chatbot builder (visual, no-code) + Hugo AI for routing and escalation |
| **Knowledge base** | Available on Professional+ | Available on Essentials+ |
| **Data residency** | US-hosted (AWS), EU data center available on Enterprise | France-based (Crisp is a French company; data stored in EU by default) |
| **Search indexing** | Full-text search across all objects | Full-text search across conversations; imported conversations are indexed and searchable by content, contact email, and metadata |
| **Real-time API** | Webhooks only | RTM (Real-Time Messaging) API via WebSocket + webhooks for event-driven sync |

## Migration Approaches: All Viable Methods

### 1. Native CSV Export/Import

**How it works:** Export contacts, companies, and tickets as CSV from HubSpot's UI, then import contacts into Crisp via Contacts → Actions → Import Contact Profiles.

**When to use it:** Small teams (<1,000 contacts) with no conversation history requirements.

**Pros:** Zero engineering required. Fast for contacts only.

**Cons:** <cite index="28-3">Conversation data cannot be exported as a native CSV from the Crisp dashboard at the moment.</cite> More critically, HubSpot's CSV ticket exports don't include full engagement bodies (email content, note text). <cite index="15-10,15-11,15-12,15-13">HubSpot Service Hub organizes support around tickets. The actual conversation content doesn't live on the ticket. Emails, notes, calls, and meetings are separate engagement objects stored at their own API endpoints (/crm/v3/objects/emails, /crm/v3/objects/notes, /crm/v3/objects/calls, etc.) and linked to tickets through HubSpot's associations API.</cite> HubSpot also limits CSV exports to 30 per rolling 24 hours, one at a time. ([developers.hubspot.com](https://developers.hubspot.com/docs/api-reference/latest/crm/exports/guide?utm_source=openai))

**Scalability:** Small data only. No conversation migration.

**Complexity:** Low

### 2. API-Based Migration (HubSpot APIs → Crisp APIs)

**How it works:** Write a custom script that extracts tickets, engagements, contacts, and companies from HubSpot's REST API, transforms them into Crisp's conversation format, and loads them via Crisp's REST API.

**When to use it:** Any migration that needs conversation history preserved. Required for >1,000 tickets.

**Pros:** Full fidelity. Preserves timestamps, message threading, and contact associations. Can be automated and repeated.

**Cons:** Requires engineering time. HubSpot's fragmented engagement model means 3–5 API calls per ticket to reconstruct a single conversation. Rate limits on both sides require careful throttling.

**Rate limits:** <cite index="41-2,41-3">Professional accounts get 650,000 requests per day with a burst limit of 190 requests per 10 seconds. Enterprise accounts get 1 million requests per day.</cite> On the Crisp side, <cite index="2-1">the Crisp API has a multi-level rate-limit (based on client IP and user identifier, if authenticated).</cite> <cite index="2-5,2-6">Plugin tokens are not subject to API Global and API Route rate-limits.</cite> However, <cite index="2-7,2-8">those tokens are subject to a special rate limiter named Plugin Quota — a quota system, reset daily, that lets a plugin perform a certain number of requests until it gets limited.</cite>

**Scalability:** Enterprise-grade if properly architected.

**Complexity:** High

### 3. Crisp's Open-Source Import Script

**How it works:** Crisp maintains an official open-source tool — [`crisp-import-conversations`](https://github.com/crisp-im/crisp-import-conversations) — that accepts JSON/JSONL/CSV/XML files and imports conversations into Crisp.

<cite index="30-5,30-6,30-7,30-8,30-9">You can use this import script with any of Crisp plans: Free, Mini, Essentials or Plus. Limits: Free has no message of type note and max 1 extra participant. Mini allows max 3 extra participants. Essentials and Plus allow max 10 extra participants.</cite>

**The catch:** Supported adapters are `gorgias`, `groovehq`, `helpscout`, `tidio`, `whmcs`, and `zendesk`. There is **no HubSpot adapter**. You need to write a custom adapter or pre-transform your HubSpot data into Crisp's expected JSON format.

**When to use it:** Mid-size migrations where you can invest time writing a HubSpot-to-Crisp adapter.

**Pros:** Handles conversation creation, message ordering, participant assignment, and resume-on-failure.

**Cons:** No built-in HubSpot support. You still need to extract and transform HubSpot data yourself.

**Complexity:** Medium (if you write an adapter)

### 4. Middleware / Integration Platforms (Zapier, Make, n8n)

**How it works:** Use a no-code platform to connect HubSpot triggers to Crisp actions. <cite index="31-1">Crisp offers import options for contacts: CSV files, APIs, JavaScript SDK, native integrations and tools such as Zapier, n8n or Make.</cite>

**When to use it:** Ongoing sync of new contacts or simple data during a phased rollout. Not suitable for bulk historical migration.

**Pros:** No code. Quick setup for live sync.

**Cons:** Cannot migrate historical conversations. Zapier doesn't expose HubSpot engagement bodies. Per-task pricing makes bulk migration prohibitively expensive (10K tickets = 50K+ tasks at $0.01–0.03/task = $500–1,500 in Zapier costs alone). No error recovery or relationship preservation.

**Complexity:** Low (but very limited scope)

### 5. Custom ETL Pipeline

**How it works:** Build a dedicated Extract-Transform-Load pipeline with a staging database (PostgreSQL, SQLite) between HubSpot extraction and Crisp loading. For enterprise environments, tools like Airbyte or Fivetran can handle the extraction into a data warehouse, with dbt for transformation and reverse-ETL into Crisp.

**When to use it:** Enterprise migrations with >100K tickets, complex custom objects, or strict compliance requirements.

**Pros:** Maximum control. Supports deduplication, data enrichment, audit logging, incremental loads, and rollback. Highly repeatable.

**Cons:** Highest engineering investment. Requires expertise in both platforms' APIs.

**Complexity:** High

### 6. Third-Party Migration Tools/Services

**How it works:** A vendor maps HubSpot exports or API data into its own staging model and loads Crisp for you. The market is asymmetric here: HubSpot's marketplace has migration apps for moving data **into** HubSpot, while Crisp's conversation importer lists adapters for Zendesk, Gorgias, Help Scout, and others — but not HubSpot. On this route, "tool" usually means service plus custom transformation. ([ecosystem.hubspot.com](https://ecosystem.hubspot.com/marketplace/apps/data-migration?eco_tiers=HUBSPOT_FREE&utm_source=openai))

**When to use it:** Low engineering bandwidth and a hard deadline.

**Pros:** Faster startup, vendor-owned retries and validation.

**Cons:** Less transparency, weaker control over custom object flattening. Quality varies by vendor. Often fail on edge cases, attachments, or custom HubSpot associations.

**Complexity:** Medium

### 7. Managed Migration Service

**How it works:** A specialist migration partner handles the entire process — data audit, field mapping, extraction, transformation, loading, validation, and post-migration QA.

**When to use it:** When you can't afford data loss, don't have API engineering bandwidth, or need to migrate quickly with zero downtime.

**Complexity:** Low (for your team)

### Approach Comparison Table

| Method | Conversation History | Contacts | Custom Fields | Complexity | Best For |
|---|---|---|---|---|---|
| CSV Export/Import | ❌ | ✅ | Partial | Low | Contact-only moves |
| API-Based Script | ✅ | ✅ | ✅ | High | Full migration, dev team available |
| Crisp Import Script | ✅ (needs adapter) | ❌ (separate) | Partial | Medium | Mid-size, some dev capacity |
| Zapier/Make/n8n | ❌ | ✅ | Partial | Low | Ongoing sync only |
| Custom ETL Pipeline | ✅ | ✅ | ✅ | High | Enterprise, compliance-heavy |
| Third-Party Tools | Varies | ✅ | Varies | Medium | Hard deadline, no dev team |
| Managed Service | ✅ | ✅ | ✅ | Low (your side) | No eng bandwidth, fast turnaround |

### Recommendations by Scenario

- **Small business, <1K contacts, no ticket history needed:** CSV export/import. Start fresh with conversations.
- **Startup, <10K tickets, has a developer:** Crisp import script with a custom HubSpot adapter.
- **Mid-market, 10K–100K tickets, limited eng time:** Managed migration service or API-based migration.
- **Enterprise, >100K tickets, compliance requirements:** Custom ETL pipeline or managed service.
- **Ongoing sync (not migration):** Zapier/Make for contacts; API script for conversations. Post-migration, consider Crisp's RTM (Real-Time Messaging) WebSocket API for event-driven sync between platforms.
- **Hybrid setup (keeping HubSpot CRM):** Backfill once via API, then use the native Crisp-HubSpot integration for ongoing sync. ([help.crisp.chat](https://help.crisp.chat/en/article/how-to-connect-hubspot-with-crisp-1klykju/))

## GDPR and Data Residency Considerations

Moving support data between HubSpot and Crisp involves a cross-platform data transfer that has compliance implications:

- **HubSpot data residency:** HubSpot hosts data on AWS, primarily in the US. EU data hosting is available for Enterprise accounts via HubSpot's data residency feature (limited to specific data types).
- **Crisp data residency:** Crisp is a French company (Crisp IM SAS) and stores data in the EU by default. This simplifies GDPR compliance for EU-based teams.
- **Transfer considerations:** If you are moving data from a US-hosted HubSpot instance to Crisp's EU infrastructure, you are technically performing a data repatriation — generally GDPR-favorable. However, the migration process itself (scripts running on your infrastructure, staging databases, intermediate file storage) creates additional processing locations that should be documented in your Records of Processing Activities (ROPA).
- **Data minimization:** GDPR's data minimization principle supports pruning old, inactive contacts and closed tickets before migration rather than migrating everything. This aligns with the technical recommendation to filter out contacts with no activity in 12+ months.
- **Right to erasure:** Ensure that contacts who have exercised their right to erasure in HubSpot are excluded from the migration dataset. Cross-reference HubSpot's GDPR deletion logs before extraction.
- **DPA requirements:** Verify that your Crisp plan includes a Data Processing Agreement (DPA). Crisp provides a DPA on request for paid plans.

## When to Use a Managed Migration Service

DIY migrations break at predictable points:

- **Engagement reconstruction:** HubSpot stores emails, notes, and calls as separate objects across different API endpoints. Forgetting to fetch even one engagement type means permanent data loss in Crisp.
- **Rate limit coordination:** You're managing throttling on two APIs simultaneously, with different limiting models. HubSpot uses burst + daily limits; Crisp uses daily quotas per plugin.
- **Relationship flattening:** HubSpot's Associations API links tickets to contacts to companies in a multi-level relational graph. These relationships need to be rebuilt in Crisp through conversation metadata and contact custom data — a fundamentally different structure.
- **Attachment handling:** File attachments on HubSpot engagements require separate downloads from authenticated URLs, re-hosting, and URL replacement in Crisp messages. Crisp's file upload API accepts multipart form data with a maximum file size of 20 MB per file. Files exceeding this must be hosted externally and linked.
- **HTML sanitization:** HubSpot emails often contain complex HTML, inline CSS, and tracking pixels. Crisp's message renderer is simpler and will break on unsanitized content.
- **Hidden engineering cost:** What looks like a 2-day script becomes a 3-week project once you handle edge cases, retries, deduplication, and validation.

### Typical Time Distribution for a 25K-Ticket Migration

| Phase | Estimated Duration | % of Total |
|---|---|---|
| Data audit and field mapping | 2–3 days | 15% |
| Extraction scripting and testing | 3–5 days | 25% |
| Transformation logic (engagement → conversation) | 3–4 days | 20% |
| Loading and rate limit management | 2–3 days | 15% |
| Validation and QA | 2–3 days | 15% |
| Edge case handling, retries, delta sync | 1–2 days | 10% |
| **Total** | **13–20 working days** | **100%** |

These estimates assume one experienced engineer working full-time. Teams without HubSpot or Crisp API experience should add 30–50% buffer.

## Pre-Migration Planning

### Data Audit Checklist

Before touching any API, inventory what you have and what you actually need in Crisp:

| HubSpot Object | Audit Question | Action |
|---|---|---|
| Contacts | How many? Active vs. dormant? | Filter out contacts with no activity in 12+ months |
| Companies | Are they associated to contacts? | Decide if company data maps to Crisp contact custom data |
| Tickets | How many per pipeline? Status distribution? | Define which pipelines and statuses to migrate |
| Engagements (emails) | Average emails per ticket? | Calculate total API calls needed |
| Engagements (notes) | Internal notes vs. customer-facing? | Map to Crisp private notes (requires Essentials+ plan) |
| Custom Objects | What types? How many records? | Assess whether key-value custom data in Crisp is sufficient |
| Attachments | Total size? File types? | Plan for re-hosting; Crisp file API accepts max 20 MB per file |
| Knowledge Base | Articles count? Locales? | Migrate separately — Crisp Knowledge Base is a distinct import |
| Workflows | How many? Cross-object dependencies? | Cannot be migrated — must be rebuilt in Crisp |
| Conversations Inbox | Using HubSpot live chat alongside tickets? | Requires separate extraction via HubSpot Conversations API |
| GDPR deletion log | Any contacts with erasure requests? | Exclude from migration dataset |

If you want a prep worksheet before you design the Crisp target, start with our [HubSpot Service Hub Migration Checklist](https://clonepartner.com/blog/blog/hubspot-service-hub-migration-checklist/).

### Define Migration Scope

- **Time window:** Decide how far back to migrate. Tickets older than 2 years rarely get referenced — consider archiving them to a data warehouse and only migrating recent history.
- **Status filter:** Migrate only closed + open tickets, or include deleted?
- **Pipeline selection:** If you have test or internal pipelines, exclude them.
- **Pruning:** Do you need 6-year-old closed tickets? Archiving old records keeps Crisp clean and reduces migration time and API costs. This also aligns with GDPR data minimization requirements.

### Migration Strategy

- **Big bang:** Migrate everything in one shot, cut over on a weekend. Best for <50K tickets.
- **Phased:** Migrate by pipeline, team, or region. Reduces risk but requires running both platforms temporarily.
- **Incremental:** Migrate historical data first, then sync new tickets daily until cutover. Best for >100K tickets where downtime is unacceptable.

### Risk Mitigation

- Never delete HubSpot data until Crisp has been running successfully in production for at least 30 days.
- Export a full HubSpot backup to a secure S3 bucket before starting.
- Document the Crisp workspace ID and all imported session IDs for potential bulk deletion if rollback is needed.
- Define a rollback owner and a validation sign-off process before touching production.

## Data Model and Object Mapping

This is the most critical technical hurdle. You are forcing a relational peg into a flat hole.

### Object-Level Mapping

| HubSpot Service Hub | Crisp Equivalent | Notes |
|---|---|---|
| Contact | Contact (Profile) | 1:1 mapping. Email is the primary key in both. |
| Company | Contact custom data (`company_name`, `company_domain`) | Crisp has no standalone Company object. Flatten to contact-level attributes. |
| Ticket | Conversation | Each ticket becomes a conversation. Status maps to conversation state (pending/resolved/unresolved). |
| Email (engagement) | Message (type: text, from: user/operator) | Reconstruct as messages inside the conversation. Preserve timestamps. |
| Note (engagement) | Message (type: note, from: operator) | Private notes. Requires Essentials or Plus plan. |
| Call (engagement) | Message (type: text or note) with call metadata | No native call object in Crisp. Log as a note with duration/outcome. |
| Deal | No equivalent | Crisp has no deal/opportunity object. Keep in HubSpot or store key fields as contact custom data. |
| Custom Object | Contact or conversation custom data (key-value) | No structured custom objects in Crisp. Flatten to key-value pairs. |
| Pipeline | Conversation segments/tags | Use Crisp segments and tags to replicate pipeline categorization. |
| Pipeline Stage | Conversation state + tags | Map stages to resolved/pending/unresolved + descriptive tags. |
| Workflow | No equivalent (rebuild manually) | Rebuild using Crisp chatbot builder, Hugo AI, or webhook triggers. |
| Knowledge Base Article | Knowledge Base Article | Separate import. Crisp KB supports locales and categories. |

### Field-Level Mapping

<cite index="21-3,21-4,21-5,21-6,21-7">Crisp uses two main levels of custom data: conversation/session data and contact data. Conversation data is stored at the conversation level — useful when the information only applies to the current exchange. Contact data is stored on the contact profile — useful for information that should remain attached to the person over time, such as user_id, plan, company_size, or lifetime_value.</cite>

| HubSpot Field | HubSpot API Property | Crisp Field | Crisp API Path | Notes |
|---|---|---|---|---|
| Contact Email | `email` | Contact Email | `people.email` | Primary key for deduplication |
| Contact First Name | `firstname` | Contact Nickname | `people.nickname` | Concatenate first + last |
| Contact Phone | `phone` | Contact Phone | `people.phone` | Normalize to E.164 format before load |
| Company Name | `company` (via association) | Contact Custom Data | `people.data.company_name` | Flattened — no separate Company object |
| Ticket Subject | `subject` | Conversation Subject | `conversation.subject` | Can also be inserted as the first message |
| Ticket Status | `hs_pipeline_stage` | Conversation State | `conversation.state` | Map: closed → resolved, open → unresolved |
| Ticket Priority | `hs_ticket_priority` | Conversation Tag | Tag: `priority-high` | No native priority field in Crisp |
| Ticket Pipeline | `hs_pipeline` | Conversation Segment | Segment rule | Use segment filters for operator workflow |
| Email Body | `hs_email_html` | Message Content | `message.content` | Sanitize HTML; strip tracking pixels and inline CSS |
| Note Body | `hs_note_body` | Note Content | `message.content` (type: note) | Requires Essentials+ |
| Ticket Owner | Owner ID | Conversation Operator | Operator ID | ID mapping required |
| Custom Property | Custom property name | Custom Data | `people.data.{key}` or `conversation.meta.data.{key}` | Key-value only; max key length 100 chars |
| HubSpot Object ID | `hs_object_id` | Custom Data | `data.hubspot_contact_id` | Keep as canonical foreign key for validation and rollback |
| Country | `country` | Geolocation | `person.geolocation.country` | Use ISO 3166-1 alpha-2 country codes, not free text |

### Handling Relationships and Dependencies

HubSpot's Associations API creates multi-level relationships: Company → Contact → Ticket → Engagement. In Crisp, these relationships are flatter:

- **Contact → Conversation:** Automatic — Crisp links conversations to contacts via email address.
- **Company → Contact:** Flatten company data into contact custom data fields.
- **Ticket → Engagement:** Engagements become messages within the conversation.
- **Deal → Contact:** In hybrid setups, keep deals in HubSpot and surface them via the Crisp sidebar integration. If needed, store deal info as contact custom data.

One critical constraint: HubSpot allows a ticket to be associated with multiple contacts or companies. Crisp conversations are tied to a single profile. You must define a primary contact for each ticket and drop secondary associations.

> [!WARNING]
> **Custom Objects Warning:** HubSpot Custom Objects (Enterprise-only) have no Crisp equivalent. You must either flatten them into key-value custom data on contacts/conversations or accept that this data won't migrate. Do not force HubSpot deals, custom objects, and deep associations into fake Crisp structures. Keep the system of record where it belongs, and migrate only the support context your agents actually need.

## Migration Architecture

### Data Flow: Extract → Transform → Load

```
┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  HubSpot APIs   │────▶│  Transform Layer │────▶│   Crisp APIs    │
│                 │     │  (staging DB)    │     │                 │
│ • Contacts API  │     │ • Deduplicate    │     │ • People API    │
│ • Tickets API   │     │ • Map fields     │     │ • Conversations │
│ • Emails API    │     │ • Merge engages  │     │ • Messages API  │
│ • Notes API     │     │ • Sanitize HTML  │     │ • Custom Data   │
│ • Calls API     │     │ • Re-host files  │     │ • File Upload   │
│ • Associations  │     │ • Validate       │     │                 │
│ • Files API     │     │ • Normalize      │     │                 │
└─────────────────┘     └──────────────────┘     └─────────────────┘
```

### HubSpot API Endpoints

- **Contacts:** `GET /crm/v3/objects/contacts` — paginated, up to 100 per page
- **Tickets:** `GET /crm/v3/objects/tickets` — specify properties in query params
- **Associations:** `GET /crm/v4/objects/tickets/{ticketId}/associations/emails`
- **Emails:** `GET /crm/v3/objects/emails/{emailId}?properties=hs_email_html,hs_email_text,hs_email_subject`
- **Notes:** `GET /crm/v3/objects/notes/{noteId}?properties=hs_note_body,hs_timestamp`
- **Conversations Inbox:** Separate endpoints via the Conversations API if your team uses HubSpot live chat alongside tickets. <cite index="14-14,14-15">Inbox data can be exported using the Conversations API. For past chat transcripts, use the Conversations API's relevant conversations or thread endpoints, including authentication and pagination.</cite>

<cite index="14-4,14-5">You can export sales activity data (calls, chat conversations, meetings, etc.) by creating reports with the custom report builder or using HubSpot's Engagements API.</cite> If HubSpot returns a truncated email body, call the original-content endpoint before loading into Crisp. ([developers.hubspot.com](https://developers.hubspot.com/docs/api-reference/legacy/conversations/guide?utm_source=openai))

**API versioning note:** This guide uses HubSpot's v3 CRM APIs (current stable) and v4 Associations API. HubSpot has historically maintained backward compatibility across major versions but deprecates endpoints with 12-month sunset windows. Pin your integration to specific API versions and monitor the [HubSpot Developer Changelog](https://developers.hubspot.com/changelog) for deprecation notices.

### Crisp API Capabilities

- **Create conversation:** `POST /v1/website/{website_id}/conversation`
- **Send message:** `POST /v1/website/{website_id}/conversation/{session_id}/message`
- **Update contact:** `PATCH /v1/website/{website_id}/contact/{people_id}/data`
- **Upload file:** `POST /v1/website/{website_id}/conversation/{session_id}/file` (multipart form data, max 20 MB)

<cite index="6-1">Crisp offers two authentication methods for the REST API: Website tokens, generated directly from the Crisp app — ideal for quick scripts and simple integrations; and Plugin tokens, generated via the Crisp Marketplace — providing advanced features for production integrations.</cite>

For migrations, use a **plugin token**. Website tokens default to 10,000 requests per day. Plugin tokens start at 5,000 requests per day but are configurable — and they bypass Crisp's per-route rate limits, which matters for sustained bulk writes. ([docs.crisp.chat](https://docs.crisp.chat/guides/rest-api/authentication/))

**Post-migration real-time sync:** For ongoing synchronization after cutover, Crisp's RTM (Real-Time Messaging) API provides a WebSocket connection that emits events for new messages, conversation state changes, and contact updates in real time. This is more efficient than polling the REST API and is the recommended approach for hybrid setups where both HubSpot and Crisp remain active.

### Rate Limit Strategy

**HubSpot side:** <cite index="43-2">HubSpot enforces burst limits (100–200 requests per 10 seconds) and daily limits (250,000–1,000,000 per day depending on tier).</cite> Note that HubSpot's own docs currently show slightly different numbers across pages for Professional app daily limits — size your workers from live response headers (`X-HubSpot-RateLimit-Daily-Remaining` and `X-HubSpot-RateLimit-Interval-Remaining`), not from one doc page alone. ([developers.hubspot.com](https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines))

**Crisp side:** <cite index="2-5,2-6">Plugin tokens are not subject to API Global and API Route rate-limits. This allows plugins to send bursts of requests, which is typical for integrations.</cite> However, <cite index="2-7,2-8">those tokens are subject to a special rate limiter named Plugin Quota — a quota system, reset daily, that lets a plugin perform a certain number of requests until it gets limited.</cite>

**Requesting a quota increase:** To increase your Crisp plugin token quota, submit a request through the Crisp Marketplace developer dashboard under your plugin's settings. Include your estimated total API calls using the formula: `(n × 5) + (n × m)` where `n` = number of conversations and `m` = average messages per conversation. For example, a 20,000-conversation migration averaging 8 messages each requires approximately 260,000 API calls. Submit the request at least 48 hours before starting the migration. Crisp's team reviews quota requests manually.

**Both APIs:** Implement exponential backoff with jitter on HTTP 429 responses. Your script must handle rate limiting gracefully on both sides simultaneously.

### Handling Large Datasets

- **Batching:** Process tickets in batches of 100 (HubSpot's max page size).
- **Pagination:** Use `after` cursor for HubSpot; page numbers for Crisp.
- **Checkpointing:** Store the last successfully processed ticket ID so you can resume on failure. If you cannot resume safely after a crash, you don't have a migration script — you have a demo.
- **Delta sync:** Migrate 99% of historical data in the weeks leading up to go-live. On cutover weekend, only migrate tickets updated in the last 48 hours.

## Step-by-Step Migration Process

### Step 1: Extract Data from HubSpot

```python
import requests
import time
import logging

HUBSPOT_TOKEN = "pat-xxx"
BASE_URL = "https://api.hubapi.com"
headers = {"Authorization": f"Bearer {HUBSPOT_TOKEN}"}

logger = logging.getLogger("hubspot_extract")

def extract_tickets(after=None):
    """Paginate through all tickets with rate limit handling."""
    url = f"{BASE_URL}/crm/v3/objects/tickets"
    params = {
        "limit": 100,
        "properties": "subject,hs_pipeline,hs_pipeline_stage,hs_ticket_priority,createdate,hs_lastmodifieddate,closed_date"
    }
    if after:
        params["after"] = after
    
    resp = requests.get(url, headers=headers, params=params)
    
    if resp.status_code == 429:
        retry_after = int(resp.headers.get("Retry-After", "2"))
        logger.warning(f"Rate limited. Retrying after {retry_after}s")
        time.sleep(retry_after)
        return extract_tickets(after)
    elif resp.status_code == 401:
        raise RuntimeError("Authentication failed. Check HUBSPOT_TOKEN validity and scopes.")
    
    resp.raise_for_status()
    return resp.json()

def get_ticket_emails(ticket_id):
    """Get email engagement IDs associated with a ticket."""
    url = f"{BASE_URL}/crm/v4/objects/tickets/{ticket_id}/associations/emails"
    resp = requests.get(url, headers=headers)
    
    if resp.status_code == 404:
        logger.info(f"Ticket {ticket_id} has no email associations")
        return []
    
    resp.raise_for_status()
    return resp.json().get("results", [])

def get_email_body(email_id):
    """Fetch full email content with fallback for missing fields."""
    url = f"{BASE_URL}/crm/v3/objects/emails/{email_id}"
    params = {
        "properties": "hs_email_html,hs_email_text,hs_email_subject,"
                       "hs_email_direction,hs_timestamp,hs_email_from,hs_email_to"
    }
    resp = requests.get(url, headers=headers, params=params)
    
    if resp.status_code == 404:
        logger.warning(f"Email {email_id} not found — may have been deleted")
        return None
    
    resp.raise_for_status()
    data = resp.json()
    
    # Validate required fields
    props = data.get("properties", {})
    if not props.get("hs_timestamp"):
        logger.warning(f"Email {email_id} missing hs_timestamp — will use ticket createdate")
    
    return data
```

### Step 2: Transform Data

Convert HubSpot's fragmented engagement model into Crisp's conversation format:

```python
import re
from html import unescape

def sanitize_html(html_content):
    """Strip tracking pixels, inline styles, and dangerous tags for Crisp."""
    if not html_content:
        return ""
    # Remove tracking pixels (1x1 images)
    html_content = re.sub(r'<img[^>]*width=["\']1["\'][^>]*>', '', html_content)
    # Remove inline styles that break Crisp rendering
    html_content = re.sub(r'\sstyle="[^"]*"', '', html_content)
    # Remove script tags
    html_content = re.sub(r'<script[^>]*>.*?</script>', '', html_content, flags=re.DOTALL)
    return html_content

def transform_ticket_to_conversation(ticket, emails, notes, fallback_date=None):
    """Map a HubSpot ticket + engagements to Crisp conversation format."""
    messages = []
    ticket_create = fallback_date or ticket["properties"].get("createdate", "0")
    
    for email in emails:
        if email is None:
            continue
        props = email.get("properties", {})
        
        # Skip empty engagements
        body = props.get("hs_email_text") or props.get("hs_email_html")
        if not body:
            logger.warning(f"Skipping email {email.get('id')} — empty body")
            continue
        
        # Sanitize HTML content
        if props.get("hs_email_html"):
            body = sanitize_html(props["hs_email_html"])
        
        timestamp = props.get("hs_timestamp", ticket_create)
        direction = props.get("hs_email_direction", "INCOMING")
        
        messages.append({
            "text": body,
            "date": int(timestamp),
            "from": "user" if direction == "INCOMING" else "operator",
            "source_id": email.get("id")
        })
    
    for note in notes:
        if note is None:
            continue
        props = note.get("properties", {})
        note_body = props.get("hs_note_body", "")
        if not note_body:
            continue
        
        timestamp = props.get("hs_timestamp", ticket_create)
        messages.append({
            "note": note_body,
            "date": int(timestamp),
            "from": "operator",
            "source_id": note.get("id")
        })
    
    # Sort chronologically
    messages.sort(key=lambda m: m["date"])
    
    return {
        "user": {
            "email": ticket.get("contact_email", ""),
            "name": ticket.get("contact_name", "Unknown")
        },
        "messages": messages,
        "metadata": {
            "hubspot_ticket_id": ticket["id"],
            "pipeline": ticket["properties"].get("hs_pipeline", ""),
            "priority": ticket["properties"].get("hs_ticket_priority", "")
        }
    }
```

### Step 3: Load into Crisp

```python
from crisp_api import Crisp
import logging
import json

client = Crisp()
client.set_tier("plugin")
client.authenticate(CRISP_IDENTIFIER, CRISP_KEY)

logger = logging.getLogger("crisp_load")
migration_ledger = []  # Tracks source→target ID mappings

def import_conversation(website_id, conversation_data):
    """Create a conversation in Crisp and send all messages with error handling."""
    source_id = conversation_data["metadata"]["hubspot_ticket_id"]
    
    try:
        # Check message count limit
        if len(conversation_data["messages"]) > 10000:
            logger.warning(
                f"Ticket {source_id} has {len(conversation_data['messages'])} messages "
                f"— exceeding Crisp's 10,000 message limit. Truncating to most recent 10,000."
            )
            conversation_data["messages"] = conversation_data["messages"][-10000:]
        
        # Create conversation
        conv = client.website.create_new_conversation(website_id)
        session_id = conv["session_id"]
        
        # Set user metadata
        user_email = conversation_data["user"]["email"]
        if not user_email or "@" not in user_email:
            logger.warning(f"Ticket {source_id} has invalid email: {user_email}")
            user_email = f"unknown+{source_id}@migrated.local"
        
        client.website.update_conversation_metas(
            website_id, session_id,
            {"email": user_email,
             "nickname": conversation_data["user"]["name"]}
        )
        
        # Send each message in chronological order
        failed_messages = []
        for i, msg in enumerate(conversation_data["messages"]):
            msg_type = "note" if "note" in msg else "text"
            content = msg.get("note", msg.get("text", ""))
            
            try:
                client.website.send_message_in_conversation(
                    website_id, session_id,
                    {"type": msg_type, "content": content,
                     "from": msg["from"], "origin": "chat",
                     "timestamp": msg["date"]}
                )
            except Exception as msg_err:
                failed_messages.append({"index": i, "error": str(msg_err)})
                logger.error(f"Failed message {i} in ticket {source_id}: {msg_err}")
            
            time.sleep(0.1)  # Throttle to respect rate limits
        
        # Set conversation as resolved if ticket was closed
        if conversation_data["metadata"].get("status") in ("closed", "resolved"):
            client.website.change_conversation_state(
                website_id, session_id, {"state": "resolved"}
            )
        
        # Log to migration ledger
        ledger_entry = {
            "hubspot_ticket_id": source_id,
            "crisp_session_id": session_id,
            "messages_total": len(conversation_data["messages"]),
            "messages_failed": len(failed_messages),
            "failed_details": failed_messages
        }
        migration_ledger.append(ledger_entry)
        logger.info(f"Imported ticket {source_id} → session {session_id}")
        
        return session_id
        
    except Exception as e:
        logger.error(f"Failed to import ticket {source_id}: {e}")
        migration_ledger.append({
            "hubspot_ticket_id": source_id,
            "crisp_session_id": None,
            "error": str(e)
        })
        return None

def save_ledger(filepath="migration_ledger.json"):
    """Persist the migration ledger for validation and rollback."""
    with open(filepath, "w") as f:
        json.dump(migration_ledger, f, indent=2)
    logger.info(f"Saved {len(migration_ledger)} ledger entries to {filepath}")
```

### Step 4: Map Users and Rebuild Relationships

Extract all HubSpot Owners and map their IDs to Crisp Operator IDs. If a HubSpot owner no longer exists, map their historical tickets to a generic "Legacy Agent" profile in Crisp.

Store the HubSpot Contact ID in a Crisp custom data field (`hubspot_id`) on every migrated profile. This mapping ledger is essential for validation, debugging, and potential rollback.

Match contacts to conversations by email address. Set custom data on contacts (company name, plan, account tier). Apply segment rules in Crisp to replicate HubSpot pipeline views.

### Step 5: Validate Data

- Compare record counts (tickets extracted vs. conversations created).
- Spot-check 5–10% of conversations for message completeness, correct sender attribution, and chronological order.
- Verify custom data fields populated correctly on Crisp contacts.
- Confirm attachment URLs resolve.
- Search for 10 known customer emails in Crisp's search bar to verify imported conversations are indexed and discoverable.

> [!CAUTION]
> **Critical:** <cite index="5-24,5-25,5-26">The total number of messages any given conversation can hold is limited to 10,000+ messages. If this limit is reached when sending a message from the REST API, the API will respond with 409 "too_many_messages".</cite> If you have HubSpot tickets with extremely high engagement counts, plan for message truncation or conversation splitting.

Log every source ID, target ID, payload hash, response code, and retry count. Your migration script should generate a ledger of every HubSpot ID and its corresponding Crisp ID. If an API call fails, log the exact payload for targeted retries.

## Edge Cases and Challenges

### Duplicate Records
HubSpot allows duplicate contacts (different record IDs, same email). Crisp deduplicates by email. Merge duplicates in HubSpot *before* running the extraction to avoid silent overwrites in Crisp. Use stable HubSpot IDs as dedupe keys, not email alone — old contacts may lack email, aliases change over time, or multiple HubSpot records may point at the same company.

### Missing or Inconsistent Data
HubSpot engagements with no `hs_timestamp` break chronological ordering. Default to the ticket creation date. Engagements with empty bodies (`hs_email_html` = null AND `hs_email_text` = null) should be logged and skipped, not imported as blank messages.

### Multi-Level Relationships
HubSpot allows a ticket to be associated with multiple contacts or companies. Crisp conversations are strictly tied to a single profile. Define a primary contact for each ticket and document dropped secondary associations.

### Attachments
HubSpot file attachments use `https://api.hubapi.com/filemanager/` URLs that require authentication. You must download each file, re-upload to Crisp's file API (multipart form data, max 20 MB per file) or a publicly accessible host, and update the URL in the message body. Files larger than 20 MB must be hosted externally (S3, GCS, etc.) and linked within the message text.

### Imported Conversations Visibility
Imported historical conversations stay visible to your team in the Crisp inbox but do **not** automatically appear to end users in the chatbox widget. Agents can search for and reference these conversations by customer email, but customers won't see their old ticket history in the chat widget. Set expectations with your support team about how legacy context surfaces after go-live.

### Crisp Search Indexing for Imported Data
Crisp indexes imported conversation content for full-text search. After migration, agents can search by customer email, message content, or metadata values. However, indexing is not instantaneous for bulk imports — allow 24–48 hours for large datasets to be fully searchable. Validate search coverage as part of post-migration QA.

### Private Notes on Free/Mini Plans
<cite index="30-6">Crisp's Free plan does not support messages of type "note."</cite> If you're migrating to Free or Mini, all HubSpot internal notes will be lost unless you upgrade to Essentials or Plus.

### Custom Dropdown Enums
HubSpot custom dropdown properties store an internal value that may differ from the display label. When mapping to Crisp custom data, keep the stored HubSpot value and, if needed, add a human-friendly label. Don't assume display labels are the source of truth. ([help.crisp.chat](https://help.crisp.chat/en/article/how-to-connect-hubspot-with-crisp-1klykju/))

### Oversized Message Content
Crisp messages have a practical content size limit. HubSpot emails with extremely long HTML bodies (e.g., marketing emails forwarded into tickets) may need truncation. Test with your largest email bodies before running the full migration. If a message exceeds Crisp's accepted size, the API will return a 400 error — catch this and either truncate or split the message.

## Limitations and Constraints

### What Crisp Cannot Replicate from HubSpot

- **Custom Objects:** No structured equivalent. Key-value custom data is the only option.
- **Multi-pipeline ticket routing:** Crisp uses conversation states and segments, not pipelines.
- **SLA policies:** <cite index="53-2">Crisp lacks built-in phone/voice support, advanced SLA management, and enterprise compliance features like HIPAA.</cite>
- **Branching workflow automation:** HubSpot workflows with if/then branches and custom code actions have no Crisp equivalent. Rebuild logic using chatbot flows and webhook triggers.
- **NPS/CES surveys:** No native survey tool in Crisp. Use a third-party integration.
- **Sandbox environment:** <cite index="53-3">Crisp does not offer a sandbox environment for testing changes.</cite> Test migrations against a separate Crisp workspace (create a second workspace on any paid plan).
- **Reporting depth:** Crisp's analytics focus on response times and chat volume. HubSpot's custom report builder is significantly more advanced. Prepare your ops team for a downgrade in native BI capabilities.
- **HIPAA compliance:** Not available on Crisp. If your team requires BAA agreements, Crisp is not a viable target.

### Data You Will Lose

| Data Type | Why It's Lost | Mitigation |
|---|---|---|
| Pipeline stage history | Crisp doesn't track state transitions | Archive to data warehouse before migration |
| Ticket SLA metrics (first response time, resolution time) | No SLA object in Crisp | Export SLA reports from HubSpot and store separately |
| Deal associations | No deal object in Crisp | Keep in HubSpot; surface via Crisp sidebar integration |
| Workflow execution history | No workflow engine equivalent | Export workflow logs from HubSpot for audit purposes |
| Form submission data linked to tickets | No form object in Crisp | Store as conversation custom data if critical |
| Task workflows | Fundamentally different paradigm | Redesign, not migrate |
| Multi-contact ticket associations | Crisp conversations are single-profile | Document dropped secondary associations |

## Validation and Testing

### Record Count Comparison

| Object | HubSpot Count | Crisp Count | Expected Delta |
|---|---|---|---|
| Contacts | ___ | ___ | Should be 0 (after deduplication) |
| Tickets → Conversations | ___ | ___ | Should be 0 |
| Messages (total engagements) | ___ | ___ | May differ due to skipped empties |
| Failed imports | — | ___ | Should be 0; investigate any |

### Field-Level Validation
- Verify email addresses match between source and target.
- Check that custom data keys exist on Crisp contacts.
- Confirm timestamps are within expected ranges (no future dates, no epoch-zero dates).
- Validate that operator assignments match the HubSpot owner → Crisp operator mapping table.

### Sampling Strategy
- Random sample 5% of migrated conversations.
- For each, compare: message count, sender attribution, chronological order, attachment presence.
- Manually verify 10 high-value conversations end-to-end.
- Search for 10 known customer emails in Crisp to confirm search indexing works.

### UAT Process
1. Have 2–3 agents use Crisp for 48 hours alongside HubSpot.
2. Verify they can find historical conversations by customer email.
3. Check that custom data appears in the Crisp sidebar during conversations.
4. Confirm that segment-based views match previous pipeline views.
5. Test that the Crisp-HubSpot integration (if used for hybrid setup) syncs contacts bidirectionally.

### Rollback Planning
- Keep HubSpot active (read-only) for at least 30 days post-cutover.
- Export a full backup of HubSpot data before migration.
- Document the Crisp workspace ID and all imported session IDs for potential bulk deletion.
- Rollback procedure: Use the migration ledger to identify all imported session IDs, then bulk-delete conversations via the Crisp API (`DELETE /v1/website/{website_id}/conversation/{session_id}`).

## Post-Migration Tasks

### Rebuild Automations
HubSpot Workflows cannot be exported or migrated. Audit every active workflow and rebuild the logic using:
- **Crisp chatbot builder** for automated greetings, routing, and FAQ responses
- **Hugo AI** for intelligent conversation handling and escalation
- **Webhook triggers** for pushing data to external systems
- **Zapier/Make/n8n** for cross-platform automation (e.g., creating Slack alerts on new conversations)
- **Crisp RTM API** for real-time event-driven integrations (e.g., updating HubSpot contact records when a Crisp conversation resolves)

### Update DNS and Email Routing
Repoint your support email forwarding rules (e.g., support@company.com) from HubSpot to Crisp. Update MX records or forwarding rules in your email provider. Test email delivery to Crisp before deactivating HubSpot email routing.

### Agent Training
Crisp's UI is faster but operates differently than a standard ticketing system. The biggest change is mental: HubSpot is object-and-ticket-heavy; Crisp is conversation-heavy. Train agents on:
- The conversation view vs. the ticket view
- Segments and filters (replacing pipeline views)
- Where custom data now lives (sidebar vs. dedicated tab)
- Shortcuts, private notes, and keyboard navigation
- How to search for historical (migrated) conversations by customer email or content keywords

### Monitoring
- Watch for missing conversations reported by agents in the first 2 weeks.
- Monitor Crisp's analytics for conversation volume parity with historical HubSpot data.
- Check for orphaned contacts (migrated but not linked to any conversation).
- If keeping HubSpot alongside Crisp, test two-way contact sync and confirm that custom contact properties use the stored HubSpot enum values you expect.
- Review the migration ledger for any entries with `crisp_session_id: null` (failed imports) and re-run those individually.

## Best Practices

1. **Back up everything first.** Export all HubSpot data as CSV and store alongside API-extracted JSON files in a secure, versioned location (S3 with versioning, or equivalent).
2. **Run a test migration.** Migrate 100 tickets to a separate Crisp workspace before touching production. Validate field mapping, message ordering, and attachment handling.
3. **Request Crisp API quota early.** Plugin token quotas default low. Submit your quota request through the Crisp Marketplace developer dashboard using the `(n × 5) + (n × m)` formula at least 48 hours before migration.
4. **Block outgoing emails during import.** Contact Crisp support to temporarily block outgoing emails for your workspace to avoid unwanted notifications during the import.
5. **Run a delta sync.** Migrate historical data in the weeks leading up to go-live. On cutover weekend, only migrate the delta — tickets updated in the last 48 hours. This ensures zero downtime.
6. **Validate incrementally.** Don't wait until all conversations are imported to check. Validate every 1,000 conversations.
7. **Log aggressively.** Every API call, every error, every skipped record. Persist the migration ledger to disk after every batch. You'll need this for post-migration QA.
8. **Keep HubSpot read-only for 30 days.** Don't cancel your subscription immediately. You'll need it for reference and potential data recovery.
9. **Allow 24–48 hours for Crisp search indexing.** After bulk imports, Crisp's search index may not immediately surface all imported conversations. Plan UAT accordingly.
10. **Test with your worst-case data.** Migrate the tickets with the most engagements, largest attachments, and most complex HTML emails first. Edge cases in test are easier to fix than edge cases in production.

## Making the Decision

A HubSpot Service Hub to Crisp migration is a **simplification trade.** You gain a faster, cheaper, conversation-first platform. You lose CRM depth, pipeline structure, workflow complexity, and SLA tooling.

**This migration makes sense when:**
- You're not using HubSpot CRM alongside Service Hub
- Your team values speed and simplicity over enterprise features
- You need flat-rate pricing that doesn't scale per agent
- Your support model is primarily chat and messaging, not ticket management
- Your team is EU-based and values Crisp's default EU data residency

**It doesn't make sense when:**
- You rely on HubSpot's cross-object workflows (ticket + deal + contact automation)
- You need multi-pipeline routing with SLA enforcement
- Your team uses Custom Objects extensively
- Compliance requirements demand HIPAA, audit trails, or SLA reporting
- You need deep BI/reporting beyond chat volume and response times

For most teams, the cleanest target architecture is **Crisp for the support inbox and HubSpot retained for CRM depth** through the native integration.

For related reading on helpdesk migrations, see our guides on [HubSpot Service Hub to Intercom migration](https://clonepartner.com/blog/blog/hubspot-service-hub-to-intercom-migration-2026-guide/) and [HubSpot Service Hub to Zendesk migration](https://clonepartner.com/blog/blog/how-to-migrate-from-hubspot-service-hub-to-zendesk-complete-guide/). If you're evaluating platforms before committing, our [Crisp vs Gorgias comparison](https://clonepartner.com/blog/blog/crisp-vs-gorgias-2026-the-ctos-technical-comparison/) covers the technical architecture differences.

> Need help migrating from HubSpot Service Hub to Crisp? ClonePartner handles the full data extraction, engagement reconstruction, and conversation import — with zero downtime and complete data validation. Book a free 30-minute scoping call.
>
> [Talk to us](https://cal.com/clonepartner/meet?duration=30)

## Frequently asked questions

### Can I migrate HubSpot Service Hub ticket history to Crisp?

Yes, but not via CSV. HubSpot stores email, note, and call content as separate engagement objects across different API endpoints. You need an API-based script to extract engagements, reconstruct them into threaded messages, and import them as Crisp conversations using the Crisp REST API or the official crisp-import-conversations tool with a custom adapter.

### Does Crisp have a built-in HubSpot migration tool?

No. Crisp's open-source crisp-import-conversations script supports Zendesk, Gorgias, Help Scout, Tidio, GrooveHQ, and WHMCS adapters, but not HubSpot. You need to write a custom adapter or use a managed migration service.

### What data is lost when migrating from HubSpot Service Hub to Crisp?

Pipeline stage history, SLA metrics (first response time, resolution time), deal associations, workflow execution history, custom objects (Crisp has no equivalent — only key-value custom data), and NPS/CES survey data. Workflows must be rebuilt manually using Crisp's chatbot builder or webhook triggers.

### How long does a HubSpot Service Hub to Crisp migration take?

For teams with under 50K tickets: 1–3 weeks including planning, test migration, and validation. Larger datasets with complex custom objects or heavy attachments take 3–6 weeks. The main bottleneck is API rate limits on both platforms and the engagement reconstruction step.

### Can I keep HubSpot CRM after moving support to Crisp?

Yes. Crisp's HubSpot integration supports two-way contact sync, can surface deals and list memberships in the Crisp sidebar, and can report Crisp conversations back to HubSpot. This hybrid setup — Crisp for support, HubSpot for CRM — is often the cleanest architecture.
