Gladly to HubSpot Service Hub Migration: Technical Guide
Technical guide to migrating from Gladly to HubSpot Service Hub. Covers data model translation, API extraction limits, field mapping, truncation risks, and step-by-step process.
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
Gladly to HubSpot Service Hub Migration: Technical Guide
TL;DR — Gladly to HubSpot Service Hub Migration
Gladly's ticketless, customer-centric timeline does not map 1:1 to HubSpot's relational ticket model. Migrating requires API-based extraction with hard caps (100 conversations per customer, 1,000 items per conversation — neither paginated), careful data-model translation, attachment re-hosting, and timestamp preservation. The single biggest risk is silent data truncation: if the Gladly-Limited-Data response header comes back true, you've lost data and may not notice without explicit checks. Expect 2–4 weeks for under 50K conversations, 4–8 weeks for larger datasets with attachments and custom attributes. Target HubSpot's Help Desk workspace (Professional or higher), not legacy Tickets. Routing logic, SLAs, and macros must be rebuilt — not exported. Teams with fewer than 10,000 email-only conversations can self-serve with API scripts. Anything larger — especially with attachments, multi-channel history, and voice recordings — benefits from a managed migration.
Last verified: August 2025. Rate limits, API endpoints, and HubSpot tier pricing confirmed against official Gladly and HubSpot developer documentation. HubSpot pricing changes frequently — verify current seat pricing at hubspot.com/pricing before budgeting.
What Is a Gladly to HubSpot Service Hub Migration?
A Gladly to HubSpot Service Hub migration extracts Customers, Conversations, Conversation Items (emails, chat messages, SMS, voice call records, social messages, notes), Topics, Tasks, Agents, Teams, Custom Attributes, and Answers (knowledge base articles) from Gladly and loads them into HubSpot as Contacts, Companies, Tickets, Engagements (emails, notes, calls), Custom Properties, Tasks, Owners, Teams, and Knowledge Base articles.
This is not a CSV import. The two platforms use fundamentally different philosophies. Gladly is ticketless — every interaction lives on a single, continuous Customer timeline regardless of channel. HubSpot is ticket-centric — every support issue is a discrete Ticket with Engagements associated to it. Translating one model to the other requires deliberate architectural decisions about how to slice Gladly's continuous timeline into discrete HubSpot Tickets. (developer.gladly.com)
Do not confuse Gladly "Contacts" with HubSpot "Contacts." In Gladly, a Contact is a channel session (a phone call, chat, or email interaction) inside a conversation. In HubSpot, a Contact is a CRM person record. Mapping Gladly Contacts to HubSpot Contacts creates duplicate people, broken associations, and bad reporting. The correct mapping is Gladly Customer → HubSpot Contact. (developer.gladly.com)
Why Teams Move from Gladly to HubSpot Service Hub
- CRM unification. HubSpot collapses sales, marketing, and support data into a single contact record. Teams running HubSpot CRM for sales want support history visible on the same timeline — not siloed in a separate tool.
- Cross-object reporting. HubSpot's reporting engine (Professional and Enterprise tiers) supports cross-object reporting across deals, tickets, and contacts. Gladly's reporting is contact-center-focused and doesn't natively connect to pipeline or revenue data.
- Integration ecosystem. HubSpot's marketplace lists 1,500+ apps. Gladly has roughly 40 native integrations, heavily weighted toward e-commerce (Shopify, Magento).
- Workflow automation. HubSpot's workflow engine spans contacts, deals, tickets, and custom objects. Gladly's automation is limited to routing and assignment rules.
- Cost structure. Gladly's per-agent pricing for mid-market teams can exceed HubSpot Service Hub Professional, especially when teams also need CRM functionality that HubSpot bundles in. Verify current Gladly contract terms against HubSpot's published seat pricing before using cost as the primary migration justification.
The Architectural Mismatch: Timeline vs. Relational CRM
Understanding the structural difference is the single most important step before writing any migration code.
Gladly's Data Model
Gladly is built around the Customer Profile. When a customer emails, calls, or chats, that interaction is appended to a single, continuous feed called the Conversation Timeline.
- There are no "Ticket IDs." A Conversation is an open-to-close cycle on the customer's timeline.
- A customer can have many conversations but only one open conversation at a time. (developer.gladly.com)
- Metadata like Topics and Status is applied to the Conversation, not an isolated ticket.
- When an issue is resolved, the conversation is closed. The next time the customer reaches out, a new conversation opens on the same timeline.
HubSpot's Data Model
HubSpot is a relational CRM. The core entities are Contacts and Companies.
- Support requests are stored as Tickets — distinct objects with their own IDs, pipeline stages, and properties.
- Messages (emails, notes, calls) are stored as Engagements (Activities in newer API terminology).
- Engagements are associated with the Ticket, and the Ticket is associated with the Contact. (developers.hubspot.com)
Data Model Mapping Reference
| Gladly Concept | HubSpot Equivalent | Notes |
|---|---|---|
| Customer | Contact | 1:1. Gladly merges all channels into one profile; HubSpot deduplicates on email. |
| Conversation | Ticket | One Gladly Conversation → one HubSpot Ticket. |
| Contact (Gladly) | Activity metadata | A channel session — NOT a HubSpot Contact. |
| Conversation Item | Engagement (Email, Note, Call) | Items are typed: email, chat, SMS, voice, note, social. Each maps to a different engagement type. |
| Topic | Tag or custom multi-select property | Gladly Topics are labels on Conversations. |
| Task | Task (CRM) | Internal action items → HubSpot Tasks. |
| Agent | Owner | 1:1. HubSpot Owners must exist before ticket import. |
| Team | Team | Configured in HubSpot account settings. |
| Inbox | Pipeline or custom property | Gladly Inboxes route by channel/team. Map to pipelines or a property. |
| Custom Attributes | Custom Properties or Custom Objects | Simple → custom properties. Complex relational → Custom Objects (Enterprise only). |
| Answers | Knowledge Base Articles + Snippets | Public-facing → KB Articles. Internal macros → Snippets. Requires Professional+. |
| Conversation Workflow | Workflows | No export. Must be rebuilt manually. |
| People Match | No equivalent | Gladly's route-by-relationship logic has no HubSpot counterpart. |
The Translation Decision
When migrating, you need to decide how to slice the timeline:
- One Gladly Conversation = one HubSpot Ticket. This is the cleanest mapping. Each Conversation becomes a Ticket, and each Conversation Item becomes an Engagement associated to that Ticket. This preserves reporting accuracy on ticket volume, resolution times, and topic distribution.
- One Gladly Customer = one archival HubSpot Ticket. If you only need searchable history, you can collapse all conversations into a single ticket with notes. Simpler, but loses granularity.
We recommend option 1 for any team that needs operational reporting.
Import API vs. CRM API: Decision Rule
Both paths load data into HubSpot but serve different needs. Use this decision table:
| Condition | Use Import API | Use CRM API |
|---|---|---|
Need to preserve historical createdate / closedate |
✓ | ✗ (sets timestamp to now) |
| Need programmatic association creation (Ticket → Contact) | ✗ | ✓ |
| Batch size exceeds 500,000 records | ✓ (volume efficiency) | ✗ |
| Need upsert with unique property key | ✗ | ✓ (batch upsert endpoint) |
Loading Engagements with hs_timestamp |
✗ | ✓ |
In practice, most migrations use both: Import API for Contacts and Tickets (to preserve timestamps), CRM API for Engagements and Associations (which require programmatic linking). The Import API does not support association creation — you must wire those via the Associations API regardless.
How to Extract Data from Gladly
Gladly provides two extraction paths: the Export API (bulk JSONL) and the REST API (per-record). Neither gives you everything on its own.
Authentication
Gladly's REST API uses HTTP Basic authentication: a base64-encoded string of email:password (or API key credentials) passed as the Authorization header. There is no OAuth 2.0 flow in Gladly's public REST API. Credentials are issued per-account through the Gladly admin console. Token rotation is manual — set a reminder to rotate credentials before they expire if your organization enforces rotation policies. Do not hardcode credentials in scripts; load them from environment variables or a secrets manager. (developer.gladly.com)
Export API (Bulk JSONL)
Gladly's Export API produces JSONL files covering agents, customers, conversation items, and topics within a date range. Key constraints:
- Files expire after 14 days. Download promptly or they're gone.
- Conversation item limit: 2,000 items per export file. High-volume accounts need multiple export jobs.
- Exports run on a 24-hour cadence. Your final backfill of recent history should not depend only on yesterday's export file. (help.gladly.com)
- No attachments. The Export API returns message text and metadata, not file attachments.
- No Tasks. Task data must be extracted separately via the REST API.
- All-time historical transcript data can only be generated by Gladly Support. (help.gladly.com)
REST API (Per-Record Extraction)
The REST API gives full control but has hard pagination limits that create the migration's biggest data-loss risk:
- Conversations per customer: max 100. This endpoint is not paginated. If a customer has more than 100 conversations, the
Gladly-Limited-Dataresponse header returnstrue, and the oldest conversations are silently dropped. - Items per conversation: max 1,000. Same behavior — no pagination, silent truncation signaled by the header.
- Rate limits: 10 requests per second per HTTP method (GET, POST, PUT, PATCH, DELETE). (developer.gladly.com)
Silent truncation is the #1 data-loss risk. Always check the Gladly-Limited-Data header on every conversations and items response. If it returns true, you have history the API cannot fully return. For these edge cases, use the Export API with date-range filtering or contact Gladly Support for a full data export. There is no REST API workaround for these caps — pagination is not available on either endpoint.
Customer Inventory
Gladly does not offer a generic list-all-customers endpoint in its public REST API. The customer lookup endpoint searches by email, phone, or external customer ID and returns at most 50 profiles per query. Bulk customer email export is also unavailable in the UI. (developer.gladly.com)
Most migrations build a seed list from conversation exports or reports, then hydrate each customer profile with direct API reads.
Recommended Extraction Strategy
- Start with the Export API to get a bulk dump of customers and conversation items within your target date range.
- Use the REST API to backfill full message bodies, attachments, and metadata for records that need higher fidelity.
- Cross-reference the
Gladly-Limited-Dataheader against your customer list to identify truncated records. - Extract Tasks separately via
GET /api/v1/tasks. - Extract Answers via the Answers API for knowledge base migration.
- Handle merged customers. Gladly returns a 301 redirect for customer records that have been merged into a new ID. Your extractor should follow that redirect chain instead of creating duplicate HubSpot contacts. (developer.gladly.com)
- Handle Sidekick-handled conversations. Conversations handled by Gladly's Sidekick AI appear in the standard conversations API as regular conversation items — they are not in a separate endpoint. Verify that
assignee.typevalues in your export include AI-handled items, and decide whether to tag them differently in HubSpot (e.g., ahandled_by_aiboolean property on the Ticket).
import requests
import time
import os
GLADLY_DOMAIN = "https://yourorg.gladly.com"
# Load credentials from environment — never hardcode
HEADERS = {
"Authorization": f"Basic {os.environ['GLADLY_API_KEY']}",
"Accept": "application/json"
}
def get_customer_conversations(customer_id):
url = f"{GLADLY_DOMAIN}/api/v1/customers/{customer_id}/conversations"
resp = requests.get(url, headers=HEADERS)
resp.raise_for_status()
truncated = resp.headers.get("Gladly-Limited-Data", "false") == "true"
if truncated:
print(f"WARNING: Customer {customer_id} has >100 conversations. Data truncated.")
# Flag for Export API fallback — log to a separate file for remediation
return resp.json(), truncated
def get_conversation_items(conversation_id):
url = f"{GLADLY_DOMAIN}/api/v1/conversations/{conversation_id}/items"
resp = requests.get(url, headers=HEADERS)
resp.raise_for_status()
truncated = resp.headers.get("Gladly-Limited-Data", "false") == "true"
if truncated:
print(f"WARNING: Conversation {conversation_id} has >1000 items. Data truncated.")
return resp.json(), truncated
# Respect rate limit: 10 req/sec
time.sleep(0.1)Data Transformation and Field Mapping
Once data is in a staging environment, transform it to match HubSpot's schema.
Customer → Contact
| Gladly Field | HubSpot Property | Notes |
|---|---|---|
name |
firstname, lastname |
Split full name |
emails [0].original |
email |
Primary email |
phones [0].original |
phone |
Primary phone |
address |
address, city, state, zip |
Parse structured address |
customAttributes |
Custom properties | Create matching properties first |
externalCustomerId |
Custom property | Useful for cross-referencing |
id |
Custom property (gladly_customer_id) |
Preserve for audit trail and reruns |
Conversation → Ticket
| Gladly Field | HubSpot Property | Notes |
|---|---|---|
id |
Custom property (gladly_conversation_id) |
Essential for validation and idempotent reruns |
status (OPEN/CLOSED) |
hs_pipeline_stage |
Map to your stage IDs |
topics [].name |
hs_tag or custom multi-select |
Topics become tags or a dropdown |
assignee.agentId |
hubspot_owner_id |
Must pre-map agent → owner IDs |
inbox.id |
hs_pipeline or custom property |
One inbox → one pipeline, or use a property |
createdAt |
createdate |
Preserve original timestamp |
closedAt |
closed_date |
Only for closed conversations |
Conversation Item → Engagement
| Gladly Item Type | HubSpot Engagement Type | Notes |
|---|---|---|
EMAIL |
Map from, to, subject, body |
|
CHAT_MESSAGE |
Note | Prefix with [Chat] for visibility |
SMS |
Note | Prefix with [SMS] — no native SMS engagement type for historical imports |
PHONE_CALL |
Call | Map duration, recording URL if available |
NOTE |
Note | Direct mapping |
FACEBOOK_MESSAGE |
Note | Prefix with [Facebook] |
INSTAGRAM_DIRECT |
Note | Prefix with [Instagram] |
TOPIC_CHANGE |
Note (optional) | Log as internal note if audit trail needed |
Agent Permission Mapping
Gladly Agents and HubSpot Owners do not share permission models. Before migration, audit your Gladly agent roster against HubSpot user permissions:
- Gladly roles (Agent, Team Lead, Admin) do not map directly to HubSpot roles (User, Super Admin, with granular object-level permissions).
- In HubSpot, ticket visibility can be restricted by team assignment or pipeline access. A Gladly agent who could see all inboxes may need explicit HubSpot pipeline permissions to maintain equivalent access.
- Create a permission mapping spreadsheet: Gladly Agent ID → HubSpot Owner ID → HubSpot Role → Pipeline Access. Run this review with your IT or RevOps team before loading any ticket data, since
hubspot_owner_idon tickets determines ownership assignments post-migration.
The Intermediate Canonical Model
A canonical staging record is your best tool for replayability:
gladlyCustomerId: OOrlNMXeS72gs_WEX2TtMg
gladlyConversationId: 9BcE2O0DQ2ynGHRmk9FeoA
gladlyItemId: ybP4szYCSy6LdV4DNwEd6g
channel: EMAIL
sessionId: 5k04bYuTRGqyT6uoSQfWVA
occurredAt: 2025-07-12T14:31:19Z
itemType: CONVERSATION_NOTE
hubspotObject: note
truncationFlagged: false
extractionRunId: run_2025-08-01_001The truncationFlagged and extractionRunId fields enable you to filter your canonical records for remediation runs and tie each record back to a specific extraction job. This lets you rerun failed batches, remap edge cases, and maintain source-to-target lineage without guessing after the fact.
Loading Data into HubSpot Service Hub
Choose the Right HubSpot Tier
Your target tier determines what's possible. Choose before you write any mapping code.
| Feature Needed | Minimum Tier | Price (annual, verify at hubspot.com) |
|---|---|---|
| Basic ticketing | Starter | $15/seat/month (approx.) |
| Help Desk workspace | Professional | $90/seat/month (approx.) |
| Knowledge Base | Professional | $90/seat/month (approx.) |
| SLAs and custom ticket routing | Professional | $90/seat/month (approx.) |
| Multiple ticket pipelines | Professional | $90/seat/month (approx.) |
| Custom Objects | Enterprise | $150/seat/month (approx.) |
Target the Help Desk workspace, not legacy Tickets. HubSpot released the Help Desk workspace in 2024 as the primary support interface. Legacy Tickets still work but won't receive new features. Design your migration for the Help Desk workspace from day one. HubSpot has announced that publishing comments to Help Desk threads via the Conversations API will error starting September 23, 2026, directing integrations toward the Notes API instead. Treat historical data as tickets + associated activities/notes, not recreated native thread comments. (developers.hubspot.com)
HubSpot sandbox limitations. Testing in a HubSpot sandbox is strongly recommended before production loads, but sandboxes do not fully replicate production rate limits or all object behaviors. Specifically: sandbox API rate limits may differ from production, and some import behaviors (large batch jobs, KB article limits) should also be tested in a low-volume production environment before full-scale execution.
HubSpot API Rate Limits
HubSpot's limits are more generous than Gladly's but still require planning:
- Private apps (Professional/Enterprise): 190 requests per 10 seconds per app
- OAuth apps: 110 requests per 10 seconds per installed account
- Daily limits: 650,000 requests/day (Professional), 1,000,000/day (Enterprise)
- Batch endpoints: Up to 100 records per request — use these to cut API usage dramatically
- Search API: 5 requests per second, 200 results per page, 10,000 total results per query — build lookup caches instead of doing live searches per row (developers.hubspot.com)
HubSpot uses a token-bucket model. Bursts are fine as long as you let the bucket refill. Implement exponential backoff on 429 responses and log the correlationId from error responses for debugging.
Preserving Historical Timestamps
If you use the standard POST /crm/v3/objects/tickets endpoint, HubSpot sets the ticket's createdate to the moment your script runs — destroying historical reporting.
Two approaches to preserve original timestamps:
- Import API (
/crm/v3/imports): Accepts CSV/JSON with historicalcreatedateandclosedatevalues. HubSpot honors them. - CRM API with
hs_timestamp: For Engagements (emails, notes, calls), seths_timestampin the payload to place activities correctly on the timeline.
HubSpot notes are capped at 65,536 characters. Long transcripts or collapsed chat histories need splitting across multiple notes. (developers.hubspot.com)
The Load Sequence
Order matters. HubSpot requires parent records before you can associate child records:
- Owners (Agents) — Create or map HubSpot users matching Gladly agents. Confirm permission assignments before proceeding.
- Contacts (Customers) — Use the batch API (
POST /crm/v3/objects/contacts/batch/create). Deduplicate on email. Gladly Customers often have multiple email/phone entries — pick a primary. - Companies — Create Company records if Gladly custom attributes include company data. Associate to Contacts.
- Tickets (Conversations) — Batch create via the Tickets API. Include
gladly_conversation_idas a custom property. Map Gladly status to pipeline stages. - Engagements (Conversation Items) — Create the appropriate type per item:
- Email items → Email Engagement
- Chat/SMS/social items → Note (prefixed with channel tag)
- Voice items → Call Engagement
- Internal notes → Note
- Associate Engagements to Tickets and Contacts via the Associations API.
- Knowledge Base (Answers) — Load via the KB API or CSV import.
- Tasks — Migrate open Gladly Tasks as HubSpot Tasks.
Create durable source-ID properties (gladly_customer_id, gladly_conversation_id, gladly_item_id) as unique-value properties in HubSpot before any load. This makes imports and API loads replay-safe and deduplication reliable. (knowledge.hubspot.com)
import requests
import os
HUBSPOT_TOKEN = os.environ["HUBSPOT_ACCESS_TOKEN"]
HS_HEADERS = {
"Authorization": f"Bearer {HUBSPOT_TOKEN}",
"Content-Type": "application/json"
}
def create_tickets_batch(tickets):
"""Create up to 100 tickets per batch request."""
url = "https://api.hubapi.com/crm/v3/objects/tickets/batch/create"
payload = {
"inputs": [
{
"properties": {
"subject": t["subject"],
"hs_pipeline": "0",
"hs_pipeline_stage": "1",
"hs_ticket_priority": t.get("priority", "MEDIUM"),
"createdate": t["created_at"],
"gladly_conversation_id": t["gladly_id"]
}
}
for t in tickets
]
}
resp = requests.post(url, json=payload, headers=HS_HEADERS)
if resp.status_code == 429:
# Log correlationId for debugging, then back off
print(f"Rate limited. correlationId: {resp.json().get('correlationId')}")
raise Exception("Rate limit hit — implement exponential backoff")
resp.raise_for_status()
return resp.json()Rollback Strategy
HubSpot has no native rollback for bulk loads. Design for safe reruns from the start:
- Upsert instead of create. Use the batch upsert endpoint (
/crm/v3/objects/tickets/batch/upsert) withgladly_conversation_idas the unique ID key. This makes the load idempotent — rerunning won't create duplicates. - If you need to delete and re-run: Use the HubSpot Search API to find all Tickets where
gladly_conversation_idis set, then batch-delete them viaPOST /crm/v3/objects/tickets/batch/archive. At 100 records per batch and 190 requests per 10 seconds, deleting 50,000 tickets takes approximately 45 minutes. - Log every created HubSpot ID against its Gladly source ID in your staging database before moving to the next phase. This is your rollback manifest — without it, targeted deletion is impossible.
- Never run association creation until Contact and Ticket loads are confirmed complete. Orphaned associations are harder to clean up than orphaned records.
Handling Attachments and Voice Recordings
Attachments are the most common failure point in helpdesk migrations.
Attachment Migration
Gladly stores attachments as URLs within Conversation Items. These URLs may be signed or time-limited and require authentication to access. You cannot pass Gladly URLs to HubSpot — once you deprecate your Gladly instance, those URLs will 404, resulting in permanent data loss.
The workflow:
- Parse each Conversation Item for attachment URLs.
- Execute an authenticated
GETto download the file to staging storage (local, S3, GCS). - Upload to HubSpot via the Files API (
POST /files/v3/files). - Store the returned HubSpot
fileId. - When creating the Engagement, reference the file using
hs_attachment_ids.
HubSpot's file size limit is 512 MB per file. Log any files that fail to upload so you can handle them manually.
Voice Call Recordings
Gladly exposes recording and voice-transcript endpoints for applicable conversation items. HubSpot Call Engagements support a hs_call_recording_url property, but the recording file must be hosted at an accessible HTTPS URL pointing to an .mp3 or .wav file. (developer.gladly.com)
If Gladly's recording URLs are signed and time-limited, download and re-host the files before migrating. Recordings uploaded to HubSpot will appear as file attachments or URLs on a Call Engagement — they won't integrate into HubSpot's native calling tool as playable objects, but they're accessible and searchable.
Compliance and Data Residency
If your organization operates under GDPR, CCPA, or other data protection regulations, treat the extraction and staging phase as a data processing activity:
- GDPR: Extracting EU customer PII (names, emails, voice recordings) from Gladly into cloud staging storage (S3, GCS) may constitute a data transfer. Confirm your staging environment's data residency aligns with your DPA obligations. If your Gladly data is EU-hosted and your staging bucket is US-based, you need a transfer mechanism (SCCs or equivalent).
- Voice recordings often carry additional consent requirements — verify that recordings in your Gladly dataset were collected with appropriate consent before migrating them to a new system.
- CCPA: Customers who have submitted deletion requests in Gladly should be excluded from migration. Cross-reference your suppression list against the customer seed list before extraction begins.
- Data minimization: Consider whether migrating full conversation bodies older than your retention policy creates compliance risk. Many organizations migrate only metadata (ticket IDs, timestamps, topics, statuses) for conversations older than 2–3 years, and full content for recent history only.
Knowledge Base Migration: Gladly Answers to HubSpot KB
Gladly "Answers" serve dual purposes: both internal agent macros and external knowledge base articles. HubSpot separates these — external content lives in the Knowledge Base, internal agent responses live in Snippets or Templates.
HubSpot KB Limits
- HubSpot's smart-copy KB import supports Freshdesk, Help Scout, Zendesk, and Intercom — not Gladly. You'll need CSV or API-based import. (help.gladly.com)
- Each knowledge base import is capped at 400 articles per batch.
- Service Hub Professional: 1 knowledge base, up to 2,000 articles.
- Service Hub Enterprise: Up to 100 knowledge bases, up to 10,000 articles.
- Table import is not supported — flatten tables to lists or simple HTML blocks.
Migration Workflow
- Export Gladly Answers via the API Export Tool or
GET /api/v1/answers. - Separate public-facing articles from internal macros.
- For public articles: normalize to HubSpot's CSV format (URL, title, category, body) and batch import in groups of 400. Or use the CMS Knowledge Base API (
/cms/v3/knowledge-base/articles). - For internal macros: recreate as HubSpot Snippets via the Snippets API.
- Update any internal links within article bodies to point to new HubSpot URLs.
- QA redirects, embedded images, and category paths after publish.
Multi-Language Considerations
Gladly Answers can be authored with multiple language variants and channel-specific versions (email, messaging, Help Center). HubSpot's KB supports multi-language articles, but each variant is a separate article linked by a primary_language relationship. If you have channel-specific answer variants, decide whether HubSpot should get one article per canonical answer or multiple channel-specific articles — that's a content design decision, not a migration script setting.
Common Failure Modes and Edge Cases
1. Customers with 100+ Conversations
Gladly's API hard-caps at 100 conversations per customer with no pagination. For loyalty program members, VIP accounts, and long-running B2B relationships, the oldest conversations are silently dropped. There is no API workaround. Use the Export API with date-range filters to capture full history, then reconcile against REST API data.
2. Conversations with 1,000+ Items
Same problem, different scale. Long email threads or chat sessions can exceed 1,000 items. The Gladly-Limited-Data header signals this, but you'll need the Export API or Gladly Support for the complete item list.
3. Multi-Channel Conversations
A single Gladly Conversation can span email, chat, SMS, and voice. When this maps to one HubSpot Ticket, the Engagements will be mixed types. This works functionally, but reporting by channel becomes harder. Add a custom property on each Engagement or a channel tag on the Ticket to preserve this metadata.
4. Real-Time Lookup API Data
Gladly's Lookup API pulls live data from external systems (Shopify orders, loyalty points) into the agent view. This data is not stored in Gladly — it's fetched in real-time. You cannot migrate it. If you need this data in HubSpot, build a separate integration from the source system to HubSpot custom properties or Custom Objects. (developer.gladly.com)
5. Merged Customer Records
Gladly returns a 301 redirect for customer records that have been merged into a new ID. Your extractor must follow that redirect chain instead of creating duplicate HubSpot contacts. (developer.gladly.com)
6. HubSpot CSV Import Constraints
Paid HubSpot accounts support import files up to 512 MB, 1,048,576 rows per file, 10,000,000 rows per day, and fewer than 1,000 columns. Existing emails, meetings, notes, and tasks cannot be updated via import — only created. API-driven idempotent upserts are safer for historical activity backfills. (knowledge.hubspot.com)
7. Delta Migration During Cutover Window
"Run a delta migration" is not an instruction on its own. Here is the concrete implementation:
- Detect new/updated records: Compare
updatedAttimestamps in the Gladly Export API against your extraction log. Any Gladly Conversation withupdatedAt > extraction_start_timestampis a candidate for the delta run. - New conversations: Run the full REST API extraction for conversations created after your initial extraction date.
- Updated conversations: For conversations that existed during initial extraction but have new items (e.g., a customer replied during the migration window), extract only new Conversation Items by comparing item
idlists against your canonical model. - Load delta records: Use the batch upsert endpoint with
gladly_conversation_idas the unique key — this prevents duplicates if an updated conversation was partially loaded during the initial run. - Note: The Export API lags by 24 hours. If cutover is same-day, supplement with REST API calls for the final window.
Step-by-Step Migration Timeline
Phase 1: Audit and Planning (Days 1–3)
- Inventory Gladly data: customers, conversations, conversation items, topics, tasks, agents, answers.
- Identify truncation risks. Query your most active customers and check the
Gladly-Limited-Dataheader. - Audit agent permissions and create the agent → owner mapping.
- Choose your HubSpot tier. Professional minimum; Enterprise if you need Custom Objects.
- Review compliance obligations: GDPR, CCPA, data retention policies.
- Map fields using the tables above. Create all custom properties in HubSpot before importing data.
- Set up a HubSpot sandbox for testing (note sandbox rate limit caveats above).
Phase 2: Extraction (Days 4–8)
- Run the Gladly Export API for your full date range. Download JSONL files immediately.
- Run REST API extraction for conversations and items, logging truncation flags.
- Download all attachments to cloud staging storage (S3, GCS). Verify data residency compliance.
- Extract Answers and Tasks via their dedicated APIs.
- Validate: total records extracted vs. expected counts from reporting.
Phase 3: Transformation (Days 5–10)
- Parse Gladly data into your intermediate canonical model (include
truncationFlaggedandextractionRunId). - Split customer names into first/last.
- Map agent IDs → HubSpot Owner IDs (using the pre-built permission mapping).
- Map Topics → HubSpot tags or multi-select property values.
- Convert Conversation Items into typed Engagement payloads.
- Generate association mappings (Ticket → Contact, Engagement → Ticket).
- Cross-reference suppression lists (GDPR/CCPA deletions) and exclude flagged customers.
Phase 4: Loading (Days 8–14)
- Load Contacts via batch upsert (100 per request), using
gladly_customer_idas unique key. - Load Companies if applicable.
- Load Tickets via batch upsert with preserved timestamps.
- Load Engagements and associate to Tickets + Contacts.
- Upload attachments via Files API and link to Engagements.
- Load Knowledge Base articles (batches of 400).
- Load Tasks.
- Log every created HubSpot ID → Gladly source ID pair in staging database.
Phase 5: Validation (Days 12–17)
- Record count validation. Compare source counts to HubSpot counts for each object type.
- Conversation fidelity. Spot-check 20–50 conversations across different channels. Verify message content, timestamps, chronological order, and associations.
- Attachment checks. Click attachments in HubSpot to confirm they open correctly and aren't gated behind a dead Gladly URL.
- Reporting. Verify ticket pipeline reports, resolution time calculations, and topic distributions match expectations.
- KB validation. Check formatting, images, links, and categories in migrated articles.
- Recount by channel and item type, not only top-level totals. A ticket count that matches with missing notes or calls is still a failed migration.
- Truncation audit. Pull all records where
truncationFlagged = trueand confirm they were remediated via Export API or Gladly Support.
Phase 6: Cutover and Cleanup (Days 15–20)
- Rebuild Gladly Conversation Workflows as HubSpot Workflows.
- Configure routing rules in HubSpot Help Desk.
- Set up SLAs (Professional+ only).
- Train agents on the Help Desk workspace.
- Run a delta migration for conversations created during the migration window (see delta mechanics above).
- Switch live traffic to HubSpot.
- Keep Gladly in read-only mode for 30 days as a safety net.
What Cannot Be Migrated
Some Gladly features have no HubSpot equivalent and must be rebuilt or accepted as losses:
- People Match routing logic — Gladly's ability to route returning customers to the same agent. You can approximate it with HubSpot's "Specific users and teams" routing, but it's manual and limited.
- Conversation Workflows — No export path. Must be reconstructed in HubSpot Workflows. Gladly can export rules as CSV (as of June 2026) for reference, but the export is not executable in HubSpot. (help.gladly.com)
- Saved Views — Agent-facing saved views don't export. Recreate as HubSpot custom views.
- Real-time Lookup API data — Not stored in Gladly. Build direct integrations from source systems to HubSpot.
- CSAT/NPS historical data — Raw scores can be stored as custom properties on Tickets, but you cannot inject historical survey data into HubSpot's native Customer Feedback reporting.
- Voice recordings as native playable objects — Recordings appear as file attachments or URLs on Call Engagements, not as native playable objects in HubSpot's calling tool.
- Sidekick (AI) configuration — Gladly's AI automation rules and trained intents have no migration path. HubSpot's Breeze AI is a different system with different training inputs. Note: Sidekick-handled conversation items appear in the standard API and can be migrated as regular conversation data; only the AI configuration itself is non-migratable.
- Gladly Rules — Routing, SLA triggers, and auto-reply logic must be rebuilt using HubSpot Workflows.
Timeline and Effort Estimates
| Scenario | Conversations | Estimated Timeline |
|---|---|---|
| Small team, email-only | <5,000 | 1–2 weeks |
| Mid-market, multi-channel | 5,000–50,000 | 2–4 weeks |
| Enterprise, custom attributes + attachments | 50,000–500,000 | 4–8 weeks |
| Large enterprise, multi-brand + voice recordings | 500,000+ | 6–12 weeks |
The bottleneck is almost always on the Gladly extraction side. At 10 requests per second, extracting 100,000 conversations with their items takes roughly 6–8 hours of sustained API calls — before factoring in attachment downloads. At S3 standard egress pricing, downloading 100,000 average-size support attachments (assume 500 KB average) costs roughly $4–5 in storage transfer; voice recordings at 2–5 MB each add meaningfully to that figure for large call centers.
Available Tooling
No commercial ETL platforms (Fivetran, Stitch, Airbyte) offer a native Gladly-to-HubSpot connector as of August 2025. This means extraction and transformation require custom API scripts or a migration service.
What exists:
- HubSpot Migration Partners — HubSpot's Solutions Partner program includes certified migration specialists. The HubSpot App Marketplace lists some data migration apps, though none cover Gladly specifically.
- HubSpot's own import tool — Handles CSV-based Contact and Ticket creation, but does not support Engagements, Associations, or historical attachments. Useful for small, email-only migrations where agents can manually triage.
- Trujay / Help Desk Migration — Third-party migration SaaS platforms support some helpdesk migrations but do not list Gladly as a supported source as of this writing. Verify current connector availability directly.
- Custom scripts — Python (requests, pandas) or Node.js are the most common choices. The code samples in this guide are starting points, not production-ready tools. At minimum, add retry logic with exponential backoff, structured logging, and a resumable checkpoint system before running against production data.
If your team cannot dedicate an engineer for 2–6 weeks depending on dataset size, a managed migration service is the practical alternative to building and maintaining custom tooling.
DIY vs. Managed Migration
Self-serve is viable when:
- Fewer than 10,000 conversations
- Email-only data (no voice, no social)
- No custom attributes requiring Custom Objects
- A dedicated engineer can commit 2–3 weeks
- You're comfortable with truncation risks on high-volume customers
- Data residency and compliance requirements are straightforward
A managed service makes sense when:
- 50,000+ conversations with multi-channel history
- Full attachment and voice recording migration required
- Custom Attributes need HubSpot Custom Objects
- You can't afford to miss truncated data on VIP customers
- GDPR/CCPA compliance review is required for the migration pipeline
- Zero downtime required during cutover
- No API engineering bandwidth on your team
The complexity scales fast when you introduce omnichannel history, hundreds of thousands of attachments, and strict uptime requirements. API rate limits force scripts to run for days, and a single uncaught exception can orphan thousands of messages. Silent truncation, bad identity joins, activity ordering drift, and cutovers that leave agents in two systems are engineering problems, not spreadsheet problems.
For other migration targets or related technical guides:
- Gladly to Zendesk — covers Zendesk's import API and ticket form mapping
- Gladly to Intercom — details the shift from Gladly's timeline to Intercom's discrete conversations
- HubSpot Service Hub Migration Checklist — preflight checklist before any HubSpot cutover
Frequently Asked Questions
- Can I export full conversation history from Gladly?
- Gladly's REST API caps at 100 conversations per customer and 1,000 items per conversation with no pagination. The Gladly-Limited-Data response header indicates truncation. Use the Export API with date-range filters to supplement, and contact Gladly Support for full exports on high-volume customers.
- What HubSpot Service Hub tier do I need for a Gladly migration?
- Professional ($90/seat/month) is the minimum for most teams — it includes the Help Desk workspace, Knowledge Base, SLAs, and custom routing. Enterprise ($150/seat/month) is required only if you need Custom Objects to model Gladly's complex custom attributes.
- How long does a Gladly to HubSpot migration take?
- For accounts with under 50,000 conversations, expect 2–4 weeks. Enterprise migrations with attachments, voice recordings, and custom attributes typically take 4–8 weeks. The bottleneck is Gladly's extraction API rate limit of 10 requests per second.
- How do Gladly Conversations map to HubSpot Tickets?
- Each Gladly Conversation becomes one HubSpot Ticket. Conversation Items (emails, chats, SMS, calls, notes) become HubSpot Engagements associated to that Ticket. Since Gladly Conversations can span multiple channels, a single Ticket may contain mixed Engagement types.
- Can Gladly workflows and routing rules be migrated to HubSpot?
- No. Gladly Conversation Workflows, People Match routing, and Saved Views cannot be exported as executable config. Gladly can export rules as CSV for reference (as of June 2026), but they must be manually rebuilt in HubSpot using Workflows, Help Desk routing rules, and custom views.