Salesforce Loader
The Salesforce loader pulls data from your Salesforce org into your data warehouse using the Salesforce REST API. It supports incremental sync via Salesforce’s SystemModstamp field and handles both standard and custom objects.
Prerequisites
- A Salesforce org (Production, Sandbox, or Developer Edition)
- A Salesforce user with API access (the “API Enabled” permission must be active)
- A connected Warehouse (target warehouse) with write permissions on the target schema
Authentication
The Salesforce loader uses OAuth 2.0 for authentication.
OAuth 2.0 Setup
- In SignalSmith, click Add Loader and select Salesforce
- Click Connect with Salesforce
- You’ll be redirected to the Salesforce login page
- Log in with your Salesforce credentials and click Allow to grant SignalSmith access
- You’ll be redirected back to SignalSmith with the connection established
SignalSmith requests the following OAuth scopes:
| Scope | Purpose |
|---|---|
api | Access Salesforce REST API |
refresh_token | Maintain a long-lived connection without re-authenticating |
offline_access | Refresh tokens when the access token expires |
SignalSmith automatically refreshes the access token before it expires. If the refresh token is revoked (e.g., user password reset, admin action), you’ll need to re-authenticate.
Sandbox Connections
To connect to a Salesforce Sandbox, toggle the Sandbox option before clicking “Connect.” This directs the OAuth flow to test.salesforce.com instead of login.salesforce.com.
Available Objects
The Salesforce loader can sync any standard or custom object accessible to the authenticated user. The most commonly used objects are:
| Object | API Name | Description | Default Sync Mode |
|---|---|---|---|
| Contact | Contact | Individual people associated with accounts | Incremental |
| Lead | Lead | Prospective customers not yet associated with an account | Incremental |
| Account | Account | Companies or organizations | Incremental |
| Opportunity | Opportunity | Sales deals with stages, amounts, and close dates | Incremental |
| Campaign | Campaign | Marketing campaigns and their metadata | Incremental |
| Campaign Member | CampaignMember | Junction object linking contacts/leads to campaigns | Incremental |
| Task | Task | Activities like calls, emails, and to-dos | Incremental |
| Event | Event | Calendar events and meetings | Incremental |
| User | User | Salesforce users (reps, admins) | Incremental |
| Case | Case | Support cases | Incremental |
| Custom Objects | MyObject__c | Any custom object with API access | Incremental |
Custom Objects
Custom objects are automatically discovered during the connection setup. They appear in the object list alongside standard objects, identified by the __c suffix. Custom fields on standard objects are also included in the extracted schema.
Configuration
| Setting | Description | Default |
|---|---|---|
| Environment | Production or Sandbox | Production |
| API Version | Salesforce REST API version to use | Latest stable (e.g., v59.0) |
| Objects | List of objects to sync | — (you choose during setup) |
| Sync Mode | Full Refresh or Incremental (per object) | Incremental |
| Cursor Field | Field used for incremental sync | SystemModstamp |
| Primary Key | Field(s) that uniquely identify a record | Id |
| Target Schema | Warehouse schema for Salesforce tables | — (required) |
| Table Prefix | Optional prefix for table names | sf_ |
| Schedule | Sync frequency | Hourly |
Scheduling Notes
- Incremental sync uses
SystemModstamp, which Salesforce updates whenever any field on a record changes, including system-level changes. This ensures no modifications are missed. - Rate limits: Salesforce enforces API call limits based on your edition and license count. A standard Enterprise edition provides approximately 100,000 API calls per 24-hour period. Each loader run consumes API calls proportional to the number of objects and records extracted.
- Bulk API: For objects with more than 10,000 records, SignalSmith automatically uses the Salesforce Bulk API 2.0 to extract data more efficiently and consume fewer API calls.
- Deleted records: SignalSmith queries the Salesforce
queryAllendpoint to capture soft-deleted records (those in the Recycle Bin). These records are marked withIsDeleted = truein your warehouse.
Schema Mapping
Salesforce field types are mapped to warehouse-compatible types:
| Salesforce Type | Warehouse Type | Notes |
|---|---|---|
id | VARCHAR(18) | 18-character Salesforce ID |
string, textarea | VARCHAR | Length from Salesforce field metadata |
boolean | BOOLEAN | |
int | INTEGER | |
double, currency, percent | DOUBLE / FLOAT | |
date | DATE | |
datetime | TIMESTAMP | UTC normalized |
reference | VARCHAR(18) | Lookup/master-detail relationship ID |
picklist, multipicklist | VARCHAR | Picklist values as strings |
email, phone, url | VARCHAR |
Troubleshooting
| Issue | Solution |
|---|---|
| ”INVALID_SESSION_ID” or token expired | Re-authenticate by clicking “Reconnect” on the loader detail page |
| ”REQUEST_LIMIT_EXCEEDED” | You’ve hit Salesforce’s daily API limit. Reduce sync frequency or number of objects, or upgrade your Salesforce edition |
| Missing custom objects | Ensure the authenticated user’s profile has read access to the custom object and that it has API access enabled |
| ”QUERY_TOO_COMPLICATED” | Salesforce rejected a complex query. Contact SignalSmith support — this may require object-specific configuration |
| Sandbox data not appearing | Verify you toggled “Sandbox” before authenticating. Sandbox and Production are separate connections |
| Records missing after incremental sync | Check if records were hard-deleted (permanently removed from Recycle Bin). Hard-deleted records are not captured by incremental sync |
| Slow initial sync | Large orgs with millions of records may take several hours for the initial backfill. Subsequent incremental syncs will be much faster |
Example API Configuration
curl -X POST https://your-workspace.signalsmith.dev/api/v1/loaders \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Salesforce Production",
"connector": "salesforce",
"auth": {
"type": "oauth2",
"access_token": "00D...",
"refresh_token": "5Aep...",
"instance_url": "https://mycompany.my.salesforce.com"
},
"objects": [
{
"name": "Contact",
"sync_mode": "incremental",
"cursor_field": "SystemModstamp",
"primary_key": ["Id"]
},
{
"name": "Lead",
"sync_mode": "incremental",
"cursor_field": "SystemModstamp",
"primary_key": ["Id"]
},
{
"name": "Account",
"sync_mode": "incremental",
"cursor_field": "SystemModstamp",
"primary_key": ["Id"]
},
{
"name": "Opportunity",
"sync_mode": "incremental",
"cursor_field": "SystemModstamp",
"primary_key": ["Id"]
}
],
"target": {
"source_id": "src_abc123",
"schema": "SALESFORCE_RAW",
"table_prefix": "sf_"
},
"schedule": {
"interval": "hourly"
}
}'Next Steps
- Create a model to transform your raw Salesforce data
- Build an audience using Salesforce contacts and leads
- Sync audiences back to Salesforce as a destination