Salesforce Setup

ActivityPulse connects to Salesforce through an OAuth Connected App (or External Client App in newer orgs) and reads activity with the Salesforce REST API.

Prerequisites

  • A Salesforce edition with REST API access: Enterprise, Unlimited, Performance, or Developer. Professional Edition needs the API add-on; lower editions do not expose the API.
  • A Salesforce administrator who can create users, permission sets, and OAuth apps.
  • A spare standard Salesforce user license for the integration user. The lightweight Salesforce Integration license, although marketed for API use, cannot grant the cross-user activity visibility this integration needs, so it is not suitable here.

Step 1 — Create a dedicated integration user

ActivityPulse authenticates as a single Salesforce user that exists only as an OAuth identity — it never signs in interactively.

1.1 Confirm your activity sharing model

Open Setup → Sharing Settings and find the Activity row in the Organization-Wide Defaults table. The most common (and recommended) value is Controlled by Parent, meaning activity visibility follows the parent record (Lead, Opportunity, Case, Account, Contact). The rest of this guide assumes that model — it shapes which permissions are grantable and which are not. If your org uses Private activity sharing instead, see the note at the bottom of this step.

1.2 Create the user

In Setup → Users → New User:

  • User License: Salesforce. Do not pick Salesforce Integration — that license cannot grant View All Activities or per-object View All on Task and Event, which the integration needs.
  • Profile: clone the standard Standard User profile (e.g. name it ActivityPulse Integration Profile) and assign the clone. Cloning Standard User carries over Read on Task and Event, which the permission set cannot grant when activity sharing is Controlled by Parent. The Minimum Access - Salesforce profile is not a fit — it omits Task and Event Read, and Salesforce blocks cloning it in most orgs.
  • Save the user.

(Optional, defense in depth) Edit the cloned profile and revoke Create / Edit / Delete on the standard objects so it is effectively read-only. This is not strictly required, because the integration user never reaches the UI and ActivityPulse itself only reads.

1.3 Create a permission set

The permission set layers cross-user visibility on top of the profile.

  1. Setup → Permission Sets → New.
  2. Label: ActivityPulse Integration (or similar).
  3. License: Salesforce. This field is not editable after creation, so pick Salesforce at creation time. Do not use the license-agnostic --None-- option — it filters out the grants we need.
  4. Save → open the permission set.

In the permission set:

  • Object Settings — for each of Opportunity, Lead, Case, Account, Contact, click the object name → Edit → tick Read and View All Records under Object Permissions → Save. These parent-record grants surface every Task and Event in the org to the integration user through the Controlled by Parent activity-sharing model.
  • System Permissions — click Edit, tick API Enabled and View All Users, save. View All Users is how Salesforce grants cross-user read on the User object; User itself is not listed under Object Settings on most permission-set licenses, and this System Permission is the canonical replacement.

Do not configure Task, Event, Case Comment, Feed Item, or Feed Comment in Object Settings:

  • Task / Event — when activity OWD is Controlled by Parent, Object Permissions on these are intentionally not grantable through a permission set (the column shows -- in the Object Settings list, and View All Activities is hidden from System Permissions). Read comes from the cloned profile; cross-user visibility comes from the parent-record grants above.
  • Case Comment — inherits from the parent Case; querying CaseComment works as soon as Case is readable.
  • Feed Item / Feed Comment — Chatter feed visibility follows the parent record automatically when Chatter is enabled (Setup → Feature Settings → Chatter → Chatter Settings).

Avoid the broad View All Data system permission — it exposes every standard object in the org and exceeds what ActivityPulse needs.

1.4 Assign the permission set

In the permission set: Manage Assignments → Add Assignments → select the integration user.

Note for Private activity sharing: if your Activity OWD is Private rather than Controlled by Parent, the View All Activities system permission becomes grantable on the permission set, and per-object View All Records on Task and Event becomes configurable in Object Settings. In that case, tick View All Activities in System Permissions and ignore the Task/Event Object Permission notes above.

Step 2 — Create the OAuth app

Salesforce is migrating from Connected Apps to External Client Apps. Newer orgs only expose External Client Apps; older orgs still have Connected Apps. Both produce the same OAuth credentials (Consumer Key + Consumer Secret) and either works.

Use Setup → Quick Find to find whichever your org provides:

  • Search App Manager → click New Connected App at the top-right of the results page; or
  • Search External Client App → click New External Client App.

Common settings (both app types)

  • Name / API Name: e.g. ActivityPulse.
  • Contact Email: yours.
  • Distribution State (External Client App only): Local.
  • Enable OAuth Settings / Enable OAuth: on.
  • Callback URL: required even though Client Credentials does not use it. Use https://login.salesforce.com/services/oauth2/success as a placeholder.
  • OAuth Scopes: add Manage user data via APIs (api).

Choose one authentication flow.

  1. Tick Enable Client Credentials Flow.
  2. Open the app’s Policies (External Client App) or Manage page (Connected App). Set the Run As user to the integration user from Step 1.
  3. Open Manage Consumer Details (Connected App) or the credentials section of the app (External Client App). Copy the Consumer Key and Consumer Secret.

Option B — JWT Bearer flow

  1. Generate an X.509 certificate and upload it under Use digital signatures.
  2. Copy the Consumer Key.
  3. Keep the matching private key (PEM) to enter into ActivityPulse.
  4. Pre-authorize the integration user for the app.

Step 3 — Configure the plugin in ActivityPulse

Open Data Sources → Salesforce → Configure and fill in:

FieldNotes
Instance URLYour org’s My Domain URL, e.g. https://your-domain.my.salesforce.com. Use the sandbox host for sandboxes (e.g. https://your-domain--sandbox.sandbox.my.salesforce.com). Must end in .my.salesforce.comnot .my.salesforce-setup.com, which is the Setup UI host and refuses OAuth token requests with invalid_grant: request not supported on this domain.
Authentication flowClient Credentials or JWT Bearer.
Consumer keyFrom the Connected App / External Client App.
Consumer secretClient Credentials flow only.
Run-as usernameJWT Bearer flow only — the integration user.
Private key (PEM)JWT Bearer flow only.
API versionOptional. Defaults to v66.0.
Include Chatter activityWhether to collect Chatter posts and comments.
Completed-item lookback (days)How far back to look for records that were closed or completed. Defaults to 30, accepts 0–90. See below.

Saving the configuration runs a live check against your org and reports the remaining daily API budget.

Completed-item lookback

ActivityPulse takes a daily snapshot of the cases, opportunities, tasks and meetings currently assigned to each teammate. A snapshot of open work alone cannot tell you what finished: an item that stops appearing might have been closed, reassigned, unassigned — or simply missed by a failed sync.

This setting is how long a completion stays visible to the sync. Each run also asks for cases, opportunities and tasks closed within the last N days, and for meetings that ended in that window, so a completion is recorded from what Salesforce reports rather than guessed from the item’s absence.

  • Defaults to 30 days, accepts 0–90.
  • It only has to exceed your sync interval, not the longest period you report on. Once a completion is captured in any snapshot it stays on the item.
  • Set it to 0 to switch the extra query off. Completions are then never observed, so finished items stop being labeled as resolved and simply show the last state that was seen, dated.

A meeting carries no status of its own, so ActivityPulse supplies one: an upcoming meeting shows Scheduled, and one that has ended shows Completed.

Step 4 — Map teammates to Salesforce users

Each teammate in ActivityPulse needs a Salesforce identifier in their External IDs so the plugin can attribute activity to the right person.

For the Salesforce source you may enter either of these values:

  • The Salesforce Username (e.g. alice@acme.com.sandbox), or
  • The user’s Email as it appears on the standard User.Email field (e.g. alice@acme.com).

The plugin matches both fields when resolving identifiers, and the match is case-insensitive on both sides. You do not need to pick one consistently across teammates — mix and match as is convenient.

Sandboxes: Salesforce appends .<sandbox-name> to every user’s Username when an org is refreshed (e.g. alice@acme.com becomes alice@acme.com.fullcopy). The Email field is usually left unchanged. If you sync from a sandbox, prefer storing the Email value so you do not have to re-edit every teammate’s external ID after each sandbox refresh.

If ActivityPulse cannot match a teammate to any Salesforce user, the plugin logs a warning with the exact external_id values that failed to resolve — check the backend logs at Logs in the admin UI if a teammate appears to be producing no Salesforce activity.

What ActivityPulse collects

  • Activities — logged calls and emails, completed to-dos, and meetings.
  • Accounts — creation, updates, and owner changes.
  • Opportunities — creation, updates, stage changes, wins, and losses.
  • Leads — creation, updates, status changes, and conversions.
  • Cases — creation, updates, status changes, closures, and comments.
  • Chatter — feed posts on a tracked user’s profile feed, and comments on those same posts. The plugin queries the per-user UserFeed view rather than the generic FeedItem object, because Salesforce rejects bare FeedItem queries from non-admin integration users with “Implementation restriction: FeedItem requires a filter by Id”. Posts authored on record feeds (Account, Opportunity, Case, Lead) or in group feeds are intentionally not collected.

Account owner-change events, and Lead and Case status-change history, are available only when your org has field history tracking enabled with the relevant field (Account Owner, Lead Status, Case Status) tracked. Without it, account, lead, and case updates are still collected, just without the precise old/new values from history.

Notes

  • ActivityPulse only reads data; it never writes to Salesforce.
  • All API calls count against your org’s shared daily API limit. ActivityPulse polls incrementally to stay frugal, but a very short fetch interval on a busy org can still consume noticeable budget.
  • The “Login” link next to a user in Setup → Users is admin impersonation (“Login As”), useful for one-off troubleshooting. It is not how the integration authenticates — the integration user should never sign in interactively in normal operation.