Datacircle

LinkedIn profiles in Zapier: enrich LinkedIn URLs with one Code step

Your Zap's trigger gives a LinkedIn profile URL: a new row in Google Sheets, a new record in Airtable or your CRM. You want the person's job title, company and location back in the same Zap, for the next step to write. Zapier's LinkedIn app can't: it posts updates, as you or as your company page.

One Code by Zapier step gets the profile back, at $2.375 per 1,000 profiles Up2Data finds, and nothing for a profile it can't find. Past Up2Data's daily limit, the same step calls Fetchin, at $1.485 per 1,000. You send the provider's own request to api.datacircle.dev, with your Datacircle key. That's the only change.

We ran the code unchanged in Node.js, not in a Zap, with the inputData and fetch a Code step gets: against a mock of our API for every answer below, then against api.datacircle.dev with a wrong key.

Before you start

  • A Zapier plan with multi-step Zaps: Professional or above. This Zap has three steps: your trigger, the Code step and the step that writes the fields back. Zapier's Free plan allows two-step Zaps only.
  • A Datacircle API key: sign up with your work email and your key is on your dashboard. You get a $5 credit, enough for 2,105 profiles through Up2Data.
  • A trigger that passes the profile's URL, like https://www.linkedin.com/in/williamhgates.

The Code step

After your trigger, add a step with these settings:

The Code by Zapier step's settings
FieldValue
AppCode by Zapier
Action eventRun JavaScript
Input Datalinkedin_url: your trigger's LinkedIn URL field
Codethe code below, your key between the quotes on the KEY line
// LinkedIn profiles in Zapier, through Datacircle: Up2Data, then Fetchin past Up2Data's daily limit.
// Input Data: linkedin_url, the profile's LinkedIn URL from your trigger. Your key goes in KEY.
const KEY = "your Datacircle API key"

async function call(method, path, provider, body) {
  const headers = { Authorization: "Token " + KEY, "X-Data-Provider": provider }
  if (body) headers["Content-Type"] = "application/json"
  const response = await fetch("https://api.datacircle.dev" + path, { method, headers, body: body && JSON.stringify(body) })
  const answer = await response.json().catch(() => ({})) // a gateway's error page isn't JSON: its status says enough
  return { status: response.status, body: answer }
}

// The same fields on every answer, so the next step can map each one
function row(status, fields = {}) {
  const all = { status, title: "", company: "", location: "", headline: "", industry: "", headcount: "", cost_usd: 0, ...fields }
  for (const key in all) if (all[key] === undefined || all[key] === null) all[key] = ""
  return all
}

function failed(answer) {
  const reason = (answer.body.error && answer.body.error.message) || answer.body.error
  return row(reason ? "error " + answer.status + ": " + reason : "error " + answer.status)
}

const url = inputData.linkedin_url
const up2data = await call("POST", "/v1/profiles/enrich", "up2data", { url })
if (up2data.status === 200) {
  const profile = up2data.body.data
  const company = profile.current_company || {}
  return row("found", {
    title: company.title, company: company.name, location: (profile.location || {}).raw, headline: profile.headline,
    industry: company.industry, headcount: company.headcount, cost_usd: up2data.body.datacircle_meta.cost_usd,
  })
}
if (up2data.status === 422) return row("not found: private or deleted, free")
if (up2data.status === 400) return row("not a profile URL, free")
if (up2data.status !== 429) return failed(up2data)

// Up2Data's daily limit: the same URL through Fetchin, with the same key
const fetchin = await call("GET", "/api/v1/profile?profileUrlOrUrn=" + encodeURIComponent(url), "fetchin")
const body = fetchin.body
if (fetchin.status === 200) {
  return row("found (Fetchin)", {
    title: body.jobTitle, company: body.companyName, location: body.location, headline: body.title,
    cost_usd: body.datacircle_meta.cost_usd,
  })
}
if (fetchin.status === 404 && body.code === "PROFILE_NOT_FOUND") {
  return row("not found (Fetchin): private or deleted, billed", { cost_usd: body.datacircle_meta.cost_usd })
}
if (fetchin.status === 400) return row("not a profile URL, free")
return failed(fetchin)

A Code step reads your trigger's fields only through Input Data, as Zapier's guide says. Run Code tests the step with a real call, and we bill it like any other call.

Anyone who can edit the Zap sees your key in the code, since a Code step has no place to keep it. It stays out of your Zap history, which shows Input Data for every run. If it leaks, reset it: the old one stops working.

Fields for the next step

The Code step returns the same fields for every answer, so the step that writes the row, such as Google Sheets' Update Spreadsheet Row, can map each one:

Code step fields and their sources in Up2Data and Fetchin
FieldFrom Up2DataFrom Fetchin
statusfound, not found: private or deleted, free, not a profile URL, free or error with the status and the reasonfound (Fetchin), not found (Fetchin): private or deleted, billed, not a profile URL, free or error with the status and the reason
titledata.current_company.titlejobTitle
companydata.current_company.namecompanyName
locationdata.location.rawlocation
headlinedata.headlinetitle
industry, headcountdata.current_company.industry, .headcountempty
cost_usddatacircle_meta.cost_usddatacircle_meta.cost_usd

Fetchin returns the profile's industry, not the company's, and no headcount, so a row through Fetchin leaves industry and headcount empty. Our LinkedIn Profile API page shows the profile's other fields, such as jobs, schools and skills.

Each API response: its cost and the status the step returns

Up2Data's and Fetchin's responses
AnswerWhat it meansCoststatus
Up2Data 200the profile$2.375 per 1,000found
Up2Data 422Up2Data can't reach that profile: private or deletedfreenot found: private or deleted, free
Up2Data 400not a LinkedIn profile URL: a company page or a malformed URLfreenot a profile URL, free
Up2Data 429Up2Data's daily limit, or its rate limitfreenone: the step sends the same URL to Fetchin
Fetchin 200the profile$1.485 per 1,000found (Fetchin)
Fetchin 404 with PROFILE_NOT_FOUNDFetchin can't find that profile: private or deleted$1.485 per 1,000: Fetchin bills the lookupnot found (Fetchin): private or deleted, billed
Fetchin 400not a LinkedIn profile URL: once Up2Data is at its daily limit, Fetchin is the one that rejects itfreenot a profile URL, free
any other401: the key is wrong. 402: your balance is too low. Fetchin's 429: its rate limit, which all Datacircle customers share. 502, 503 or 504: Up2Data or Fetchin failedfreeerror, the status and the reason

The step returns a status for every answer and never fails on one, so one private profile doesn't stop your Zap. Zapier turns a Zap off when 95% of its runs in the last 7 days end in an error.

Up2Data takes $1 a day per account (421 profiles), with a shared daily limit for all customers, then answers 429 until 00:00 UTC. HarvestAPI has no daily limit. Fetchin has no daily limit either. A call your balance can't cover answers 402. Add funds, from $5, on your dashboard.

For an error row, fix what its reason says, then replay its Zap run: in the Zap editor, open Zap runs, select the runs, then Replay, Entire Zap. Zapier offers Replay on paid plans and counts the replayed steps as new tasks.

Cost per 1,000 profiles

We charge your balance these prices, with no markup, as our pricing page shows:

Our price per 1,000 profiles and daily limit, by provider
Up2DataFetchin
Per 1,000 found$2.375$1.485
Per 1,000 not foundfree$1.485
Daily limit421 profiles per accountnone

Zapier counts each step against your plan's tasks. If 1,000 new rows come in one day and the providers find every profile, you pay us $1.86 at most: $1.00 for 421 through Up2Data and $0.86 for the other 579 through Fetchin, less if the daily limit all customers share stops Up2Data sooner. Fetchin costs less per profile found. But it bills a profile it can't find, which Up2Data doesn't. It also gives no company industry or headcount, so the code calls Up2Data first.

The same call in n8n: LinkedIn profiles in n8n. In a Make scenario instead: LinkedIn profiles in Make. In a Google Sheet, without Zapier: LinkedIn profiles in Google Sheets. From Python: get LinkedIn profile data with Python. Other vendors' prices per 1,000: LinkedIn profile API pricing compared.

Questions

Can Zapier get LinkedIn profile data?

Yes, with a Code by Zapier step that calls a LinkedIn profile API: send the profile's URL, get JSON back. Zapier's LinkedIn app can't: it posts updates, as you or as your company page. With our API: POST {"url": "<the profile's LinkedIn URL>"} to https://api.datacircle.dev/v1/profiles/enrich, with the headers Authorization: Token <your key> and X-Data-Provider: up2data. Past Up2Data's daily limit, the code in the same step sends the URL to Fetchin: GET https://api.datacircle.dev/api/v1/profile?profileUrlOrUrn=<the profile's LinkedIn URL>, with X-Data-Provider: fetchin.

Does it work on Zapier's Free plan?

No. Zapier's Free plan allows two-step Zaps only, and this one has three: your trigger, the Code step and the step that writes the fields back. Zapier gives a Code step 1 second to run on Free, and 30 seconds on Professional and Team.

Can I use Webhooks by Zapier instead of code?

Yes, for the Up2Data call: use the POST action, Payload Type JSON, Data url = the profile's URL, and two Headers: Authorization = Token, a space, then your key, and X-Data-Provider = up2data. Webhooks by Zapier is a premium app, on Professional and above. A Webhooks step sends one request, so you need a second step to call Fetchin past Up2Data's daily limit. Our Code step reads each response's status and calls Fetchin itself.

How much does it cost to enrich LinkedIn profiles in Zapier?

$2.375 per 1,000 through Up2Data (a profile it can't find is free), $3.70 per 1,000 through HarvestAPI. $1.485 per 1,000 through Fetchin, a profile it can't find billed the same. HarvestAPI bills a profile it can't find at $2.30 per 1,000. Zapier counts each step against your plan's tasks, and we take each call's price from your Datacircle balance. Say you find 1,000 profiles in a day: 421 through Up2Data ($1.00) and 579 through Fetchin ($0.86), $1.86 in all.

Is there a daily limit?

Up2Data takes $1 a day per account (421 profiles), with a shared daily limit for all customers, then answers 429 until 00:00 UTC. HarvestAPI has no daily limit. Fetchin has no daily limit either.

Is each request live, or cached?

Live. Each request goes to the provider and gets the profile as it is today.

Do I need a LinkedIn account?

No. You send the profile's URL with your Datacircle key: no LinkedIn login, no cookies, no browser.

What happens when my balance runs out?

A call your balance can't cover answers 402. Add funds, from $5, on your dashboard.

Get started

Sign up at datacircle.dev with your work email: a $5 credit, that's 2,105 LinkedIn profiles at $2.375 per 1,000.

Sign up
Ask AI about Datacircle

Each opens with our question