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 pickSalesforce Integration— that license cannot grantView All Activitiesor per-object View All on Task and Event, which the integration needs. - Profile: clone the standard
Standard Userprofile (e.g. name itActivityPulse Integration Profile) and assign the clone. CloningStandard Usercarries over Read on Task and Event, which the permission set cannot grant when activity sharing isControlled by Parent. TheMinimum Access - Salesforceprofile 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.
- Setup → Permission Sets → New.
- Label:
ActivityPulse Integration(or similar). - License:
Salesforce. This field is not editable after creation, so pickSalesforceat creation time. Do not use the license-agnostic--None--option — it filters out the grants we need. - 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 Parentactivity-sharing model. - System Permissions — click Edit, tick
API EnabledandView All Users, save.View All Usersis how Salesforce grants cross-user read on theUserobject;Useritself 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, andView All Activitiesis 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
CaseCommentworks 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
Privaterather thanControlled by Parent, theView All Activitiessystem 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, tickView All Activitiesin 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/successas a placeholder. - OAuth Scopes: add
Manage user data via APIs (api).
Choose one authentication flow.
Option A — Client Credentials flow (recommended)
- Tick Enable Client Credentials Flow.
- 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.
- 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
- Generate an X.509 certificate and upload it under Use digital signatures.
- Copy the Consumer Key.
- Keep the matching private key (PEM) to enter into ActivityPulse.
- Pre-authorize the integration user for the app.
Step 3 — Configure the plugin in ActivityPulse
Open Data Sources → Salesforce → Configure and fill in:
| Field | Notes |
|---|---|
| Instance URL | Your 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.com — not .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 flow | Client Credentials or JWT Bearer. |
| Consumer key | From the Connected App / External Client App. |
| Consumer secret | Client Credentials flow only. |
| Run-as username | JWT Bearer flow only — the integration user. |
| Private key (PEM) | JWT Bearer flow only. |
| API version | Optional. Defaults to v66.0. |
| Include Chatter activity | Whether 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.Emailfield (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
UserFeedview rather than the genericFeedItemobject, because Salesforce rejects bareFeedItemqueries 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.