HubSpot Integration

How to get there: Go to Settings in the sidebar → Integrations tab (under Other) → HubSpot section.

Automatically pull customer data from HubSpot CRM to enrich user profiles with company name, MRR, LTV, plan type and lifecycle stage. Once users carry that data, you can use the Companies view and the MRR/LTV columns on posts to prioritize what your highest-value customers want.

Setup

  1. In HubSpot, create a Private App (Settings → Integrations → Private Apps → Create a private app)

  2. Under Scopes, tick the ones you need:

    Scope What it gives you in ProductLift
    crm.objects.contacts.read Matches HubSpot contacts to portal users by email and fills firstname, lastname, phone, lifecycle stage
    crm.objects.companies.read Fills customer_company_name from the associated Company object when the contact has no freeform company value. Falls back to the company's domain if the name field is empty (same behavior HubSpot itself shows on the contact card)
    crm.objects.deals.read Fills MRR, ARR, deal count and total deal amount (only when "Sync deals" is turned on)
  3. Copy the access token (starts with pat-na1-...)

  4. In ProductLift, go to Settings > Integrations, expand the HubSpot card

  5. Paste the token and click Test connection. A green check means HubSpot accepted the token.

  6. Click Save, then Sync now

The first sync pages through all contacts (100 per page) and self-redispatches in the background until done, so large HubSpot portals do not block the request.

Matching

ProductLift matches HubSpot contacts to portal users by email address. Contacts whose email does not exist in the portal are skipped, no new users are created.

For each match, the integration writes:

  • customer_company_name from the contact's HubSpot company property. If empty, falls back to the associated Company's name, then its domain (matches how HubSpot displays the company on a contact)
  • customer_mrr / customer_ltv if you map them in the HubSpot card
  • customer_plan_type from the lifecycle stage by default
  • A link row in integration_links so re-syncs are idempotent

What you get after a sync

  • All Posts page: the Combined MRR column shows the revenue weight behind each post (sum of voter MRR)
  • Companies page (Users → Companies button): one row per company with combined MRR/LTV, votes, last activity, plus a detail modal showing the company's top voted posts
  • Filters on posts: filter by customer_mrr range to surface what enterprise customers are asking for

Sync frequency

Syncs are manual only, on demand. There is no scheduled job that pulls HubSpot in the background. You sync when you want a refresh:

  • Full sync: click Sync now in the HubSpot card on Settings → Integrations. This pages through every contact in your HubSpot portal, matches by email, and updates customer_* fields on existing users. Safe to run as often as you like; it is idempotent.
  • Single-user sync: on a user's detail page (Users → click a user), click Sync from HubSpot. This refetches just that one contact. Use this when a customer just upgraded in HubSpot and you want their MRR/plan reflected immediately without waiting for a full sync.

The HubSpot card shows the last full sync time and any error from the most recent run. If a sync fails (bad token, scope missing), the error is shown inline so you can fix and retry without digging through logs.

Troubleshooting

Company name is empty after sync. The contact's freeform company property is empty in HubSpot and your Private App is missing crm.objects.companies.read. Add the scope, copy the rotated token back into ProductLift, and click Sync now (or Sync from HubSpot on the user page).

Test connection passes but sync errors. Most often a scope mismatch: the connection test only checks contacts read access. If you turned on "Sync deals", the token also needs crm.objects.deals.read.

A user shows up in HubSpot but not after sync. Matching is by email and is case-insensitive. Confirm the email in HubSpot matches the email on the ProductLift user record exactly (no plus-aliases, no whitespace). New contacts that have no matching portal user are skipped, not created.

Removing the integration

Click Disable in the HubSpot card. The encrypted token is removed and no further syncs run. Existing customer_* fields on users remain. Re-enable later by pasting the token again.