Datacircle

LinkedIn profiles in n8n: enrich a list of LinkedIn URLs with one HTTP Request node

You keep LinkedIn profile URLs in a Google Sheet, Airtable or a CRM, and an n8n workflow should fill in each person's name, headline, location, company and title. n8n's own LinkedIn node can't: its one operation creates a post. The usual templates start a scraper on Apify, wait for its run, then read its dataset.

Here it's one HTTP Request node that gets the profile back in the same step, at $1.25 per 1,000 profiles found through Up2Data, nothing for a profile it can't find. You send the provider's own request to api.datacircle.dev, with your Datacircle key. That's the only change. Below, the node, what each answer means, and the whole workflow to import, run on n8n 2.42.6 before it went up.

What you need

  • n8n, self-hosted or n8n Cloud. Nothing to install: the workflow uses only n8n's own nodes.
  • A Datacircle API key: sign up with your work email and it's on your dashboard, with the $5 credit, 4,000 profiles through Up2Data.
  • A list where each item has a linkedin_url, like https://www.linkedin.com/in/williamhgates.

The credential

In n8n, add a credential of the type Header Auth. Name: Authorization. Value: Token, a space, then your key. Save it as Datacircle API key. Both HTTP Request nodes below use it, and the key stays out of the workflow's JSON when you share it.

The HTTP Request node

The HTTP Request node's settings for Up2Data through Datacircle
FieldValue
MethodPOST
URLhttps://api.datacircle.dev/v1/profiles/enrich
AuthenticationGeneric Credential Type, then Header Auth: Datacircle API key
Send HeadersX-Data-Provider: up2data
Send BodyJSON, Using Fields Below: url = {{ $json.linkedin_url }}
Options, ResponseInclude Response Headers and Status: on. Never Error: on
Options, BatchingItems per Batch: 1. Batch Interval (ms): 1000

Never Error keeps one private profile from stopping the run: every answer comes out of the node, and its statusCode says what it is. Batching sends one URL at a time, a second apart. Or copy the node and paste it on your canvas:

{
  "nodes": [
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.datacircle.dev/v1/profiles/enrich",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Data-Provider",
              "value": "up2data"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "url",
              "value": "={{ $json.linkedin_url }}"
            }
          ]
        },
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 1000
            }
          },
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true
            }
          }
        }
      },
      "name": "Up2Data",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        440,
        300
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "datacircle",
          "name": "Datacircle API key"
        }
      },
      "id": "71dd5be5-3c66-4982-8e15-f2421444e60a"
    }
  ],
  "connections": {}
}

A 200 carries Up2Data's own profile in body.data, and what the call cost and your balance after it in body.datacircle_meta. Every field, jobs, schools and skills included: LinkedIn Profile API.

What each answer means

A Switch node on {{ $json.statusCode }} sends each answer down its own branch:

The Up2Data call's statuses, what each costs and the workflow's branch for it
StatusWhat it meansCostThe branch
200the profile$0.00125Profile: writes the columns
422Up2Data can't reach that profile: private or deletedfreeNot found
400not a LinkedIn profile URL: a company page or a malformed URLfreeNot a profile URL
429Up2Data's daily limit, or its own rate limitfreeHarvestAPI: the same URL, $0.0037 found, $0.0023 not found
other401: the key is wrong; 402: your balance; 502, 503 or 504: the provider failedfreeError: the status and the reason, to run again

Up2Data takes $1 a day per account (800 profiles), with a shared daily limit for all customers, then answers 429 until 00:00 UTC; HarvestAPI has no daily limit. So past 800 profiles in a day, the workflow sends each URL to HarvestAPI, through the same key: a GET with the URL as a query parameter and X-Data-Provider: harvestapi. HarvestAPI answers a 200 even when it finds nothing; then body.element is null and the row says not found (HarvestAPI). A call your balance can't cover answers 402. Add funds, from $5, on your dashboard.

The whole workflow

Download the workflow (JSON), then in n8n open a new workflow and import it from the file, or paste its contents on the canvas. Pick your Datacircle API key credential on the two HTTP Request nodes. Swap the LinkedIn URLs node, two example URLs, for your own source: a Google Sheets, Airtable or CRM node whose items have a linkedin_url. After the five branches, add the node that writes the rows back.

Every branch ends with the same columns, so one write node takes them all:

The workflow's columns and where each comes from in Up2Data's and HarvestAPI's answers
ColumnFrom Up2DataFrom HarvestAPI
linkedin_urlyour itemyour item
statusfound, not found: private or deleted, free, not a profile URL, free or error with the status and the reasonfound (HarvestAPI), not found (HarvestAPI) or error with the status and the reason
full_namedata.full_nameelement.firstName + lastName
headlinedata.headlineelement.headline
locationdata.location.rawelement.location.linkedinText
companydata.current_company.nameelement.currentPosition[0].companyName
titledata.current_company.titleelement.currentPosition[0].position
industry, headcountdata.current_company.industry, .headcountempty
cost_usddatacircle_meta.cost_usddatacircle_meta.cost_usd

We ran this file on n8n 2.42.6, self-hosted, against a stand-in of the API that answers as its reference does. With four URLs, a profile came out found, a private one not found for free, a company page not a profile URL for free, and a profile past the daily limit found (HarvestAPI). With a wrong key, every row came out error 401, and nothing stopped the run.

What it costs

From the pricing, per profile, taken from your balance with nothing added:

What a LinkedIn profile costs through Datacircle, per provider
Up2DataHarvestAPI
Profile found$0.00125$0.0037
Per 1,000 found$1.25$3.70
Profile not foundfree$0.0023
Daily limit800 profiles per accountnone

So a sheet of 1,000 URLs run in one day, every profile found, costs $1.00 for the first 800 through Up2Data and $0.74 for the other 200 through HarvestAPI: $1.74. Spread over two days, 500 a day, they fit in your account's Up2Data limit: $1.25.

The same call from Python: get LinkedIn profile data with Python. In a Google Sheet, without n8n: LinkedIn profiles in Google Sheets. From a Clay table: Clay alternative. What Apify's LinkedIn profile actors cost next to it: Apify LinkedIn profile scraper alternative; and every vendor's price per 1,000: LinkedIn profile API pricing compared.

Questions

Can n8n scrape LinkedIn profiles?

Not with its own LinkedIn node: its one operation creates a post, as you or your company page. An HTTP Request node can call a LinkedIn profile API instead: send the profile's URL, get JSON back. Through Datacircle: POST {"url": "<the profile's LinkedIn URL>"} to https://api.datacircle.dev/v1/profiles/enrich, with your key in a Header Auth credential and the header X-Data-Provider: up2data.

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

$1.25 per 1,000 through Up2Data (a profile it can't find is free), $3.70 per 1,000 through HarvestAPI. n8n doesn't charge per HTTP request: each call is taken from your Datacircle balance. 1,000 profiles found in a day: 800 through Up2Data ($1.00) and 200 through HarvestAPI ($0.74), $1.74 in all.

Is there a daily limit?

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

Is each request live, or cached?

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

Does it need a LinkedIn account, a cookie or Apify?

No. The HTTP Request node sends a URL to an API and gets JSON back in the same step: no LinkedIn login, no session cookie, no actor run to start and wait for. You need a Datacircle API key.

What happens when my balance runs out?

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

Sign up at datacircle.dev with your work email: a $5 credit, that's 4,000 LinkedIn profiles at $1.25 per 1,000. Free: 10M+ U.S. B2B leads, as a flat file. Download it at datacircle.dev.

Sign up