Every recorded call, automatically archived and surfaced as a rich HubSpot note — with AI summaries, action items, recordings, and the right associations — within minutes of the call ending.
Gong generates genuinely useful AI output after every call — summaries, action items, key points, tracked keywords, meeting outlines. The problem is it stays in Gong. This recipe pipes all of that into HubSpot automatically, so reps work from one place instead of two.
But the HubSpot sync is only half the story. The other half is data ownership. Gong stores all call recordings on its own infrastructure, which means if you ever leave Gong — for any reason — you lose access to every historical call. This recipe also archives every recording to Storj and Google Drive before writing the HubSpot note, so the organization retains a permanent copy of all media that no vendor contract can touch.
The three components serve three distinct purposes, and it's worth being explicit about that:
There are two layers to this dish. The first is a cloud pipeline: Gong webhooks → GCP Pub/Sub → Cloud Functions → Storj + Google Drive + HubSpot. The second is a local CLI for backfilling historical calls, debugging, and searching the archive. Both use the same shared library under the hood.
It is written in Python, runs on GCP, and touches four external APIs. There are more moving parts than a typical integration — but the setup scripts do most of the heavy lifting, and once it's deployed, it runs entirely without intervention.
| Difficulty | Advanced |
| Prep Time | ~45 mins (credentials + GCP setup) |
| Cook Time | ~1 hour (deploy + configure + backfill) |
| Serves | Sales and success teams running Gong alongside HubSpot |
| Allergens | Requires Gong Admin access to create API keys and webhooks. Google Drive is optional but recommended. |
Accounts & Access
Environment
gcloud CLI installed and authenticatedpip / venvFrom the pantry (provided in this repo)
local/backfill.py) — 10+ subcommands for backfill, preview, archive search, and diagnosticsBefore deploying anything, get your credentials together. There are four sources:
1. Gong API key
Gong Admin → Company Settings → API → Create API Key
You need: Access Key, Access Key Secret, and the Public Key (used to verify signed webhook JWTs). Required scopes: api:calls:read:basic, api:calls:read:extensive, api:calls:read:transcript, api:calls:read:media-url, api:stats:scorecards.
2. HubSpot Private App token
Settings → Integrations → Private Apps → Create
Required scopes: contacts and companies (read/write), deals (read), owners (read), notes (write).
3. Storj S3 credentials
Storj Console → Access → S3 Credentials
Note the Access Key, Secret Key, and Endpoint. For permanent playback links, also generate a linkshare key:
uplink share --register --public --readonly sj://your-bucket/
4. Google Drive service account (optional)
GCP Console → IAM → Service Accounts → Create → JSON key
Share your Shared Drive with the service account email (Editor access) and note the Shared Drive ID from the URL.
Once you have everything, populate your .env file:
cp .env.example .env # Edit .env with your values # Validate everything is working before deploying python local/validate_credentials.py
Deploy three Cloud Functions and all supporting infrastructure in two commands.
Set up GCP secrets:
bash cloud/scripts/setup-secrets.sh YOUR_GCP_PROJECT_ID
This reads your .env values, shows you each one masked, and loads them into GCP Secret Manager. You can press Enter to accept each value or type a new one. All secrets are prefixed gong- to avoid collisions.
Deploy Cloud Functions:
bash cloud/scripts/deploy.sh YOUR_GCP_PROJECT_ID us-central1
This deploys three functions, creates the service account, enables required APIs, creates the Pub/Sub topic, and prints the webhook URL you'll need next.
| Function | Trigger | What it does |
|---|---|---|
gong-webhook-receiver |
HTTP (public) | Validates Gong JWT, queues event to Pub/Sub |
gong-call-processor |
Pub/Sub | Archives call, creates HubSpot note |
gong-backfill |
HTTP (authenticated) | Bulk backfill for a date range |
Configure the Gong webhook:
Gong Admin → Company Settings → API → Create Webhook Subscription
Set the URL to the webhook URL from the deploy script. Use Signed JWT header authentication and subscribe to CALL_ANALYSIS_READY events.
Chef's note: The webhook receiver and call processor are deliberately separate functions. Gong requires a fast HTTP response — the receiver validates and queues immediately, then the processor handles the slower archive + note flow without risking a webhook timeout.
Catch up on past calls before real-time sync takes over.
# See what would be processed (no changes made) python local/backfill.py backfill --days 30 --dry-run # Run the full backfill python local/backfill.py backfill --days 30
The backfill archives each call to Storj and Google Drive, creates a HubSpot note, skips duplicates automatically, and syncs the SQLite index to Storj every 10 calls.
Preview a single note before committing:
python local/backfill.py preview-note CALL_ID
Renders the HTML note to a file so you can inspect exactly what will appear in HubSpot before running anything.
gong-call-id:{id} signature in the body. Backfills and re-runs check for this before creating anythingpython local/backfill.py archive-search "acme corp" --type company
Once real-time sync is live, the most useful follow-on is setting up HubSpot workflow automations that trigger off new Gong notes — for example, assigning follow-up tasks when a note containing specific tracked keywords is created, or alerting a manager when a call with a key account is logged. The notes are standard HubSpot notes, so any existing workflow logic can be applied to them.
The four APIs this integration depends on (Gong, HubSpot, Storj, Google Drive) all version independently. Gong in particular occasionally changes how AI output fields are structured. If notes start appearing with missing sections, check the Gong API changelog and compare against the field mappings in src/services/note_formatter.py — that's where all Gong response fields are mapped to note content.
Complete source code, setup scripts, and the local CLI are in the GitHub repository:
Part of a professional portfolio — view the project brief