LinkedIn profiles in Langflow: a LinkedIn tool through MCP or a custom component
You're building a flow in Langflow with the Agent component, and the agent should read a LinkedIn profile from its URL: the job title, company, location and headline. Langflow's docs say "Langflow is an open-source, Python-based, customizable framework for building AI applications." None of its core components reads a LinkedIn profile.
Datacircle is a data co-op. Step 1: Query your favorite B2B data APIs through us. Same request, same price, no markup. Step 2: You're DONE. Every morning, you get the flat file of your data plus everyone else's. Add $50 to your account: you get $50 of API PLUS the flat file. Right now we have 3 live LinkedIn profile APIs that we trust: Up2Data, HarvestAPI and Fetchin.
You can add our MCP server in Langflow's settings and drag it onto the canvas: no code. Or you can paste one custom component into the flow and decide what the agent reads. Both call Up2Data first. Up2Data costs $2.375 per 1,000 profiles it finds, and nothing for a profile it can't find. Fetchin is cheaper at $1.485 per 1,000, but it charges for a profile it can't find, and all our customers share its rate limit. Both switch to Fetchin only when Up2Data hits its daily limit and returns a 429. Through our MCP server, Langflow sends each call that gets an error 3 times, so we bill a profile Fetchin can't find 3 times. The component sends each call once.
We built both flows in Langflow 1.12.5 and ran them with a script in place of OpenAI's model and a test server in place of our API. We ran both flows against api.datacircle.dev with a wrong key: each got a 401, at no charge. We haven't run either with a real key or a real model.
Langflow has no core component that reads a LinkedIn profile URL
A Langflow agent uses tools: any component in Tool Mode, connected to the Agent's Tools port, as Langflow's tools page shows. The MCP Tools component gives the agent an MCP server's tools, and a custom component is a Python class you paste in. No core component reads LinkedIn.
On October 12, 2026, GitHub's code search for "linkedin" in langflow-ai, Langflow's GitHub organization, found 14 files. None is a LinkedIn component: they are prompts in starter flows, test files, links to LinkedIn pages, and the Composio Tools component's list of apps. That component is in lfx-bundles, a package you install on its own, as the Composio bundle page says. Composio's LinkedIn tools use your LinkedIn sign-in: they post as you and read your own profile. Their person profile tool takes a member's person ID, not a profile URL.
Before you start
- Langflow, with Python 3.10 to 3.14 and uv, or Langflow Desktop. We tested the Python package, 1.12.5, on Python 3.12. In a virtual environment:In our test, uv installed 457 packages.
uv pip install langflow uv run langflow run - A Datacircle API key: Sign up at datacircle.dev with your work email: a $5 credit, that's 2,105 LinkedIn profiles at $2.375 per 1,000. Log in at datacircle.dev/login with your work email. Your API key is on the page once you're in.
- A language model for the Agent. We set up OpenAI in Settings, Model Providers, and picked gpt-5.4-mini in the Agent's Language Model. Langflow's Agents page lists the other providers. Our tests used a script that answers like OpenAI's API, not a real model, and no other provider.
The MCP way: our MCP server in the MCP Tools component
Our MCP server is at https://. It gets a LinkedIn profile from its URL, through Up2Data, HarvestAPI or Fetchin. As Langflow's MCP client page shows, you add the server in Settings, then put it on the canvas as an MCP Tools component. First, open Settings, MCP Servers, click Add MCP Server, and fill in the Streamable HTTP/SSE tab:
| Field | Value |
|---|---|
| Name | datacircle |
| Streamable HTTP/SSE URL | https:// |
| Headers | Authorization: Bearer, a space, then your Datacircle API key |
Click Add Server. Langflow lists datacircle with the number of its tools. Langflow's docs show a Credential global variable in place of the key: create one holding Bearer and your key, then type its name as the header's value. Both worked in our test.
Then build the flow from a Chat Input, an Agent and a Chat Output:
| Component | Setting | Value |
|---|---|---|
| Agent | Language Model | your model, such as gpt-5.4-mini |
| Agent | Max Iterations | 4: at most 4 tool calls, each sent up to 3 times when it fails (below) |
| Agent | Agent Instructions | the line below, added at the end |
| MCP Tools | MCP Server | datacircle: drag it from the MCP section of the sidebar |
| MCP Tools | Tool Mode | on, in the component's header menu |
| MCP Tools | Actions | get_ enabled, every other action disabled |
| Connections | Chat Input to the Agent's Input, the MCP Tools' Toolset to the Agent's Tools, the Agent's Response to Chat Output |
The line for Agent Instructions:
If get_linkedin_profile says up2data's daily limit is reached, call it again with provider fetchin.Open the Playground and ask:
Read the LinkedIn profile at https://www.linkedin.com/in/example-profile: the job title, company, location and headline.Langflow gives the model our whole JSON answer
The model got our tool's name, its whole description, and its two inputs, url and provider, but not its output schema. It got the Agent's own two tools too, Current Date and Calculator, both on by default. The first request to the model was 5,485 bytes with only get_ enabled, and 7,455 with all our tools.
Our server sends each answer as text and as structuredContent. Langflow gives the model the text: the provider's JSON, plus datacircle_meta, what the call cost and your balance after it:
{"data": {…}, "meta": {…}, "datacircle_meta": {…}}Up2Data's example answer was 1,167 characters. Langflow passed a saved Fetchin answer of 65,229 characters to the model whole.
Each failed call reaches our server 3 times
The tool takes url, and provider: up2data (the default), harvestapi or fetchin. At Up2Data's limit, the server tells your agent to call again through Fetchin or HarvestAPI. HarvestAPI costs more per 1,000 profiles than the other two, so we name Fetchin in Agent Instructions.
Langflow raises each error our server returns. The Agent's Handle Parse Errors setting is on by default, and with it the Agent sends the same call twice more, one second and then two seconds later. Then the model reads:
Tool 'get_linkedin_profile' failed after 3 attempts with ValueError: MCP tool 'get_linkedin_profile' failed:
{"error": "daily up2data limit reached for your account …"}. Please try again.At Up2Data's limit, our three 429s were free, and our scripted model called again with fetchin and got the profile. Every other error reached our server 3 times too. Most are free, but Fetchin bills a profile it can't find: that's 3 billed lookups for one question. With Handle Parse Errors off, the first error stopped the run, and the agent never answered. The component below returns its errors as data, so Langflow sends each call once. Our MCP server docs list every tool.
With a wrong key, the flow stops before any model call
We added the server with a wrong key for api.datacircle.dev. Langflow's list of MCP servers, which Settings reads, returned:
Connection failed: MCP server 'datacircle' at https://api.datacircle.dev/mcp rejected the request
with HTTP 401: the configured credential was refused. …The MCP Tools component got no actions, and the flow stopped before the model, with:
Error running graph: Error building Component MCP Tools:
Error updating tool list: MCP server 'datacircle' at https://api.datacircle.dev/mcp rejected the request with HTTP 401 …Edit the server, and set the right key in its header.
Leave Tool Execution Timeout at 0, which waits up to 180 seconds
With Tool Execution Timeout (seconds) at 0, the MCP Tools component waits up to 180 seconds for a tool, above the 45 seconds our API waits for a provider. Our stand-in server answered after 50 seconds, and the model got the profile.
We set it to 10. Each call timed out after 10 seconds, and with Handle Parse Errors on, the Agent sent it twice more. Our server got 3 calls in 33 seconds, then the model read:
Tool 'get_linkedin_profile' failed after 3 attempts with ValueError: Tool 'get_linkedin_profile' execution failed:
Tool 'get_linkedin_profile' timed out after 10s. It was not retried because the MCP server may have already run it …Langflow's message says the call wasn't retried, but our server got it 3 times, and the agent got no profile. On api.datacircle.dev, we bill each call that gets a profile, so a timeout shorter than the provider's answer can bill you for profiles the agent never reads.
The component way: one custom component that calls our API
You send the provider's own request to api.datacircle.dev, with your Datacircle key. That's the only change. The component sends Up2Data's and Fetchin's own requests, with X-Data-Provider naming the provider. Up2Data's request is in our API reference. In the sidebar, click New Custom Component, paste this code into its Code pane, and save:
import time
import httpx
from lfx.custom.custom_component.component import Component
from lfx.io import MessageTextInput, Output, SecretStrInput, StrInput
from lfx.schema.data import Data
class DatacircleLinkedInProfile(Component):
display_name = "Datacircle LinkedIn Profile"
description = (
"Get the current job title, company, location and headline on a LinkedIn profile, from the profile's URL, "
"like https://www.linkedin.com/in/example-profile. Returns the keys job_title, company, location and headline, "
"or one key, error, when the profile can't be read. Each call asks the provider live and may be billed to the "
"Datacircle balance."
)
icon = "linkedin"
inputs = [
SecretStrInput(name="api_key", display_name="Datacircle API Key", required=True),
MessageTextInput(name="url", display_name="LinkedIn URL", info="The profile's URL", tool_mode=True),
StrInput(name="api_url", display_name="API URL", value="https://api.datacircle.dev", advanced=True),
]
outputs = [Output(display_name="Profile", name="profile", method="get_linkedin_profile")]
def send(self, provider, method, path, **request):
"""One call to Datacircle's API through one provider. Fetchin's 429 is its rate limit: wait a second and send it again."""
headers = {"Authorization": f"Token {self.api_key}", "X-Data-Provider": provider}
for wait in (0, 1, 2):
time.sleep(wait)
answer = httpx.request(method, f"{self.api_url}{path}", headers=headers, timeout=60, **request)
if provider != "fetchin" or answer.status_code != 429:
return answer
return answer
def get_linkedin_profile(self) -> Data:
answer = self.send("up2data", "POST", "/v1/profiles/enrich", json={"url": self.url})
if answer.status_code == 200:
profile = answer.json()["data"]
company = profile.get("current_company") or {}
return Data(data={"job_title": company.get("title"), "company": company.get("name"),
"location": (profile.get("location") or {}).get("raw"), "headline": profile.get("headline")})
if answer.status_code == 429: # Up2Data's daily limit: Fetchin answers instead
answer = self.send("fetchin", "GET", "/api/v1/profile", params={"profileUrlOrUrn": self.url})
if answer.status_code == 200:
profile = answer.json()
return Data(data={"job_title": profile.get("jobTitle"), "company": profile.get("companyName"),
"location": profile.get("location"), "headline": profile.get("title")})
if answer.status_code in (404, 422):
return Data(data={"error": "This LinkedIn profile is private or deleted."})
if answer.status_code == 400:
return Data(data={"error": "This is not a LinkedIn profile URL. Send one like https://www.linkedin.com/in/example-profile"})
if answer.status_code == 402:
return Data(data={"error": "The Datacircle balance is too low for this call. Tell the user to add funds on their Datacircle dashboard."})
if answer.status_code in (429, 500, 502, 503, 504):
return Data(data={"error": f"The provider didn't answer ({answer.status_code}), and the call wasn't charged. Try again in a minute."})
answer.raise_for_status() # 401: the Datacircle API Key is wrong
| Component | Setting | Value |
|---|---|---|
| Datacircle LinkedIn Profile | Datacircle API Key | your key, or a Credential global variable that holds it |
| Datacircle LinkedIn Profile | Tool Mode | on, in the component's header menu |
| Agent | Language Model | your model, such as gpt-5.4-mini |
| Agent | Max Iterations | 4 |
| Connections | Chat Input to the Agent's Input, the component's Toolset to the Agent's Tools, the Agent's Response to Chat Output |
In Tool Mode, Langflow turns the component into one tool, named after its output's method, get_. The model gets the component's description as the tool's, and url as its one input, with its info. The description names the answer's keys.
The component sends the URL to Up2Data. At Up2Data's daily limit (its 429), it sends the same URL to Fetchin. Fetchin takes 5 requests a second across all our customers, and returns a 429 past that: the component waits one second and sends it again, then waits two seconds and sends it once more.
The component returns a Data object, and Langflow gives the model its dict as JSON text:
{"job_title": …, "company": …, "location": …, "headline": …}For a private or deleted profile, a URL that isn't a profile, a low balance or a provider error, the component returns one key, error, as Langflow's custom components page suggests, so the agent can tell the user and go on. In our tests, Langflow sent each of these calls to our API once. Each field comes from the same JSON path as in our Python post:
| Field | Up2Data's answer | Fetchin's answer |
|---|---|---|
job_ | data. | jobTitle |
company | data. | companyName |
location | data. | location |
headline | data. | title |
With a wrong key (401), the component raises. Langflow gives the model the error's message, with no traceback, and the agent keeps going. We tried a wrong key on api.datacircle.dev, and the model read this:
Client error '401 Unauthorized' for url 'https://api.datacircle.dev/v1/profiles/enrich'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401Set the right key in Datacircle API Key. httpx waits 5 seconds by default, and 60 here: our stand-in server answered after 50 seconds, and the model got the profile. With httpx's default, the model read timed out after 5 seconds. API URL, under the advanced settings, is for tests: point it at a stand-in for our API, and you can run the flow without spending your balance.
Cap the agent's calls with Max Iterations
Each tool call reaches our API. We bill each call that gets a profile, and each call for a profile Fetchin or HarvestAPI can't find, at the price on our pricing page. The component sends up to four requests per call, and we bill at most one of them: Up2Data's 429 and Fetchin's 429 are free.
The Agent's Max Iterations caps its calls to the model, 15 by default, and each of those calls can ask for a tool. A scripted model that asked for the tool at every turn made 15 calls to a stand-in for our API in under a second. With Max Iterations at 4, it made 4. At the limit, the agent answers with this line, and no profile:
Model call limits exceeded: run limit (4/4)A question about one profile took two calls to the model, and three when Up2Data hit its limit. At each turn, Langflow sends the model every tool result so far. With the long Fetchin answer at each turn, the requests grew from 5,485 bytes to 74,638, 143,791 and 212,944.
Langflow has a Requires Approval setting on each action, and its tools page says "the run pauses until a human selects Approve or Reject in the Playground." We set it on get_ and ran the flow through Langflow's API. Its v1 run endpoint refused the flow, since that endpoint can't pause. Its v2 workflows endpoint returned an empty answer, and our server got no call. We didn't try the Playground.
API answers: cost and what the tool returns
| Answer | Meaning | Cost | The tool returns |
|---|---|---|---|
| Up2Data 200 | the profile | $2.375 per 1,000 | the four fields |
| Up2Data 422 | the profile is private or deleted | free | error: "This LinkedIn profile is private or deleted." |
| Up2Data 400 | not a LinkedIn profile URL | free | error: "This is not a LinkedIn profile URL." |
| Up2Data 429 | Up2Data's daily limit is reached | free | Fetchin's answer |
| Fetchin 200 | the profile | $1.485 per 1,000 | the four fields |
Fetchin 404 with PROFILE_ | the profile is private or deleted | $1.485 per 1,000: Fetchin bills the lookup | error: "This LinkedIn profile is private or deleted." |
| Fetchin 429 | Fetchin's rate limit is reached: all our customers share it | free | Fetchin's answer after up to two retries, or error: "Try again in a minute" |
| 402 | your balance can't cover the call | free | error: "The Datacircle balance is too low for this call." |
| 500, 502, 503 or 504 | the provider failed, or didn't answer within 45 seconds | free | error: "Try again in a minute" |
| 401 | your key is wrong | free | httpx's error message |
Through the MCP Tools component, Langflow sends each call that doesn't get a 200 to our server 3 times, and the model reads our error inside Langflow's failure message, shown above. 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.
The tests we ran
- We tested on October 12, 2026, with Python 3.12,
langflow1.12.5 (langflow-baseandlfx1.12.5),mcp1.30.0, langchain 1.3.18, langchain-openai 1.7.0, openai 2.54.0 and httpx 0.28.1. - We ran Langflow without its visual editor and built each flow through the same API calls the editor makes: the custom component from the code above, unchanged, and the MCP server with the settings above. We ran each flow through Langflow's run API. We pointed the OpenAI provider's OpenAI Base URL at a scripted stand-in for OpenAI's API.
- We tested the component against a stand-in for our API that returned each answer in the table. We ran the MCP flow against a stand-in for our MCP server with the tools our live server lists, and tried each error, a 50 second answer, both timeouts, the long answer and both caps.
- We didn't try an OAuth sign in, a real Datacircle key, a real model or the Playground.
Cost per 1,000 profiles
We charge your balance the prices on our pricing page, with no markup:
| Up2Data | HarvestAPI | Fetchin | |
|---|---|---|---|
| Per 1,000 found | $2.375 | $3.70 | $1.485 |
| Per 1,000 not found | free | $2.30 | $1.485 |
| Daily limit | 421 profiles per account | none | none |
Say your agent looks up 1,000 profiles in a day, one call each, and the providers find every one. You pay us at most $1.86: $1.00 for 421 through Up2Data and $0.86 for the other 579 through Fetchin. Through Fetchin alone, the same 1,000 would cost less: $1.485. Both flows call Up2Data first because it bills nothing for a profile it can't find, and all our customers share Fetchin's rate limit. Your agent may call the tool more than once per question. Your model's provider bills you for its tokens.
The same agent in Flowise, another visual builder: LinkedIn profiles in Flowise. In Dify: LinkedIn profiles in Dify. The same call as an n8n workflow, without an agent: LinkedIn profiles in n8n. In code, as a tool for an agent: LinkedIn profiles in LangChain, LinkedIn profiles in DSPy and other frameworks on our blog. The same call from a script: get LinkedIn profile data with Python. In Claude, ChatGPT or Cursor: our LinkedIn MCP server. Other vendors' prices per 1,000: LinkedIn profile API pricing compared.
Questions
Does Langflow have a LinkedIn component?
Not in its core components. The Composio Tools component, in the separate lfx-bundles package, lists LinkedIn: you sign in with your own LinkedIn account, and its person profile tool takes a member's person ID, not a URL. To read a profile from its URL, add our MCP server at https://
How do I send an API key to a remote MCP server in Langflow?
In Settings, MCP Servers, Add MCP Server, pick Streamable HTTP/SSE and add an Authorization header with the value Bearer and your key. Or, as Langflow's docs show, put Bearer and your key in a Credential global variable and type the variable's name as the header's value.
Why does Langflow call my MCP tool three times?
If an MCP tool returns an error, Langflow raises it. The Agent's Handle Parse Errors setting is on by default, and with it the Agent sends the same call twice more. In our test, each failing call reached our server 3 times before the model read the error. With Handle Parse Errors off, the first error stopped the run.
What does Max Iterations default to in Langflow's Agent?
15 in Langflow 1.12.5: up to 15 model calls, so up to 15 tool calls in one run. At the limit, the agent answers "Model call limits exceeded: run limit (15/15)".
How much does a LinkedIn profile cost?
$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.
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