Salesforce Lead Pusher — Upsert Leads & Contacts is an Apify actor on ApifyForge. Imports leads from any Apify scraper directly into Salesforce CRM as Leads, Contacts, or Accounts. Email deduplication, 200-record batch upserts, custom field mapping, and free dry-run preview. It costs $0.05 per lead-pushed. Best for sales teams and marketers who need verified contact data, lead lists, or prospect enrichment at scale. Not ideal for real-time monitoring or historical data analysis. Maintenance pulse: 90/100. Last verified March 27, 2026. Built by Ryan Clinton (ryanclinton on Apify).

LEAD GENERATIONINTEGRATIONS

Salesforce Lead Pusher — Upsert Leads & Contacts

Salesforce Lead Pusher — Upsert Leads & Contacts is an Apify actor available on ApifyForge at $0.05 per lead-pushed. Imports leads from any Apify scraper directly into Salesforce CRM as Leads, Contacts, or Accounts. Email deduplication, 200-record batch upserts, custom field mapping, and free dry-run preview. B2B CRM sync at $0.05 per lead created.

Best for sales teams and marketers who need verified contact data, lead lists, or prospect enrichment at scale.

Not ideal for real-time monitoring or historical data analysis.

Try on Apify Store
$0.05per event
Last verified: March 27, 2026
90
Actively maintained
Maintenance Pulse
$0.05
Per event

What to know

  • Results depend on publicly available data; private or gated contacts may not be found.
  • Email verification accuracy varies by domain and provider policies.
  • Requires an Apify account — free tier available with limited monthly usage.

Maintenance Pulse

90/100
Last Build
Today
Last Version
1d ago
Builds (30d)
8
Issue Response
N/A

Cost Estimate

How many results do you need?

lead-pusheds
Estimated cost:$5.00

Pricing

Pay Per Event model. You only pay for what you use.

EventDescriptionPrice
lead-pushedCharged per lead successfully created or updated in Salesforce CRM.$0.05

Example: 100 events = $5.00 · 1,000 events = $50.00

Documentation

Salesforce Lead Pusher is a programmable CRM data engine that ingests, deduplicates, enriches, and syncs lead data into Salesforce. It's the final decision layer between your lead pipeline and your CRM — deciding which records should be created, which should be updated, and which should be skipped before any Salesforce write happens.

This actor converts raw signals into deterministic, automation-ready CRM-sync decisions (Salesforce).

Apify GTM Pipeline: Scrape → Enrich → Verify → Score → Research → Push to CRM Role of this actor: CRM ingestion + sync layer (Salesforce).

If you are scraping leads, enriching contacts with tools like Clay or Apollo, running scheduled lead pipelines, or trying to keep Salesforce clean as new sources arrive — this actor replaces manual CSV imports, fragile Zapier / Make workflows, and one-off Apex integrations with a single stateful pipeline that gets smarter every run.

When should you use Salesforce Lead Pusher?

Use this actor when you need to:

  • Push scraped or enriched leads into Salesforce automatically (Lead, Contact, or Account objects)
  • Deduplicate leads across multiple sources (scrapers + enrichment tools + manual imports)
  • Keep Salesforce clean as titles, phone numbers, and company info change over time
  • Replace Zapier / Make workflows for Salesforce automation with a more reliable, auditable, programmable system
  • Build a complete lead pipeline (scrape → enrich → score → push) using the Apify actor suite
  • Resolve conflicts when scraper, enrichment, and CRM history disagree on the same field

Do NOT use this actor if you only need:

Why this actor exists

Most Salesforce pipelines fail because they treat the CRM as a dump destination. Scrape something, push it, hope for the best — and a quarter later sales reps are working a lead list full of duplicates, stale phone numbers, and contacts attached to the wrong accounts.

This actor treats Salesforce as a system that has to stay clean, consistent, and auditable. Instead of pushing blindly, every record runs through a decision pipeline that:

  • evaluates data quality (per-field confidence aggregated from upstream sources + freshness from history)
  • resolves conflicts between sources (scraper vs enrichment vs Salesforce history) via per-field policy
  • tracks lifecycle over time (stale flagging, score decay, re-enrichment signals, archive triggers)
  • writes only when the push improves the CRM — and skips when it would degrade it

The result is a CRM that gets cleaner over time, not noisier. And every decision is auditable: every record carries a structured trail of which signals fired, which policies applied, and why the actor decided what it decided.

This positions the actor as a programmable alternative to Clay's CRM-sync layer for Salesforce, a more reliable replacement for Zapier / Make Salesforce workflows, and a stateful complement to Salesforce's native data tools (which validate but don't decide).

How this actor works (conceptually)

For every record, the decision pipeline runs:

  1. Identify the entity — multi-signal hash across email, domain, LinkedIn, and normalised name+company → stable identityId + matchConfidence + matchType. Detects duplicates even when emails differ.
  2. Compare with history — load the prior snapshot from the watchlist's named KV store: when did we last see this entity, what fields did it have, what was the score?
  3. Evaluate data quality — aggregate per-field confidence (verified email = 0.95, role-account email = 0.4, plausible phone = 0.7) + source attribution + freshness decay → dataConfidence block.
  4. Resolve field conflicts — when sources disagree, apply per-field policy (highest-confidence / most-recent / history-wins / incoming-wins / locked) against entity history → fieldConflicts[] block.
  5. Decide the action — push (create), update (real upsert via External Id), or skip (duplicate / quality-gate / rule-engine / replay / no-change-since-last-push).
  6. Write to Salesforce — only when the decision is push or update. Otherwise the record lands in the dataset as recordType: "skipped" with the structured reason — and is never charged.

This is what makes the actor different from "pushers" that just dump records: every Salesforce write is gated by a transparent, reproducible decision. Every dataset record carries the audit trail.

What's new (capability summary)

Core CRM writes

  • Real upsert via Salesforce External Id custom fields (PATCH /sobjects/<Type>/<extIdField>/<value>) — creates or updates the same record based on your external id without a separate query-then-create.
  • Multi-object orchestration for Contact pushes — when createAccountIfMissing: true, the actor resolves the linking Account before the Contact push (matches existing Accounts by domain or name; creates missing ones; attaches AccountId to each Contact). Closes Salesforce's hard requirement that Contacts link to an Account.
  • Mode presetsprospect-import / crm-hygiene-sync / signup-gate / event-attendees / account-based-push / audit-only / raw. Each bundles object type + lead status + source + dedup behaviour for a specific job.
  • Field overrides — per-object-type custom field name remapping for orgs with custom property names.

Data quality + deduplication

  • Identity resolution (multi-signal dedup) — every record gets an identityId hash + matchConfidence + matchType enum (exact-email / domain+company / name+company / fuzzy / low-signal) computed across email, domain, LinkedIn, and normalised name+company. Catches duplicates even when emails differ.
  • Truth resolution (fieldConflictPolicy) — per-field policy resolved against entity history. Policies: highest-confidence / most-recent / history-wins / incoming-wins / locked. Surfaces fieldConflicts[] per record. Solves "which value wins when scraper, enrichment, and Salesforce history disagree?" without live CRM fetches.
  • Data confidence — every record gets a trust block aggregating upstream signals (verified-email status, upstream score, identity match-confidence) + freshness from history. Use to gate pushes or prioritise updates.
  • Quality gate — pre-push filter rejects records missing required fields. Rejected records land in the dataset as recordType: "skipped" and are never charged in PPE mode.

Stateful pipeline (cross-run intelligence)

  • Watchlist + replay protection — cross-run idempotency via named KV store. A lead processed in a prior run on the same watchlist is skipped on re-run with replayMode: "skip" (default), preventing accidental double-billing.
  • Entity history — when watchlistName is set, the actor persists per-eventId snapshots (firstSeenAt, lastSeenAt, lastPushedAt, runsSeen, pushedCount, enrichmentLevel, scoreHistory) to a named KV store. Scheduled runs become a lifecycle tracker, not episodic pushes.
  • Delta-only pushdeltaPush: true skips records whose canonical fields haven't changed since the prior run. Eliminates redundant Salesforce writes on scheduled refresh schedules.
  • Lifecycle policies — stale flagging + optional score decay + archive signals + re-enrichment hints derived from entityHistory.lastSeenAt + changeSet. Configurable staleAfterDays / decayRatePerDay / archiveIfNoChangeDays / reEnrichIfStale.
  • Adaptive schema validation — across runs, the actor learns which Salesforce fields fail validation in your specific org. The schemaValidation.learnedFailures[] block surfaces "field X failed N times in prior runs — known risky" so subsequent runs auto-fix or warn.
  • Programmable push rules — per-record if/then logic on score / grade / industry / domain. Skip rejects or override leadStatus / leadSource / objectType without writing custom orchestration.

Simulation + cost control

  • Multi-scenario simulationsimulateScenarios[] runs the input through alternate decision profiles (e.g. strict / lenient / account-based) and emits recordType: 'scenario' records comparing predicted pushable / spend / skip counts vs the primary run. Tune your quality gate before committing to a live run.
  • Cost modelCOST_MODEL KV mirror with per-outcome breakdown ({ created: $0.05, updated: $0.05, skipped: $0 }), predictedCostUsd, and confidenceOfPrediction based on input quality. CFO-readable.
  • Replay enginereplayRecordId re-runs the decision pipeline against a single record from the entity store, emits recordType: 'replay' with the diff. No Salesforce write. For debugging "why did this record's decision change between runs?".
  • Cohort policies — advisory routing from cohortInsights.risk tier to push action (skip / push-all / best-only). Surfaces on lifecycleState.reasons[] for Dify / n8n consumers to enforce.

Auditability + downstream integration

  • Decision telemetry per record — every result carries pipelineState, actorGraph (sibling-actor next-step pointers), decisionTrace[] flat enum codes, failureAnalysis root-cause attribution, recommendedAction, nextActions[], inlineEnrichmentHints (per-need-type lookup), task execution object, improvementSuggestions[], and decisionSnapshot for audit replay.
  • Run-level summary blocksbatchInsights (success rate, failure category distribution), suiteInsights (which sibling actors to chain before this one next time), simulationStats, cohortBreakdown (per-domain rollup), runDelta (compared to prior watchlist run).
  • Output profilesminimal / standard / full / llm. Shape the dataset for your downstream consumer without writing transforms.
  • Stable enum tokens for automation — recordType (result | skipped | error | summary | scenario | replay), action, status, skipReason.source, failureAnalysis.category. Additive-only across minor versions; downstream Dify / n8n / Zapier rules can branch on them safely.

Common workflows

Drop-in pipeline patterns using the Apify actor suite:

Scrape → Enrich → Push
  Website Contact Scraper → Lead Enrichment Pipeline → Salesforce Lead Pusher

Daily CRM hygiene sync
  Scheduled scraper → bulk-email-verifier → Salesforce Lead Pusher (deltaPush + watchlistName)

Event lead import
  CSV / dataset → Salesforce Lead Pusher (mode=event-attendees, qualityGate)

Account-based pipeline
  B2B Lead Gen Suite → Salesforce Lead Pusher (mode=account-based-push, createAccountIfMissing=true)

Dual-CRM sync
  Lead Scoring Engine → Salesforce Lead Pusher AND HubSpot Lead Pusher (in parallel)

Audit-only preview
  Any upstream → Salesforce Lead Pusher (mode=audit-only) → review dataset → flip dryRun=false

Each workflow is supported natively — no Zapier, no Make, no custom orchestration code.

What data can you push to Salesforce?

Data PointSalesforce FieldExample
📧 EmailEmail[email protected]
👤 Full name (auto-split)FirstName + LastNameSarah / Chen
📞 PhonePhone+1-415-555-0192
📱 MobileMobilePhone+1-415-555-8847
🏢 Company nameCompany (Lead) / Name (Account)Acme Corp
💼 Job titleTitleVP of Engineering
🌐 Website / DomainWebsitehttps://acmecorp.com
🏭 IndustryIndustryTechnology
📍 City, State, CountryCity / State / CountrySan Francisco / CA / US
🏷️ Lead sourceLeadSourceWeb
RatingRatingHot
👥 Employee countNumberOfEmployees250
💰 Annual revenueAnnualRevenue12000000
📝 Description / NotesDescriptionMet at SaaStr 2025
🏷️ Custom fieldsAny Field__cLinkedIn_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/sobjects endpoint, 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), or Account (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" becomes FirstName: "Sarah" and LastName: "Chen" automatically; single-word names go to LastName; pre-split firstName/lastName fields pass through unchanged
  • Flexible input normalization — accepts email or emails[], phone or phones[], companyName or company, website or domain, jobTitle or title — 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 __c fields: {"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 action status (created, skipped_duplicate, skipped_dry_run, failed) and an error field with the Salesforce error code and message if the push failed
  • Rate-limit retry — detects REQUEST_LIMIT_EXCEEDED HTTP 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 datasetId to 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

  1. Create a Salesforce Connected App — go to Salesforce Setup, search for "App Manager", click "New Connected App". Enable OAuth 2.0, add the api scope, save, and copy your Consumer Key and Consumer Secret. This takes about 5 minutes and only needs to be done once.

  2. 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 is abc123XYZ, enter Summer2025!abc123XYZ. Get your security token at Setup > My Personal Information > Reset Security Token.

  3. Configure the actor — paste your Consumer Key, Consumer Secret, username, and combined password into the credential fields. Set objectType to Lead for new prospects. Leave dryRun set to true for the first run. Paste your lead records into the leads array, or enter a datasetId from a previous actor run.

  4. 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

Core

ParameterTypeDefaultDescription
modestringrawJob preset: prospect-import / crm-hygiene-sync / signup-gate / event-attendees / account-based-push / audit-only / raw. Bundles objectType + status + source + dedup behaviour.
salesforceUsernamestringSalesforce login email, e.g. [email protected] (required for live runs)
salesforcePasswordstringPassword + security token concatenated, no separator (required for live runs)
salesforceClientIdstringConsumer Key from your Salesforce Connected App (required for live runs)
salesforceClientSecretstringConsumer Secret from your Salesforce Connected App (required for live runs)
salesforceLoginUrlstringhttps://login.salesforce.comUse https://test.salesforce.com for sandbox orgs
leadsarrayInline lead records (flexible field names). Use datasetId to chain instead.
datasetIdstringApify dataset ID to load leads from (up to 5,000 items)
objectTypestringLeadLead / Contact / Account. Overrides the mode preset.
leadStatusstringpresetSalesforce Status (e.g. Open - Not Contacted). Overrides the mode preset.
leadSourcestringpresetSalesforce LeadSource (e.g. Outbound, Web, Event). Overrides the mode preset.
skipDuplicatesbooleantrueQuery Salesforce before inserting; skip matching Email/Name. Ignored when upserting.
dryRunbooleantruePreview mapping without writing to Salesforce. Auto-on with audit-only mode.
maxLeadsinteger500Cap records per run (1–5,000)

Real upsert (External Id)

ParameterTypeDefaultDescription
upsertExternalIdFieldstringSalesforce custom field marked External Id (e.g. External_Id__c). Switches the actor to PATCH-by-external-id mode (true upsert).
upsertExternalIdSourcestringexternalIdInput record field whose value provides the external id per lead.
createAccountIfMissingbooleanfalseAuto-resolve and attach AccountId for each Contact push. The actor matches existing Accounts (by domain or name), creates missing ones in a single batch, then attaches the resolved AccountId. Ignored for Lead and Account object types.
accountMatchKeystringdomainHow to match existing Accounts: domain (matches Account.Website against the lead domain) or name (matches Account.Name against the lead companyName).

Control plane

ParameterTypeDefaultDescription
outputProfilestringstandardminimal / standard / full / llm. Shape the dataset records.
systemModebooleanfalseOne-flag stateful service. Auto-enables batch + cohort insights.
includeBatchInsightsbooleansystemModeRun-level summary record with success rate, failure distribution, recommendations.
includeCohortInsightsbooleansystemModePer-domain rollup attached to each record + COHORT_INSIGHTS KV.
pushStrategyobject{}contactPolicy (all / best-only / role-based) for nested contacts[]. accountPolicy (always / only-if-new). seniorityRoles[].
pushRulesarray[]Programmable if/then rules — skip + override leadStatus / leadSource / objectType. Up to 50.
qualityGateobject{}Pre-push filter: requireEmail / requireDomain / requirePhone / minScore / minFields / requireDecisionMaker. Rejected records skipped + never charged.
decisionProfileobject{}Strictness tuning: strictness / minScore / requireDecisionMaker.
fieldOverridesobject{}Per-object-type custom field remapping: {Lead: {industry: 'Custom_Industry__c'}, Contact: {Title: 'role'}, Account: {Phone: 'Main_Phone__c'}}.
fieldMappingobject{}[Legacy alias] Treated as an override on the active objectType.
watchlistNamestringCross-run state via named KV store (entity snapshots + prior run + processed eventIds). Required for deltaPush and entityHistory.
monitorStateKeystringSuite-aligned alias for watchlistName. Either input works; if both are set, watchlistName wins. Use this for one consistent field name across salesforce-lead-pusher, hubspot-lead-pusher, lead-scoring-engine, bulk-email-verifier, waterfall-contact-enrichment, phone-number-finder, company-deep-research, and lead-enrichment-pipeline.
lastActionobjectCloses the feedback loop. Pass { type, takenAt: ISO date, note? } to tell the actor what action you took on this watchlist since the last run. On the next scheduled run the actor compares prior push outcomes against the current one and emits decisionMemory with an inferred outcome. Honest: only push-result delta is observable. Requires watchlistName / monitorStateKey.
replayModestringskipskip (default) skips already-processed eventIds. force pushes regardless (refresh runs).
identityResolutionobject{}Multi-signal dedup config: { strategy, signals[], confidenceThreshold }. Default uses email + domain + name+company across all leads.
deltaPushbooleanfalseWhen true AND watchlistName is set, skip records whose canonical fields haven't changed since the prior run.
simulateScenariosarray[]Multi-scenario simulation: [{ name, qualityGate?, skipDuplicates? }]. Each scenario emits a recordType: 'scenario' record with predicted counts + delta vs primary.
fieldConflictPolicyobject{}Per-field truth resolution against entity history. { score: 'highest-confidence', companyName: 'locked' }. Policies: highest-confidence / most-recent / history-wins / incoming-wins / locked.
lifecyclePoliciesobject{}{ staleAfterDays, decayScore, decayRatePerDay, archiveIfNoChangeDays, reEnrichIfStale }. Defaults: 30 / false / 0.01 / 90 / true. Drives lifecycleState block per record.
cohortPoliciesobject{}Map cohort risk tier → action: { high: 'skip', high_variance: 'best-only', moderate: 'push-all', low: 'push-all' } (defaults). Advisory only — surfaced in lifecycleState.reasons.
replayRecordIdstringDebug mode: replay decision pipeline on a single record by eventId. NO Salesforce write. Requires watchlistName.

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: true before committing. The output shows every Salesforce field that would be set; check that LastName and Company are 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 salesforceLoginUrl to https://test.salesforce.com and append .sandbox to 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 the fieldMapping object 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

FieldTypeDescription
inputNamestring | nullName from the input record as provided
inputEmailstring | nullEmail resolved from email or first item of emails[]
inputCompanystring | nullCompany resolved from companyName or company
salesforceIdstring | nullSalesforce record ID (e.g. 00Q8Z000001GxAb) on success; null otherwise
objectTypestringSalesforce object type: Lead, Contact, or Account
actionstringOne of: created, updated, skipped_duplicate, skipped_dry_run, failed
errorstring | nullSalesforce error code and message if action is failed; null otherwise
pushedAtstringISO 8601 timestamp of when the record was processed
typestring"summary" on the final summary record only
totalProcessedintegerSummary: total records processed in the run
createdintegerSummary: records successfully created in Salesforce
updatedintegerSummary: records updated (reserved; currently always 0)
skippedDuplicatesintegerSummary: records skipped because they already existed
skippedDryRunintegerSummary: records skipped because dry-run was enabled
failedintegerSummary: records that Salesforce rejected with an error
instanceUrlstring | nullSummary: Salesforce instance URL used for this run
completedAtstringSummary: 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.

ScenarioLeads pushedCost per leadTotal cost
Quick test (dry-run)Any$0.00$0.00
Small batch10$0.05$0.50
Medium batch100$0.05$5.00
Large batch500$0.05$25.00
Enterprise batch1,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 (typically a per-task subscription — verify current plans) or a custom Salesforce integration developer (commonly priced significantly higher per 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

  1. Always dry-run first. The dry-run output shows exactly which Salesforce fields would be populated for each record. Check that Company is set for Leads (defaults to "Unknown Company" if no company field is found) and that names split correctly before committing a large batch.

  2. 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.

  3. Use sandbox for initial integration testing. Set salesforceLoginUrl to https://test.salesforce.com and append .sandbox or 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.

  4. 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 datasetId directly to this actor. No CSV export, no reformatting.

  5. Set maxLeads conservatively for testing. When testing with a real production dataset, set maxLeads to 5 or 10 to verify a small sample before processing the full list. This costs $0.25–$0.50 and confirms everything maps correctly.

  6. 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 in fieldMapping during the dry-run phase. Custom fields must be explicitly mapped — they are not picked up automatically.

  7. Verify the Connected App OAuth scopes. The Connected App must have at minimum the api scope enabled. If you see INSUFFICIENT_ACCESS errors in the output, check Setup > App Manager > your app > OAuth Scopes and add api. The refresh_token scope is not required.

  8. Filter failed records for follow-up. Filter the output dataset by action: "failed" and check the error field. Common failure reasons: REQUIRED_FIELD_MISSING (usually LastName or Company), INVALID_EMAIL_ADDRESS, or FIELD_CUSTOM_VALIDATION_EXCEPTION from org-specific validation rules.

Use in Dify

Drop this actor into Dify workflows via the Apify plugin's Run Actor node. Each lead returns a structured push outcome — created / updated / skipped_duplicate / skipped_dry_run / failed plus a status discriminator (success / partial / error / dry_run / skipped) and a typed failureAnalysis.category enum your downstream node branches on. Generic HTTP nodes pointed at the Salesforce REST API return raw composite-result JSON; this returns decisions.

  • Actor ID: ryanclinton/salesforce-lead-pusher
  • Sample input (live push of a scored lead from lead-scoring-engine with quality-gate protection):
{
    "mode": "prospect-import",
    "salesforceUsername": "[email protected]",
    "salesforcePassword": "MyPass123TOKEN456abc",
    "salesforceClientId": "3MVG9...",
    "salesforceClientSecret": "1234567890ABCDEF",
    "datasetId": "scoredLeadsDatasetId",
    "qualityGate": { "requireEmail": true, "minScore": 70 },
    "watchlistName": "weekly-prospect-import",
    "dryRun": false
}

Dify routing example

A Dify if/else node can route the actor's per-record output without parsing prose:

Branch onFieldStable enum values
Did the push succeed?statussuccess / partial / error / dry_run / skipped
What did the actor do?actioncreated / updated / skipped_duplicate / skipped_dry_run / failed
Why did it fail?failureAnalysis.categoryauth / rate-limit / validation / duplicate / network / no-domain / no-contacts / no-required-field / unknown
Why was it skipped?skipReason.sourcequality-gate / rule-engine / replay-skip / strategy-policy
What should we do next?recommendedAction.actionIdpreview / verify-in-salesforce / resolve-domain / find-email / fix-credentials / enrich-and-retry / investigate
Should automation act?task.shouldActtrue / false
Per-domain push approachcohortInsights.recommendedApproachindividual / account-based / avoid / unknown
Per-domain riskcohortInsights.risklow / moderate / high_variance / high

A typical Dify workflow gates on task.shouldAct === true && status === 'success', then routes recoverable failures by failureAnalysis.category to the matching sibling actor in actorGraph.next[].

Opt-in modes Dify workflows can leverage

  • mode: "audit-only" — preview every mapped Salesforce record without writing. Free in PPE mode (no charges fire on dry-run skips).
  • watchlistName — cross-run idempotency. The same lead processed in a prior run on the same watchlist is auto-skipped (replayed: true, skipReason.source: "replay-skip"), preventing accidental double-billing on scheduled re-runs.
  • qualityGate — pre-push filter. Records that fail the gate land in the dataset as recordType: "skipped" with skipReason.source: "quality-gate" and are never charged. Branch downstream cleanup workflows on gateFailReasons[].
  • pushRules[] — programmable per-record if/then logic. Branch CRM behaviour on score / grade / industry / domain without writing a separate Dify branching tree.

Action arrays usable verbatim — no LLM rewriting

Every record's nextActions[] array is structured { actor, reason, inputHint, blocking }. Dify can iterate it and call each sibling actor directly with the supplied inputHint — no LLM prompt step, no JSON manipulation. The improvementSuggestions[] array similarly names sibling-actor slugs. Both arrays are deterministic; they don't change between runs of the same input.

Combine with other Apify actors

ActorHow to combine
B2B Lead Gen SuiteFull pipeline: scrape websites → enrich → push to Salesforce via datasetId
Google Maps Lead EnricherSearch Google Maps for local businesses, enrich with contacts, push as Leads
Website Contact ScraperExtract emails and phones from company websites, push directly as Salesforce Leads
Waterfall Contact EnrichmentEnrich partial records through 10 data sources, then push the enriched output to Salesforce
Email Pattern FinderDiscover email naming patterns for a domain, build full email addresses, push to CRM
Bulk Email VerifierVerify email deliverability before pushing — avoid invalid addresses triggering Salesforce validation errors
HubSpot Lead PusherPush the same lead dataset to HubSpot in parallel for teams using dual CRM setups
Lead Enrichment PipelineAll-in-one Clay alternative: email discovery, verification, company research, and scoring in one run ($0.12/lead)
AI Outreach PersonalizerGenerate personalized cold emails using your own OpenAI/Anthropic key — zero AI markup ($0.01/lead)
Intent Signal TrackerTrack buying signals: hiring, tech changes, funding, content updates. Prioritize outreach by intent score ($0.05/company)
Lead Data Quality AuditorAudit lead data quality before outreach — email verification, phone validation, domain freshness ($0.005/record)

What this actor does NOT do

Honest scope-fencing — these are not bugs, they're scope decisions. Each row points at the right actor for the job.

NeedUse this instead
Score / qualify leads before pushingLead Scoring Engine
Enrich leads (find emails / phones / decision-makers)Lead Enrichment Pipeline
Generate likely emails for a domainEmail Pattern Finder
Verify email deliverability before sendingBulk Email Verifier
Push the same leads to HubSpot CRMHubSpot Lead Pusher
Scrape websites for contact dataWebsite Contact Scraper
Search Google Maps for local business leadsGoogle Maps Lead Enricher
Run multi-source contact enrichment waterfallsWaterfall Contact Enrichment
Build a complete B2B lead list end-to-endB2B Lead Gen Suite

This actor's job is the Salesforce write itself — receive structured leads from any of the actors above (or from your own pipeline) and create or upsert them in your Salesforce org with a control plane (mode presets, push rules, quality gate, watchlist replay protection).

The actor's actorGraph.next[] field on every output record names the recommended sibling actor for the next step. The summary record's suiteInsights.recommendedPipeline[] names the actors that should run BEFORE this one on a future scheduled run.

Limitations

  • Two write modes — create-only or upsert-by-external-id. Default is create-only (with skipDuplicates: true querying Salesforce by Email/Name and skipping matches). Real upsert is supported when you set upsertExternalIdField to a Salesforce custom field marked as External Id; the actor then uses PATCH /sobjects/<Type>/<extIdField>/<value> for each record (creates on miss, updates on match). Upsert mode is one record per HTTP call (Salesforce-imposed); for large lists keep skipDuplicates create-only mode.
  • Up to 5,000 leads per run from a dataset. The listItems call is capped at 5,000 items. For larger datasets, split into multiple runs using maxLeads and 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 pushes can auto-create the linking Account (opt-in). Salesforce requires Contacts to carry an AccountId. Set createAccountIfMissing: true and the actor resolves the Account before the Contact push: it queries existing Accounts by domain (default) or name, creates any that don't exist, and attaches the resolved AccountId to each Contact. Output records carry accountId + accountCreated so you can audit which accounts the actor newly created. Without the flag, Contacts without a pre-supplied AccountId will fail with the Salesforce validation error.
  • 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 the error field of each failed output record but cannot be handled generically.
  • Sandbox usernames differ from production. Sandbox usernames typically have .sandbox or 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

What is the best way to automate Salesforce lead import? — point this actor at any upstream lead source (Apify dataset ID from another actor, or inline JSON) and configure a mode preset (prospect-import for cold outbound, crm-hygiene-sync for weekly refresh, event-attendees for event lists). The actor handles auth, dedup, field mapping, error classification, and per-record audit. Schedule it to run daily / weekly / on a webhook trigger and Salesforce stays in sync without manual CSV imports.

How do I deduplicate leads before importing them into Salesforce? — set skipDuplicates: true (default) and the actor queries Salesforce by Email (Lead/Contact) or Name (Account) before each batch and skips matching records. For multi-source dedup that catches duplicates even when emails differ, the identityResolution block computes a multi-signal identityId across email + domain + LinkedIn + name+company. The candidateMatches field flags cross-cohort duplicates within the same run.

Can I replace Zapier or Make for Salesforce automation with this actor? — yes for the Salesforce-write portion. The actor takes a stream of leads (any input source, any upstream Apify actor), applies programmable rules + quality gate + dedup, and writes to Salesforce with full per-record audit. It does NOT replace orchestration tools entirely — for chaining sibling actors (enrichment, verification, scoring) before the push, pair with Dify, n8n, Make, or schedule via Apify's native scheduler.

Is this a Clay alternative for Salesforce? — for the CRM-write layer specifically, yes. The actor provides identity resolution, field-conflict policy, lifecycle tracking, and stateful dedup that Clay does as a paid feature. It does NOT replace Clay's enrichment graph — for that, use Lead Enrichment Pipeline upstream and pipe the enriched records into this actor for the Salesforce write.

How do I keep Salesforce data clean when leads come from multiple sources? — combine identityResolution (multi-signal dedup) + fieldConflictPolicy (per-field rules for which source wins on conflicts) + lifecyclePolicies (stale flagging + score decay + archive signals) + watchlistName (cross-run state). The result: a CRM that gets cleaner over time as the actor reconciles incoming data against history.

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:

  1. Go to Account Settings > Privacy
  2. 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.

Last verified: March 27, 2026

Ready to try Salesforce Lead Pusher — Upsert Leads & Contacts?

Run it on your own Apify account. Apify offers a free tier with $5 of monthly credits.

Open on Apify Store