---
title: "Send scraped leads to Salesforce · Scrape.ly Docs"
description: "Create or update Salesforce leads, contacts and accounts from every successful scraper run. Map fields to any field; matched by email or name, so no duplicates."
url: https://scrape.ly/docs/salesforce
markdown: https://scrape.ly/docs/salesforce.md
---

# Send scraped leads to Salesforce

> Create or update leads, contacts or accounts from the results of each successful run.

Creates or updates Salesforce leads, contacts or accounts from the dataset items of each successful run. A Salesforce admin installs the Scrape.ly app in your org once, you connect your Salesforce account, then you choose which result fields go into which Salesforce fields. Common lead sources are the [Google Maps scrapers](https://scrape.ly/scrapers/google-maps) for local businesses and the [LinkedIn scrapers](https://scrape.ly/scrapers/linkedin) for company data.

## Install Scrape.ly in your org

Salesforce only lets apps that are installed in an org sign in to it. Installing is free, takes about a minute, and is done once per org by someone with the **System Administrator** profile:

1. In the dashboard, open **Settings** → **Connections** and click **Install link for your admin** next to **Salesforce** (the automation form shows the same link). Send it to your admin if that isn't you.
2. Your admin opens the link, signs in to Salesforce, picks **Install for Admins Only** (or the users who will connect), and clicks **Install**.

After that, anyone in the org can connect. Your org needs API access: Enterprise, Unlimited, Performance and Developer editions have it; Professional Edition only with Salesforce's API add-on. Production orgs only: sandboxes (`test.salesforce.com`) can't connect.

## Connect Salesforce

1. In the dashboard, open **Settings** → **Connections** and click **Connect account** next to **Salesforce** (or **Connect Salesforce** in the automation form).
2. Sign in to Salesforce and click **Allow**.

Scrape.ly can create and update records and read the field list of leads, contacts and accounts for the field mapping, with your Salesforce user's permissions. The sign-in renews itself while it's in use; if your org's policy for connected apps ends it (or your admin revokes it), you connect again. **Disconnect** removes the connection and revokes Scrape.ly's access, and Salesforce automations stop until you connect again. Uninstalling the app in Salesforce does the same for the whole org.

## Send results to Salesforce

1. Click **New automation** and pick **Send results to Salesforce** (on an Actor's **Automations** tab the Actor is already chosen).
2. Under **Send results as**, pick **Leads**, **Contacts** or **Accounts**.
3. Under **Field mapping**, add a row for each result field you want in Salesforce: type the field's name on the left and pick the Salesforce field on the right. Nested fields are named with dots, such as `address.city`. The field list comes from your org, custom fields included; fields marked `*` are needed to create a record.
4. Save and send a test. The test checks the connection, that every mapped field exists and can be written, and that the fields Salesforce needs for a new record are mapped; it doesn't create anything in Salesforce.

**Matching**: records are matched so a re-run updates them instead of adding duplicates. One result field must be mapped to the match field:

- **Leads** are matched by `Email`. An open (not converted) lead with the same email is updated; otherwise a new one is created.
- **Contacts** are matched by `Email`. A contact with the same email is updated; otherwise a new one is created.
- **Accounts** are matched by `Name` (Account Name). An account with the same name is updated; otherwise a new one is created.

Results without a valid email or a name in that field are skipped. Only the mapped fields that have a value are written; other fields of an existing record keep their values. When two results in the same batch have the same email or name, the later one wins.

**Required fields**: Salesforce needs `LastName` and `Company` for a new lead and `LastName` for a new contact, plus any field your admin made required. A record without them is refused by Salesforce and listed in the delivery history; the others are still written. Your org's validation and duplicate rules apply too.

**Values**: numbers, dates, checkboxes (`true`, `yes`, `y`, `1`) and picklists are converted to the field's type. A picklist value is matched to the field's values ignoring case; a multi-select picklist takes values separated by commas or semicolons. Text longer than the field allows is cut.

**When it writes**: only for succeeded runs, and only when the run returned items. **Max records per run** (1 to 1,000, default 1,000) caps how many items are sent.

**Limits**: records are looked up 100 and written 200 at a time, so 1,000 records take up to about 21 API requests of your org's daily allowance. Each Salesforce automation of this kind writes at most 30 times an hour, and an account at most 500 exports a day (Google Sheets, S3, GitHub, Airtable, HubSpot, Salesforce, Notion, Dropbox, OneDrive, Postgres, Azure Blob, BigQuery, Snowflake, and OpenAI Vector Store together). If Salesforce isn't connected, a field can't be written, or the org has used up its daily API requests, the delivery history on the automation's page says so.

## API

A webhook with a `salesforce` notification. Only `ACTOR.RUN.SUCCEEDED` is allowed, and Salesforce must be connected in the dashboard first.

```bash
curl -X POST https://api.scrape.ly/v2/webhooks \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "eventTypes": ["ACTOR.RUN.SUCCEEDED"],
    "condition": { "actorId": "YOUR_ACTOR_ID" },
    "description": "Leads to Salesforce",
    "notification": {
      "channel": "salesforce",
      "objectType": "Lead",
      "mapping": [
        { "field": "email", "property": "Email" },
        { "field": "lastName", "property": "LastName" },
        { "field": "company.name", "property": "Company" }
      ],
      "maxRows": 1000
    }
  }'
```

`objectType` is `Lead`, `Contact` or `Account`; `mapping` has 1 to 50 rows, each field at most once, and must map a field to `Email` (leads, contacts) or `Name` (accounts). `property` is the field's API name, such as `LastName` or `Rating__c`. `GET /v2/integrations/salesforce/fields?objectType=Lead` lists the fields of your connected org that can be written, with `required` for the ones a new record needs. Responses carry `notification.salesforceSettings` with `objectType`, `mapping`, and `maxRows`, and `connected` says whether Salesforce is still connected. In an automation, use a delivery with `"channel": "salesforce"` and the same `objectType`, `mapping`, and `maxRows` fields.

## FAQ

### Will re-running a scraper create duplicate Salesforce leads?

No. Leads and contacts are matched by email and accounts by name: a record with the same email or name is updated, and a new one is created only when there is no match. Results without a valid email or name are skipped.

### Why does Salesforce say the app isn't installed when I connect?

Salesforce only lets installed apps sign in to an org. Ask your Salesforce admin to open the install link from **Settings** → **Connections** and install Scrape.ly, then connect again.

### What can Scrape.ly access in my Salesforce org?

It works with your Salesforce user's permissions. It creates and updates records of the object you pick (leads, contacts or accounts), reads that object's field list for the field mapping, and when you connect reads your org's name and your email to show which account is connected. It doesn't read or change anything else.

---

- Previous: [HubSpot](https://scrape.ly/docs/hubspot.md)
- Next: [Notion](https://scrape.ly/docs/notion.md)
- All docs: [Docs index](https://scrape.ly/docs.md), [llms.txt](https://scrape.ly/llms.txt)
