Perfcopilot

CRM (Salesforce / HubSpot)

CRM signals are the primary evidence source for revenue-facing roles — AEs, SDRs, and CSMs. PerfCopilot pulls closed deals, renewals, and upsells from your connected CRM and includes them in reviews. Headline metric: deals_won. Supports Salesforce and HubSpot; one CRM per org.

What we pull

Three signal types per employee, fetched in parallel:

  • Closed deals (deal_won / deal_lost) — opportunities owned by the rep that closed in the cycle window. Fields: deal name, outcome (won/lost), amount, close date, pipeline, deal type.
  • Renewals (renewal_closed) — deals flagged as existing-business renewals. Tracks ARR retained. Fields: deal name, outcome, arr_value, close date.
  • Upsells (upsell_closed) — expansion revenue events. Fields: deal name, amount, close date.

Each deal lands as a separate RawSignal row, timestamped by its close_date.

Connecting

CRM is an org-wide install. Only one CRM can be active at a time.

Salesforce

  1. Go to /admin?tab=integrations, find the Salesforce card.
  2. Click Connect and complete the Salesforce OAuth flow. PerfCopilot requests read-only access to Opportunity objects.
  3. In the card's configuration, set the instance URL for your org (e.g. https://acme.my.salesforce.com). This is stored in extra_config.instance_url and used for all SOQL queries.
  4. Map each employee's Salesforce OwnerId (18-character Salesforce ID) in the unmapped-employees list.

The Salesforce adapter queries:

SELECT Id, Name, StageName, Amount, CloseDate, Type
FROM Opportunity
WHERE OwnerId = '<id>' AND IsClosed = true AND CloseDate >= <start>

Renewals are filtered by Type = 'Existing Customer - Renewal'; upsells by Type = 'Existing Customer - Upgrade' and StageName = 'Closed Won'.

HubSpot

  1. Go to /admin?tab=integrations, find the HubSpot card.
  2. Click Connect and authorize PerfCopilot via HubSpot's OAuth. Required scopes: crm.objects.deals.read.
  3. Map each employee's HubSpot owner ID (numeric, visible in HubSpot → Settings → Users or via the Owners API).

The HubSpot adapter filters by hubspot_owner_id, closedate >= <since>, and dealstage in [closedwon, closedlost]. Renewals and upsells use property + value pairs that you configure on the HubSpot integration card — defaults are dealtype = existingbusiness for renewals and deal_source = upsell for upsells.

HubSpot upsell + renewal classification is configurable. HubSpot has no native "upsell" classification, and most teams use a custom property like Deal classification with values like expansion / cross-sell / renewal. The HubSpot card on /admin?tab=integrations exposes four fields — Upsell property name, Upsell property value, Renewal property name, Renewal property value — so you can wire the filter to whatever convention your team uses. Defaults work for HubSpot orgs that happen to use the literal deal_source / dealtype properties out of the box; most need to override at least the upsell pair.

What hits a review

[CRM DATA]
deals_won:         8
deals_lost:        3
total_arr_won:     142000
renewals_closed:   4
renewals_retained: 3
upsells_closed:    2
upsell_arr:        18500
crm:               salesforce

Plus cohort medians for deals_won in the [BASELINES] block, so the AI can assess performance against the team.

Troubleshooting

"CRM signals show zero deals"

  1. OwnerId / HubSpot owner ID not mapped. The ingester filters strictly by owner. An unmapped employee returns nothing. Check the CRM card for unmapped employees.
  2. Salesforce instance URL missing. Without instance_url in the card config, SOQL queries have no target. The ingester will error silently if this field is blank.
  3. Deals closed before the cycle start. CRM queries scope by CloseDate >= cycle_start. If your cycle started Monday and all deals closed Friday, they're in the previous cycle. Verify dates on a deal in Salesforce/HubSpot directly.
  4. OAuth token expired. CRM tokens can expire or be revoked when an admin password changes or the connected app is removed. Reconnect from the integration card.

"Renewals or upsells are missing"

  • Salesforce: Renewal filtering uses Type = 'Existing Customer - Renewal'. If your org uses a different opportunity type name, these won't pull. Check the Type field values in Salesforce and update accordingly (this currently requires a code change — contact support).
  • HubSpot: Upsell filtering uses the property + value you configured on the integration card (defaults deal_source = upsell). If counts are zero, double-check the HubSpot card's Upsell property name and Upsell property value fields against your actual HubSpot deal data — most teams need to override at least one. Same for renewals if you don't use HubSpot's default dealtype = existingbusiness convention.

"Deal amounts look wrong"

Salesforce amounts are read from the Amount field; HubSpot from amount. If your reps use a different field for ARR (e.g. Annual_Contract_Value__c), the numbers PerfCopilot shows won't match your pipeline reports.

Privacy notes

  • We pull deal names, amounts, stages, and close dates. No contact or company records.
  • Deal names may contain customer names. These are stored in raw_signals.payload and visible to managers.
  • CRM signals are only useful for roles that own deals. Adding CRM signals to an IC engineer's review will contribute zero data and is not recommended. Weight CRM signals to zero in the skill preset for non-revenue roles.