Gong is a revenue intelligence platform: AI call analysis, transcription, talk ratio, sentiment, and recommendations based on winning call patterns. The native HubSpot + Gong integration exists in the HubSpot App Marketplace — Gong is installed as an App, calls appear in the contact Timeline. This sounds convenient. In practice, the integration only solves the simplest task — call visibility in HubSpot. Critical context — AI insights, Deal attribution, property updates based on conversation outcomes — the native integration does not handle any of that. Here is a concrete breakdown of what is lost and how to build it correctly.
What the Native Integration Can and Cannot Do
Can:
— Add a call record to the contact Timeline (caller, duration, link to Gong)
— Show the transcript in Gong when clicking from HubSpot (redirects to the Gong site)
— Sync contacts from HubSpot into Gong (for recognizing who is calling)
Cannot:
— Attribute a call to a specific Deal (only to Contact / Company)
— Pass AI insights (talk ratio, key topics, next steps) as HubSpot Deal properties
— Update Deal Stage based on call outcomes
— Create a HubSpot Task “Follow-up” based on Gong analysis results
— Pass the call score (Gong Deal Score) into HubSpot for segmentation
What the Business Specifically Loses
1. Call attribution to a deal.
The native integration records the call against a Contact. But the call happened in the context of a specific Deal. Revenue Ops cannot answer: “How many calls were made on deal X and which of them resulted in pipeline movement?” The data exists in Gong; in HubSpot it is not attributed.
2. AI insights remain in Gong, not in the CRM.
Gong generates the following after each call: talk ratio, longest monologue, topics (pricing, competition, timeline), key moments. All of this is only available in the Gong UI. Deal properties in HubSpot are empty or filled in manually based on what the manager decided to write down.
3. Deal Score does not influence prioritization in HubSpot.
Gong Deal Score is a prediction of deal close probability based on call patterns. The native integration does not pass this score to HubSpot. The manager sees the score in Gong; in HubSpot it is absent. Pipeline reports in HubSpot do not account for Gong data.
4. Next Steps from calls do not become HubSpot Tasks.
Gong AI extracts Next Steps from the transcript (“Send proposal by Friday”, “Organize a demo for the technical team”). The native integration does not create Tasks in HubSpot for these Next Steps — they stay in Gong and get forgotten.
The Right Architecture: Gong Webhooks + Engagements API
Gong call ended -> Gong Webhook -> Python handler
-> HubSpot Engagements API (create Engagement: Call)
-> HubSpot CRM API (update Deal properties)
-> HubSpot Tasks API (create Task from next steps)
Step 1: Subscribe to the Gong Webhook
Gong Webhooks are configured via the Gong API: POST https://api.gong.io/v2/settings/webhooks/register.
import requests
from requests.auth import HTTPBasicAuth
import hmac, hashlib
GONG_ACCESS_KEY = "your_access_key"
GONG_ACCESS_SECRET = "your_access_secret"
GONG_AUTH = HTTPBasicAuth(GONG_ACCESS_KEY, GONG_ACCESS_SECRET)
GONG_BASE = "https://api.gong.io/v2"
HS_TOKEN = "your_hubspot_private_app_token"
HS_BASE = "https://api.hubapi.com"
HS_HDRS = {
"Authorization": f"Bearer {HS_TOKEN}",
"Content-Type": "application/json",
}
def register_gong_webhook(callback_url: str):
payload = {
"url": callback_url,
"secret": "your_webhook_signing_secret",
"events": ["call.processed"],
}
resp = requests.post(
f"{GONG_BASE}/settings/webhooks/register",
auth=GONG_AUTH,
json=payload,
)
resp.raise_for_status()
return resp.json()
Step 2: Retrieve Call Data from Gong
def get_gong_call_details(call_id: str) -> dict:
resp = requests.get(
f"{GONG_BASE}/calls/{call_id}",
auth=GONG_AUTH,
)
resp.raise_for_status()
return resp.json().get("call", {})
def get_gong_call_insights(call_id: str) -> dict:
resp = requests.get(
f"{GONG_BASE}/calls/{call_id}/extensive",
auth=GONG_AUTH,
)
resp.raise_for_status()
data = resp.json()
result = {}
for section in data.get("contentInsights", []):
result[section["insightType"]] = section.get("insights", [])
return result
Step 3: Create an Engagement in HubSpot + Update the Deal
def create_hubspot_call_engagement(deal_id: str, contact_id: str,
call_data: dict) -> dict:
duration_ms = call_data.get("duration", 0) * 1000
recording_url = call_data.get("url", "")
title = call_data.get("title", "Gong Call")
payload = {
"engagement": {
"type": "CALL",
"timestamp": call_data.get("started", 0) * 1000,
"active": True,
},
"associations": {
"dealIds": [deal_id],
"contactIds": [contact_id],
},
"metadata": {
"body": f"Gong recording: {recording_url}",
"durationMilliseconds": duration_ms,
"fromNumber": call_data.get("callerPhoneNumber", ""),
"toNumber": call_data.get("calleePhoneNumber", ""),
"status": "COMPLETED",
"title": title,
"recordingUrl": recording_url,
},
}
resp = requests.post(
f"{HS_BASE}/engagements/v1/engagements",
headers=HS_HDRS,
json=payload,
)
resp.raise_for_status()
return resp.json()
def update_deal_with_gong_insights(deal_id: str, insights: dict):
topics = insights.get("Highlights", [])
topics_str = ", ".join([t.get("text", "") for t in topics[:5]])
props = {
"gong_last_call_date": "",
"gong_key_topics": topics_str,
}
resp = requests.patch(
f"{HS_BASE}/crm/v3/objects/deals/{deal_id}",
headers=HS_HDRS,
json={"properties": props},
)
resp.raise_for_status()
Step 4: Create Tasks from Next Steps
def create_hubspot_tasks_from_next_steps(deal_id: str,
next_steps: list, owner_id: str):
for step in next_steps[:3]:
task_text = step.get("text", "")
if not task_text:
continue
payload = {
"engagement": {"type": "TASK", "timestamp": None, "active": True},
"associations": {"dealIds": [deal_id]},
"metadata": {
"body": f"Gong Next Step: {task_text}",
"status": "NOT_STARTED",
"forObjectType": "DEAL",
},
}
requests.post(f"{HS_BASE}/engagements/v1/engagements",
headers=HS_HDRS, json=payload)
@app.route("/webhooks/gong", methods=["POST"])
def gong_webhook():
payload = request.json
event = payload.get("eventType")
call_id = payload.get("callId", "")
if event != "call.processed":
return "", 200
call = get_gong_call_details(call_id)
insights = get_gong_call_insights(call_id)
email = call.get("parties", [{}])[0].get("emailAddress", "")
deal_id = find_hubspot_deal_by_email(email)
contact_id = find_hubspot_contact_by_email(email)
if deal_id:
create_hubspot_call_engagement(deal_id, contact_id, call)
update_deal_with_gong_insights(deal_id, insights)
next_steps = insights.get("NextSteps", [])
if next_steps:
create_hubspot_tasks_from_next_steps(deal_id, next_steps, "")
return "", 200
Real-World Case
B2B SaaS (US, 25 sales managers, HubSpot + Gong):
- With native integration: RevOps tried to correlate Gong data (deal score, topics) with the HubSpot pipeline manually — weekly export from Gong -> Excel -> HubSpot import. 3–4 hours per week. Deal Score in Gong was 85% for 12 deals; in HubSpot pipeline they remained with “baseline” close probability.
- After custom integration:
call.processed-> Engagement on Deal -> Deal properties updated (key topics, talk ratio). HubSpot Reports can now filter bygong_key_topics = "pricing"— showing which deals are in the pricing discussion stage. Next Steps -> Tasks -> managers see the task queue in HubSpot without switching to Gong.
Who This Is Relevant For
- RevOps teams where Gong Deal Score is needed for pipeline review in HubSpot
- Companies with 10+ sales reps where manual Gong -> HubSpot sync takes hours per week
- Heads of Sales who need reports on “which topics most commonly stall deals” — the data is in Gong, it needs to be in HubSpot
- Companies where Next Steps from calls get forgotten because they only live in Gong
Frequently Asked Questions
Does the Gong API require special access?
Gong API (api.gong.io) is not public in the open-signup sense. Obtaining API credentials requires submitting a request through Gong Support or being an enterprise client with API access in the plan. Access Key + Secret are issued via Gong -> Company Settings -> Ecosystem -> API. Verify that API access is included in your Gong contract.
HubSpot Engagements API v1 vs v2 — which one to use?
Engagements v1 (/engagements/v1/engagements) — the older endpoint, still works, supports type CALL with recordingUrl. CRM API v3 (/crm/v3/objects/calls) — newer, stricter typing. For recording calls with a recording URL, Engagements v1 is recommended — it supports all metadata fields including the recording link.
How do you find a HubSpot Deal by email from Gong?
POST /crm/v3/objects/contacts/search with filter {propertyName: "email", operator: "EQ", value: email} -> get contact_id -> GET /crm/v3/objects/contacts/{id}/associations/deals -> get deal_id. If the contact has multiple deals — select the last active one by closedate or hs_lastmodifieddate.
Can the native HubSpot + Gong integration run alongside the custom one?
Depends on the setup. If the native integration also records calls in the Timeline — there will be duplicates (native Activity + custom Engagement). The recommendation is to disable the native Gong -> HubSpot call sync (Gong -> Settings -> Integrations -> HubSpot -> disable call activity sync) and keep only the custom webhook. Contact sync can still be done through the native integration — this does not conflict.
Summary
- Native integration: calls in the contact Timeline, no Deal attribution, no AI insights
- The right path: Gong Webhook
call.processed-> HubSpot Engagements API (with Deal association) - AI insights -> Deal properties (custom): key topics, talk ratio, Gong deal score
- Next Steps from transcript -> HubSpot Tasks -> managers see the task queue without switching to Gong
- Disable the native integration (call sync) — keep only contacts sync
If you have HubSpot + Gong and RevOps is spending time manually syncing data between systems — describe which fields are needed in HubSpot. Exceltic.dev will configure a two-way integration via Gong Webhooks.