Kingdom of KumarBack to home

Fix · HubSpot + Zoom

Get Zoom webinar poll answers, registration questions and per-session attendance into HubSpot

By Mayank Raj · Kingdom of Kumar · Published 5 November 2026

The problem

“Poll and survey answers never make it into HubSpot”

Abenezer Melkamu, How are you handling Zoom webinar data in HubSpot today? (HubSpot Community, 28 Oct 2026)

Same problem elsewhere: Zapier community: syncing attendance and poll answers · r/hubspot: workaround for data that doesn't sync

Short answer: Run a small sync after each webinar occurrence. Pull registrant answers from GET /v2/webinars/{id}/registrants (custom_questions), attendance from GET /v2/report/webinars/{uuid}/participants, and polls from GET /v2/past_webinars/{uuid}/polls, then batch update existing HubSpot contacts matched by email. Leave attendees without an email in a review file instead of guessing.

The usual workaround is exporting CSVs from Zoom and importing them by hand after every webinar. The data is all in the Zoom API, keyed by the occurrence UUID, so a recurring webinar can be split by session. The script plans every update as a CSV first, and only writes to HubSpot when you add --apply.

Download

Everything is free to use. The scripts are Python 3 standard library only and default to read-only or dry-run. Each one ships with an offline test on sample data.

Step by step

1. Create the Zoom app

In the Zoom App Marketplace create a Server-to-Server OAuth app with read scopes for webinars and reports. Set ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID and ZOOM_CLIENT_SECRET as environment variables.

2. Create the HubSpot private app

Give it contacts read and write scopes and set HUBSPOT_TOKEN.

3. Pick the occurrence

For a recurring webinar, pass --occurrence-uuid. Without it, the script lists past instances from GET /v2/past_webinars/{id}/instances. UUIDs that start with / or contain // are double URL-encoded for you.

4. Dry run

Nothing is written. You get out/planned_updates.csv, out/unmatched.csv and out/properties_to_create.csv.

python3 zoom_hubspot_sync.py --webinar-id 123456789 --occurrence-uuid 'THE_UUID'

5. Create the properties

Create the contact properties listed in properties_to_create.csv: zoom_attended, zoom_minutes_attended, zoom_last_webinar_id, zoom_last_webinar_date, plus one zoom_q_ property per registration question and one zoom_poll_ property per poll question.

6. Check the review file

Someone who joined twice is merged into one row with total minutes. People who joined without an email go to unmatched.csv for a person to look at.

7. Write to HubSpot

Re-run with --apply. Contacts are found with batch/read by email and updated with batch/update. New contacts are only created if you also pass --create-missing, which stops every webinar from filling the CRM with junk contacts.

What this does not cover

Want this done for you?

Kingdom of Kumar runs it for $500/month, first automation live in 48 hours. Claude + Grok Bot + $500/month (my fee). Email me the task you hate doing every week.

Email me the task

Related: HubSpot cleanup · All fixes