Salesforce Lead Pusher
Salesforce Lead Pusher on ApifyForge — Salesforce Lead Pusher takes enriched lead data from any source and pushes it directly into your Salesforce CRM as Leads, Contacts, or Accounts — with automatic deduplication by email, 200-record batch upserts, and a dry-run preview mode that costs nothing. Built for sales teams and RevOps engineers who want a direct pipeline from Apify scrapers into Salesforce without writing Apex code.
Maintenance Pulse
90/100Documentation
Salesforce Lead Pusher takes enriched lead data from any source and pushes it directly into your Salesforce CRM as Leads, Contacts, or Accounts — with automatic deduplication by email, 200-record batch upserts, and a dry-run preview mode that costs nothing. Built for sales teams and RevOps engineers who want a direct pipeline from Apify scrapers into Salesforce without writing Apex code.
Connect it to any Apify actor output — B2B Lead Gen Suite, Google Maps Lead Enricher, Website Contact Scraper, or a plain CSV — and your Salesforce records update automatically. The actor handles OAuth authentication, field normalization, rate-limit retries, and per-record error reporting in a single run.
What data can you push to Salesforce?
| Data Point | Salesforce Field | Example |
|---|---|---|
Email | [email protected] | |
| 👤 Full name (auto-split) | FirstName + LastName | Sarah / Chen |
| 📞 Phone | Phone | +1-415-555-0192 |
| 📱 Mobile | MobilePhone | +1-415-555-8847 |
| 🏢 Company name | Company (Lead) / Name (Account) | Acme Corp |
| 💼 Job title | Title | VP of Engineering |
| 🌐 Website / Domain | Website | https://acmecorp.com |
| 🏭 Industry | Industry | Technology |
| 📍 City, State, Country | City / State / Country | San Francisco / CA / US |
| 🏷️ Lead source | LeadSource | Web |
| ⭐ Rating | Rating | Hot |
| 👥 Employee count | NumberOfEmployees | 250 |
| 💰 Annual revenue | AnnualRevenue | 12000000 |
| 📝 Description / Notes | Description | Met at SaaStr 2025 |
| 🏷️ Custom fields | Any Field__c | LinkedIn_URL__c |
Why use Salesforce Lead Pusher?
Building a manual import workflow for every lead source is the kind of work that never actually gets done. Someone exports a CSV, someone else reformats columns to match Salesforce field names, duplicates slip in, the import fails on bad data, and by the time the leads land in CRM the outreach window has closed. Most teams fall back to copy-pasting or abandon the pipeline entirely.
This actor automates the entire process: authenticate once, point it at a dataset, and every qualifying lead lands in Salesforce as a structured record — deduplicated against what already exists, with all standard fields mapped automatically and custom fields handled via a JSON mapping config.
- Scheduling — run daily, weekly, or on a trigger to push fresh leads as they arrive from your scraping pipeline
- API access — call from Python, JavaScript, or any HTTP client to embed this in an existing orchestration layer
- Proxy rotation — not needed for CRM pushes, but Apify's infrastructure handles reliable outbound connectivity
- Monitoring — receive Slack or email alerts when a run fails, producing zero records, or hits Salesforce rate limits
- Integrations — chain via Dataset ID from any other Apify actor, or trigger via Zapier, Make, or webhooks
Features
- OAuth 2.0 username-password authentication — connects to any Salesforce org using a Connected App Consumer Key + Secret; supports both production (
login.salesforce.com) and sandbox (test.salesforce.com) orgs - Salesforce Composite Collections API — pushes records 200 at a time using the
/composite/sobjectsendpoint, the fastest bulk-create path available without governor-limit concerns from Bulk API 2.0 quotas - Three object types — push the same lead data as a
Lead(unqualified prospect),Contact(person linked to an Account), orAccount(company/organisation) depending on where you are in the sales cycle - Email-based deduplication — before each batch, runs a SOQL query in chunks of 50 to find existing Leads or Contacts by email; for Accounts, deduplicates by company name. Existing records are skipped and logged
- Full name splitting —
"Sarah Chen"becomesFirstName: "Sarah"andLastName: "Chen"automatically; single-word names go toLastName; pre-splitfirstName/lastNamefields pass through unchanged - Flexible input normalization — accepts
emailoremails[],phoneorphones[],companyNameorcompany,websiteordomain,jobTitleortitle— compatible with output from any Apify actor without preprocessing - Custom field mapping — pass a JSON object to map any input field to any Salesforce API field name, including custom
__cfields:{"linkedinUrl": "LinkedIn_URL__c"} - Dry-run mode enabled by default — previews every mapped record in the dataset output without creating anything in Salesforce; shows exactly which fields would be set on each record
- Per-record error reporting — each record in the output carries an
actionstatus (created,skipped_duplicate,skipped_dry_run,failed) and anerrorfield with the Salesforce error code and message if the push failed - Rate-limit retry — detects
REQUEST_LIMIT_EXCEEDEDHTTP 403 responses and waits 10 seconds before a single automatic retry; network errors get a 2-second retry - Spending limit enforcement — PPE charging fires after data is saved to the dataset; stops cleanly when the run's spending cap is reached rather than crashing mid-batch
- Summary record — the final dataset item is a
type: "summary"record with totals: created, updated, skipped duplicates, skipped dry-run, failed - Dataset chaining — provide a
datasetIdto pull leads directly from another actor's output dataset, up to 5,000 records per run
Use cases for Salesforce lead pushing
Sales prospecting pipeline
SDRs and BDRs using tools like Website Contact Scraper or Google Maps Lead Enricher end up with hundreds of qualified contacts sitting in a spreadsheet. This actor closes the loop: run the scraper, pass its dataset ID to Salesforce Lead Pusher, and every new contact appears in Salesforce within minutes — ready for assignment, sequencing, or automatic lead routing rules.
Marketing agency lead delivery
Agencies running lead gen campaigns for clients need to hand off structured CRM records, not CSV attachments. Point the actor at a completed B2B Lead Gen Suite dataset, set objectType to Lead, and deliver clean Salesforce records directly to the client's org. Duplicates are filtered automatically, so the client never complains about seeing the same contact twice.
RevOps data enrichment
Revenue operations teams enriching existing accounts with fresh firmographic data can push updated fields — employee count, annual revenue, industry — into existing Account records. The fieldMapping config maps any enrichment actor's output field to the correct Salesforce field without touching the existing record structure.
Recruiting and talent sourcing
Recruiters extracting hiring manager contacts from LinkedIn scrapers or conference attendee lists can push directly into Salesforce as Contacts or Leads, with job title, department, and company mapped automatically. The email-based deduplication prevents the same contact from appearing in multiple hiring pipelines.
Automated daily lead imports
Teams running scheduled Apify actors (nightly scrapes, weekly enrichment jobs) can chain Salesforce Lead Pusher at the end of the pipeline via webhooks or the Apify API. New leads from the previous day's run land in Salesforce before the sales team starts work in the morning — no manual import step required.
Conference and event lead capture
After events, lead lists arrive in inconsistent formats. The actor's flexible field normalization handles varying column names (email, emails, Email Address) without preprocessing. Push 500 event leads into Salesforce in one run, with the dry-run preview confirming the mapping looks correct before committing.
How to push leads to Salesforce
-
Create a Salesforce Connected App — go to Salesforce Setup, search for "App Manager", click "New Connected App". Enable OAuth 2.0, add the
apiscope, save, and copy your Consumer Key and Consumer Secret. This takes about 5 minutes and only needs to be done once. -
Prepare your credentials — your password must be your Salesforce login password concatenated with your security token (no space, no separator). If your password is
Summer2025!and your token isabc123XYZ, enterSummer2025!abc123XYZ. Get your security token at Setup > My Personal Information > Reset Security Token. -
Configure the actor — paste your Consumer Key, Consumer Secret, username, and combined password into the credential fields. Set
objectTypetoLeadfor new prospects. LeavedryRunset totruefor the first run. Paste your lead records into theleadsarray, or enter adatasetIdfrom a previous actor run. -
Preview, then push — run with dry-run enabled and check the output dataset. Each record shows which Salesforce fields would be set. When the mapping looks correct, run again with
dryRun: false. Results land in Salesforce in under a minute for batches under 1,000 records.
Input parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
salesforceUsername | string | Yes (live) | — | Salesforce login email, e.g. [email protected] |
salesforcePassword | string | Yes (live) | — | Password + security token concatenated, no separator |
salesforceClientId | string | Yes (live) | — | Consumer Key from your Salesforce Connected App |
salesforceClientSecret | string | Yes (live) | — | Consumer Secret from your Salesforce Connected App |
salesforceLoginUrl | string | No | https://login.salesforce.com | Use https://test.salesforce.com for sandbox orgs |
leads | array | No | — | Inline lead records to push; accepts flexible field names |
datasetId | string | No | — | Apify dataset ID to load leads from (up to 5,000 items) |
objectType | string | No | Lead | Salesforce object: Lead, Contact, or Account |
skipDuplicates | boolean | No | true | Query Salesforce before inserting; skip matching email/name |
fieldMapping | object | No | {} | Map input fields to Salesforce API field names |
dryRun | boolean | No | true | Preview mapping without writing to Salesforce |
maxLeads | integer | No | 500 | Cap records per run (1–5,000) |
Input examples
Push a single lead in dry-run mode (recommended first run):
{
"leads": [
{
"name": "Sarah Chen",
"email": "[email protected]",
"phone": "+1-415-555-0192",
"companyName": "Acme Corp",
"jobTitle": "VP of Engineering",
"industry": "Technology",
"website": "https://acmecorp.com",
"city": "San Francisco",
"state": "CA",
"country": "US",
"description": "Met at SaaStr 2025. Interested in automation tools."
}
],
"objectType": "Lead",
"dryRun": true
}
Pull from a dataset and push live to Salesforce with custom field mapping:
{
"salesforceUsername": "[email protected]",
"salesforcePassword": "MyPass123TOKEN456abc",
"salesforceClientId": "3MVG9...",
"salesforceClientSecret": "1234567890ABCDEF",
"datasetId": "abc123xyzDatasetId",
"objectType": "Lead",
"skipDuplicates": true,
"fieldMapping": {
"linkedinUrl": "LinkedIn_URL__c",
"score": "Lead_Score__c",
"sourceActor": "Lead_Source_Actor__c"
},
"dryRun": false,
"maxLeads": 500
}
Push to a Salesforce sandbox for testing:
{
"salesforceUsername": "[email protected]",
"salesforcePassword": "MyPass123TOKEN456abc",
"salesforceClientId": "3MVG9...",
"salesforceClientSecret": "1234567890ABCDEF",
"salesforceLoginUrl": "https://test.salesforce.com",
"leads": [
{
"name": "Marcus Rivera",
"email": "[email protected]",
"companyName": "Beta Industries",
"jobTitle": "Head of Sales"
}
],
"objectType": "Lead",
"dryRun": false
}
Input tips
- Run dry-run first — always preview with
dryRun: truebefore committing. The output shows every Salesforce field that would be set; check thatLastNameandCompanyare populated correctly before going live. - Concatenate password + security token — the most common setup error is entering only the password. Salesforce requires the security token appended immediately after the password with no separator.
- Use sandbox for integration testing — set
salesforceLoginUrltohttps://test.salesforce.comand append.sandboxto the username (e.g.[email protected]) to push to a sandbox org without touching production data. - Chain via datasetId to avoid copy-paste — pass the dataset ID from any other actor's run directly. The actor loads up to 5,000 records automatically, normalizing field name variations across different actor output formats.
- Use fieldMapping for custom fields — any Salesforce custom field (those ending in
__c) must be mapped explicitly. Add{"sourceField": "SalesforceField__c"}to thefieldMappingobject for each custom field you want to populate.
Output example
{
"inputName": "Sarah Chen",
"inputEmail": "[email protected]",
"inputCompany": "Acme Corp",
"salesforceId": "00Q8Z000001GxAbUAK",
"objectType": "Lead",
"action": "created",
"error": null,
"pushedAt": "2025-09-14T09:22:11.843Z"
}
Summary record (last item in every dataset):
{
"type": "summary",
"objectType": "Lead",
"totalProcessed": 47,
"created": 39,
"updated": 0,
"skippedDuplicates": 7,
"skippedDryRun": 0,
"failed": 1,
"dryRun": false,
"instanceUrl": "https://mycompany.my.salesforce.com",
"completedAt": "2025-09-14T09:23:04.217Z"
}
Dry-run record (no Salesforce ID, no charge):
{
"inputName": "Marcus Rivera",
"inputEmail": "[email protected]",
"inputCompany": "Beta Industries",
"salesforceId": null,
"objectType": "Lead",
"action": "skipped_dry_run",
"error": null,
"pushedAt": "2025-09-14T09:20:55.012Z"
}
Output fields
| Field | Type | Description |
|---|---|---|
inputName | string | null | Name from the input record as provided |
inputEmail | string | null | Email resolved from email or first item of emails[] |
inputCompany | string | null | Company resolved from companyName or company |
salesforceId | string | null | Salesforce record ID (e.g. 00Q8Z000001GxAb) on success; null otherwise |
objectType | string | Salesforce object type: Lead, Contact, or Account |
action | string | One of: created, updated, skipped_duplicate, skipped_dry_run, failed |
error | string | null | Salesforce error code and message if action is failed; null otherwise |
pushedAt | string | ISO 8601 timestamp of when the record was processed |
type | string | "summary" on the final summary record only |
totalProcessed | integer | Summary: total records processed in the run |
created | integer | Summary: records successfully created in Salesforce |
updated | integer | Summary: records updated (reserved; currently always 0) |
skippedDuplicates | integer | Summary: records skipped because they already existed |
skippedDryRun | integer | Summary: records skipped because dry-run was enabled |
failed | integer | Summary: records that Salesforce rejected with an error |
instanceUrl | string | null | Summary: Salesforce instance URL used for this run |
completedAt | string | Summary: ISO 8601 timestamp when the run finished |
How much does it cost to push leads to Salesforce?
Salesforce Lead Pusher uses pay-per-event pricing — you pay $0.05 per lead successfully created in Salesforce. Dry-run runs are completely free. Skipped duplicates are free. Failed records are free. You only pay when a record is actually written to your CRM.
| Scenario | Leads pushed | Cost per lead | Total cost |
|---|---|---|---|
| Quick test (dry-run) | Any | $0.00 | $0.00 |
| Small batch | 10 | $0.05 | $0.50 |
| Medium batch | 100 | $0.05 | $5.00 |
| Large batch | 500 | $0.05 | $25.00 |
| Enterprise batch | 1,000 | $0.05 | $50.00 |
You can set a maximum spending limit per run to control costs. The actor stops cleanly when your budget is reached — no partial batches left in an unknown state.
Compare this to Zapier's Salesforce integration at $49–299/month for automation tasks, or a custom Salesforce integration developer at $150+/hour. Most teams pushing 200–500 leads per week spend under $10/month with no subscription commitment.
Push leads to Salesforce using the API
Python
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("ryanclinton/salesforce-lead-pusher").call(run_input={
"salesforceUsername": "[email protected]",
"salesforcePassword": "MyPass123TOKEN456abc",
"salesforceClientId": "3MVG9...",
"salesforceClientSecret": "1234567890ABCDEF",
"leads": [
{
"name": "Sarah Chen",
"email": "[email protected]",
"companyName": "Acme Corp",
"jobTitle": "VP of Engineering",
"industry": "Technology"
}
],
"objectType": "Lead",
"skipDuplicates": True,
"dryRun": False
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item.get("type") == "summary":
print(f"Run complete: {item['created']} created, {item['skippedDuplicates']} duplicates skipped")
elif item.get("action") == "created":
print(f"Created: {item['inputName']} ({item['inputEmail']}) → SF ID: {item['salesforceId']}")
elif item.get("action") == "failed":
print(f"Failed: {item['inputEmail']} — {item['error']}")
JavaScript
import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: "YOUR_API_TOKEN" });
const run = await client.actor("ryanclinton/salesforce-lead-pusher").call({
salesforceUsername: "[email protected]",
salesforcePassword: "MyPass123TOKEN456abc",
salesforceClientId: "3MVG9...",
salesforceClientSecret: "1234567890ABCDEF",
leads: [
{
name: "Marcus Rivera",
email: "[email protected]",
companyName: "Beta Industries",
jobTitle: "Head of Sales",
}
],
objectType: "Lead",
skipDuplicates: true,
dryRun: false,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
if (item.type === "summary") {
console.log(`Done: ${item.created} created, ${item.skippedDuplicates} skipped, ${item.failed} failed`);
} else if (item.action === "created") {
console.log(`Pushed: ${item.inputName} → ${item.salesforceId}`);
}
}
cURL
# Start the actor run
curl -X POST "https://api.apify.com/v2/acts/ryanclinton~salesforce-lead-pusher/runs?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"salesforceUsername": "[email protected]",
"salesforcePassword": "MyPass123TOKEN456abc",
"salesforceClientId": "3MVG9...",
"salesforceClientSecret": "1234567890ABCDEF",
"leads": [{"name": "Sarah Chen", "email": "[email protected]", "companyName": "Acme Corp"}],
"objectType": "Lead",
"dryRun": false
}'
# Fetch results (replace DATASET_ID from the run response defaultDatasetId field)
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=json"
How Salesforce Lead Pusher works
Authentication phase
The actor authenticates using the Salesforce OAuth 2.0 username-password flow, posting credentials to /services/oauth2/token with grant_type=password. This returns an access_token and instance_url specific to your org. The token is reused for all subsequent requests in the run — there is no token refresh logic since runs complete in well under the one-hour token expiry window. In dry-run mode, authentication is skipped entirely.
Deduplication query phase
Before pushing each batch of up to 200 records, the actor runs SOQL queries to find existing records. It queries in chunks of 50 values to stay within URL length limits: SELECT Id, Email FROM Lead WHERE Email IN ('[email protected]', '[email protected]', ...). The result set is loaded into a Set<string> of lowercase lookup keys. For Account objects, the lookup uses Name instead of Email. Records with a matching key are tagged skipped_duplicate without touching Salesforce.
Batch push phase
Active (non-duplicate) records in each batch are mapped to Salesforce field names using mapToSalesforceFields(). This function handles object-type differences — Contact uses MailingCity where Lead uses City, Account uses BillingCity and maps company to Name. Full names are split by whitespace with the last token becoming LastName and everything prior becoming FirstName. The mapped records are submitted to the Salesforce Composite Collections endpoint (/composite/sobjects) in a single POST. The allOrNone: false flag means individual record failures do not roll back the rest of the batch.
Error handling and charging phase
Each item in the Composite API response maps 1-to-1 with the submitted records by position. Records where success: true are logged as created and trigger a PPE charge event (Actor.charge({ eventName: "lead-pushed", count: N })). Records where success: false have their errors[] array serialized into the output error field (statusCode: message format). The actor checks eventChargeLimitReached after each batch charge and stops cleanly if the run's spending cap is hit.
Tips for best results
-
Always dry-run first. The dry-run output shows exactly which Salesforce fields would be populated for each record. Check that
Companyis set for Leads (defaults to"Unknown Company"if no company field is found) and that names split correctly before committing a large batch. -
Concatenate password and security token correctly. This is the most common configuration error. Your Salesforce security token is a separate alphanumeric string sent to your email when you reset it. It goes immediately after your password with no space or separator. If you change your password, Salesforce resets your token.
-
Use sandbox for initial integration testing. Set
salesforceLoginUrltohttps://test.salesforce.comand append.sandboxor the sandbox name to your username (e.g.[email protected]). This lets you verify the full push pipeline against real Salesforce API behavior without risking production data. -
Chain with B2B Lead Gen Suite for a full pipeline. Run B2B Lead Gen Suite or Google Maps Lead Enricher to build your lead list, then pass the output
datasetIddirectly to this actor. No CSV export, no reformatting. -
Set maxLeads conservatively for testing. When testing with a real production dataset, set
maxLeadsto5or10to verify a small sample before processing the full list. This costs $0.25–$0.50 and confirms everything maps correctly. -
Map custom fields before you need them. If your Salesforce org has custom fields (
Lead_Score__c,Source_Actor__c,LinkedIn_URL__c), configure them infieldMappingduring the dry-run phase. Custom fields must be explicitly mapped — they are not picked up automatically. -
Verify the Connected App OAuth scopes. The Connected App must have at minimum the
apiscope enabled. If you seeINSUFFICIENT_ACCESSerrors in the output, check Setup > App Manager > your app > OAuth Scopes and addapi. Therefresh_tokenscope is not required. -
Filter failed records for follow-up. Filter the output dataset by
action: "failed"and check theerrorfield. Common failure reasons:REQUIRED_FIELD_MISSING(usuallyLastNameorCompany),INVALID_EMAIL_ADDRESS, orFIELD_CUSTOM_VALIDATION_EXCEPTIONfrom org-specific validation rules.
Combine with other Apify actors
| Actor | How to combine |
|---|---|
| B2B Lead Gen Suite | Full pipeline: scrape websites → enrich → push to Salesforce via datasetId |
| Google Maps Lead Enricher | Search Google Maps for local businesses, enrich with contacts, push as Leads |
| Website Contact Scraper | Extract emails and phones from company websites, push directly as Salesforce Leads |
| Waterfall Contact Enrichment | Enrich partial records through 10 data sources, then push the enriched output to Salesforce |
| Email Pattern Finder | Discover email naming patterns for a domain, build full email addresses, push to CRM |
| Bulk Email Verifier | Verify email deliverability before pushing — avoid invalid addresses triggering Salesforce validation errors |
| HubSpot Lead Pusher | Push the same lead dataset to HubSpot in parallel for teams using dual CRM setups |
Limitations
- Creates only, no updates. The actor creates new records. It does not update existing Salesforce records — when
skipDuplicatesistrue, existing matches are skipped; whenfalse, Salesforce will return a duplicate error for records that violate your org's duplicate rules. A true upsert (update-on-match) is not currently supported. - Up to 5,000 leads per run from a dataset. The
listItemscall is capped at 5,000 items. For larger datasets, split into multiple runs usingmaxLeadsand offset logic in a parent orchestrator. - Password flow requires security token. If your Salesforce org enforces IP restrictions, you must append the security token to the password. Orgs with "trusted IP ranges" covering Apify's IP space may not require it, but this varies by org configuration.
- No Salesforce Bulk API support. The Composite Collections API is used instead of Bulk API 2.0. This is intentional — Bulk API jobs require polling, add latency, and consume a separate daily job limit quota. The Composite API handles up to 200 records per call with synchronous results.
- Contact object requires an existing Account. When pushing as
Contact, Salesforce requires anAccountIdfield linking to an existing Account record. The actor does not auto-create Accounts for Contacts. Use thefieldMappingto pass a known AccountId, or push asLeadinstead. - Custom validation rules may reject records. If your Salesforce org has custom validation rules or required custom fields, records may fail with
FIELD_CUSTOM_VALIDATION_EXCEPTION. These are reported in theerrorfield of each failed output record but cannot be handled generically. - Sandbox usernames differ from production. Sandbox usernames typically have
.sandboxor a sandbox name appended. The actor cannot auto-detect sandbox vs. production from the login URL alone — ensure the username matches the target org. - No support for Person Accounts. Salesforce orgs with Person Accounts enabled treat individuals as Accounts rather than Contacts or Leads. The actor does not detect this configuration. Use
objectType: "Lead"for person-level records in orgs with Person Accounts.
Integrations
- Zapier — trigger a Salesforce Lead Pusher run when new leads arrive in a Google Sheet or Airtable base
- Make — chain actor runs in a Make scenario: scraper → enrichment → Salesforce push in a single automated workflow
- Google Sheets — export the push results to Google Sheets for stakeholder reporting on leads created vs. duplicates skipped
- Apify API — trigger runs programmatically from your own CRM middleware or ETL pipeline
- Webhooks — notify your team via Slack or email when a push run completes, with the summary record included in the payload
- LangChain / LlamaIndex — use Company Deep Research to generate AI-enriched company summaries, then push the enriched records to Salesforce via this actor
Troubleshooting
Authentication fails with "INVALID_CLIENT_CREDENTIALS" or HTTP 400 — the Consumer Key or Consumer Secret is incorrect. Double-check by copying them fresh from Setup > App Manager > your Connected App > Manage Consumer Details. Ensure the Connected App has "Enable OAuth Settings" checked and the api scope is listed. If you just created the Connected App, wait 2–10 minutes for Salesforce to propagate the settings before retrying.
Records fail with "REQUIRED_FIELD_MISSING: LastName" — the input records have no name, firstName, or lastName field. The actor defaults LastName to "Unknown" when no name data is found, but some org configurations override this. Check that your input records include a name field in any of the supported formats.
Records fail with "REQUIRED_FIELD_MISSING: Company" — Lead records require a Company value. The actor defaults to "Unknown Company" when no companyName or company field is found. If you see this error, your Salesforce org has a validation rule making the default value unacceptable. Add a company field to your input records.
Deduplication is not catching existing records — ensure skipDuplicates is true. Deduplication checks Salesforce's existing records by email for Leads/Contacts, or by name for Accounts. If your existing records used a different email format (uppercase vs lowercase), deduplication uses case-insensitive matching — but if emails differ entirely, duplicates will not be caught. The dedup query also does not paginate beyond 50 values per SOQL chunk — for very large batches with many pre-existing records, some may slip through.
Run is slow for large batches — the deduplication SOQL query runs before each batch of 200. For 1,000 leads this means 5 batch cycles, each with a SOQL query. This is expected behavior. Disable skipDuplicates if your dataset is known to be clean and you want maximum throughput.
Responsible use
- This actor only writes data you explicitly provide — it does not scrape or collect data independently.
- Ensure the personal data you push to Salesforce was collected with appropriate consent under GDPR, CAN-SPAM, CCPA, and other applicable data protection laws.
- Do not use this actor to push data obtained through unauthorized scraping of protected or private systems.
- Respect your Salesforce org's data governance policies and duplicate management rules.
- For guidance on web scraping legality, see Apify's guide.
FAQ
How do I push leads to Salesforce from another Apify actor? — run the source actor (e.g. B2B Lead Gen Suite), copy the dataset ID from its run detail page, and paste it into the datasetId field of Salesforce Lead Pusher. The actor loads up to 5,000 records automatically with no export step.
Does Salesforce Lead Pusher update existing records or only create new ones? — it creates new records only. When skipDuplicates is true, records with a matching email or company name in Salesforce are skipped and logged as skipped_duplicate. True update-on-match (upsert) is not currently supported.
How many leads can I push to Salesforce in one run? — up to 5,000 from a dataset, or as many as you provide inline (subject to the maxLeads cap, default 500). Increase maxLeads up to 5,000 for larger batches. For datasets over 5,000 records, split across multiple runs.
Is it safe to test against my production Salesforce org? — use dry-run mode (dryRun: true) to validate field mapping without writing anything. For full live testing, use a Salesforce sandbox org — set salesforceLoginUrl to https://test.salesforce.com and use your sandbox username.
What Salesforce editions does this work with? — any Salesforce edition that supports Connected Apps and the REST API: Essentials, Professional (with API add-on), Enterprise, Unlimited, and Developer Edition. The Composite Collections API endpoint used is available in all REST API-enabled orgs on API version 59.0 and later.
How is this different from Salesforce's built-in data import wizard? — the import wizard requires manual CSV exports, column header matching, and manual deduplication. This actor runs on a schedule, accepts data directly from other Apify actors, handles field normalization automatically, and produces per-record audit output showing exactly what was created, skipped, or failed.
How much does it cost to push 1,000 leads to Salesforce? — $50.00 total ($0.05 per successfully created record). Dry-run runs, skipped duplicates, and failed records are not charged. Set a spending limit on the run if you want to cap costs — the actor stops cleanly when the limit is reached.
Can I push Salesforce Contacts instead of Leads? — yes, set objectType to Contact. Note that Contacts in Salesforce typically require an AccountId linking them to an existing Account. If your Contact records do not include an AccountId, they may fail with a validation error in orgs where AccountId is required. Use Lead for unqualified prospects.
Is it legal to push scraped contacts into Salesforce CRM? — legality depends on how the contact data was collected and the jurisdiction. In the EU, GDPR requires a lawful basis for processing personal data. In the US, CAN-SPAM and CCPA apply to marketing use. You are responsible for ensuring the data you push was collected lawfully. See Apify's web scraping legal guide for detailed guidance.
What happens if Salesforce rate limits the actor mid-run? — the actor detects REQUEST_LIMIT_EXCEEDED (HTTP 403) responses and automatically waits 10 seconds before retrying the batch once. If the retry also fails, the batch is marked as failed in the output. Most orgs have a daily API request limit of 100,000–1,000,000 — a single run pushing 500 records uses 3–6 API calls total.
Can I schedule this actor to run automatically? — yes. Use Apify's built-in scheduler to run daily, weekly, or at custom intervals. Combine with a scheduled scraping actor upstream and use datasetId chaining to keep Salesforce updated automatically without any manual steps.
How do I map a custom Salesforce field like LinkedIn_URL__c? — add it to the fieldMapping input: {"linkedinUrl": "LinkedIn_URL__c"}. The left side is the field name in your input data, the right side is the Salesforce API field name. Custom fields always end in __c. You can map as many custom fields as needed.
Help us improve
If you encounter issues, you can help us debug faster by enabling run sharing in your Apify account:
- Go to Account Settings > Privacy
- Enable Share runs with public Actor creators
This lets us see your run details when something goes wrong, so we can fix issues faster. Your data is only visible to the actor developer, not publicly.
Support
Found a bug or have a feature request? Open an issue in the Issues tab on this actor's page. For custom Salesforce field mapping, enterprise integrations, or high-volume pipelines, reach out through the Apify platform.
How it works
Configure
Set your parameters in the Apify Console or pass them via API.
Run
Click Start, trigger via API, webhook, or set up a schedule.
Get results
Download as JSON, CSV, or Excel. Integrate with 1,000+ apps.
Use cases
Sales Teams
Build targeted lead lists with verified contact data.
Marketing
Research competitors and identify outreach opportunities.
Data Teams
Automate data collection pipelines with scheduled runs.
Developers
Integrate via REST API or use as an MCP tool in AI workflows.
Related actors
GitHub Repository Search
Search GitHub repositories by keyword, language, topic, stars, forks. Sort by stars, forks, or recently updated. Returns metadata, topics, license, owner info, URLs. Free API, optional token for higher limits.
Weather Forecast Search
Get weather forecasts for any location worldwide using the free Open-Meteo API. Returns current conditions, daily and hourly forecasts with temperature, precipitation, wind, UV index, and more. No API key needed.
EUIPO EU Trademark Search
Search EU trademarks via official EUIPO database. Find registered and pending trademarks by name, Nice class, applicant, or status. Returns full trademark details and filing history.
Nominatim Address Geocoder
Geocode addresses to GPS coordinates and reverse geocode coordinates to addresses using OpenStreetMap Nominatim. Batch geocoding with rate limiting. Free, no API key needed.
Ready to try Salesforce Lead Pusher?
Start for free on Apify. No credit card required.
Open on Apify Store