Sync qualified HubSpot leads to a Google Ads audience daily
Every morning, refresh a Google Ads Customer Match list from HubSpot so paid campaigns retarget the right leads and stop wasting spend on the wrong ones.
Every weekday at 7:00am in my local timezone, sync my qualified HubSpot pipeline into a Google Ads Customer Match audience so my paid campaigns can retarget the right people and exclude the wrong ones. Post a short recap in Slack when it finishes.
Configuration I want to set once and reuse each run: (1) the HubSpot qualification rule, either a list of lifecycle stages (default: marketingqualifiedlead, salesqualifiedlead, opportunity) or a lead score threshold on the hubspotscore property; (2) the name of the Google Ads Customer Match user list to keep in sync (default: 'HubSpot Qualified Leads'); (3) the Slack channel for the recap (default: #growth).
Step 1 — Pull qualified contacts from HubSpot. Use HubSpot Search Contacts with a filter matching my configured qualification rule (lifecycle stage IN the configured stages, or hubspotscore >= the configured threshold). Request the email, firstname, lastname, and country properties, and paginate through all results. Only keep contacts that have a valid email.
Step 2 — Find or create the Google Ads Customer Match audience. Call Google Ads List Customer (User) Lists and look for a user list with the configured name. If none exists, call Create Customer Match User List to create one of type CRM_BASED with upload_key_type CONTACT_INFO and remember the resource name. Otherwise reuse the existing list's resource name.
Step 3 — Compute the diff. Read the current membership of the Customer Match list (via GAQL if needed) and compare it against the freshly pulled qualified set. Determine which SHA-256 hashed emails need to be added (new qualified leads not yet in the list) and which need to be removed (previously synced contacts that are no longer qualified). Normalize every email before hashing: lowercase, trim whitespace.
Step 4 — Reconcile the audience. Call Google Ads Add or Remove Members From Customer Match List once with the additions and once with the removals (or a single combined offline user data job — whichever the operation supports). Pass hashed_email values (lowercase hex SHA-256). Do NOT send raw emails. Skip the job entirely if both add and remove sets are empty.
Step 5 — Post the recap. Send a Slack Bot message to the configured channel summarizing the run: audience name, counts added, counts removed, total members in the list after the update, and the HubSpot rule used (e.g. 'lifecycle stage in MQL, SQL, Opportunity'). Keep the message short and skimmable, with a one-line headline and a bulleted breakdown. If the run was a no-op (nothing to add or remove), still post a brief 'no changes today' line so the team knows it ran.
Error handling: if Google Ads is not yet approved for Standard developer token access, if the Customer Match list is not eligible for uploads, or if HubSpot rate-limits me, post a Slack message describing the failure instead of silently failing. Do not partially update the audience — abort and report if anything mid-flow errors.
Additional information
What does this prompt do?
- Pulls your current qualified pipeline from HubSpot every morning, filtered by lifecycle stage (MQL, SQL, Opportunity) or a lead score threshold.
- Adds new qualified contacts to a Google Ads Customer Match audience and removes anyone who no longer meets the bar, so the list always reflects reality.
- Handles the security bits for you (emails are hashed before they leave HubSpot) and creates the audience on first run if it does not exist yet.
- Posts a short Slack recap each morning with the audience name and how many people were added or removed.
What do I need to use this?
- A HubSpot account with contacts tagged by lifecycle stage or lead score.
- A Google Ads account where you can build a Customer Match audience.
- A Slack workspace and a channel for the daily recap.
How can I customize it?
- Change which HubSpot lifecycle stages or lead score threshold defines a qualified lead.
- Rename the Customer Match audience or point the workflow at an existing one you already run campaigns against.
- Pick the Slack channel and the time of day the sync should run.
Frequently asked questions
Do my leads' email addresses get sent to Google in plain text?
What if the Google Ads audience does not exist yet?
Can I use this to exclude closed-won customers from prospecting campaigns?
How often does the audience refresh?
What happens if a contact is no longer qualified?
Related templates
Stop retargeting the wrong leads on Google.
Connect HubSpot, Google Ads, and Slack once, and Geni keeps your Customer Match audience in sync with your qualified pipeline every single morning.