LinkedIn Profile Scraper — Public Profile Data by URL avatar

LinkedIn Profile Scraper — Public Profile Data by URL

Pricing

from $6.08 / 1,000 profile founds

Go to Apify Store
LinkedIn Profile Scraper — Public Profile Data by URL

LinkedIn Profile Scraper — Public Profile Data by URL

LinkedIn profile scraper with no cookies and no account. Give it public LinkedIn profile links and get one flat row each: name, headline, location, current title and company, roles with dates, schools, follower and connection counts, and the photo. Nothing found, nothing charged.

Pricing

from $6.08 / 1,000 profile founds

Rating

0.0

(0)

Developer

Adrian Voss

Adrian Voss

Maintained by Community

Actor stats

1

Bookmarked

1

Total users

1

Monthly active users

3 days ago

Last modified

Share

LinkedIn Profile Lookup: LinkedIn Profile Scraper, No Cookies

Give this actor a list of public LinkedIn profile links and it fetches each one the way a signed-out browser does, then hands you a flat row per person: name, headline, location, current job title and company, the current roles the page lists with their start and end years, schools with years, follower and connection counts, and the profile photo. No login. No cookies. No li_at session token to paste in, no account of yours at risk, and nothing read from behind LinkedIn's sign-in wall.

The data comes from the schema.org Person block LinkedIn itself publishes in the page source of every public profile, so a row is the profile's own structured description of itself rather than a guess assembled from scraped text. When LinkedIn decides a request should sign in first, the actor says so in the row's status and charges you nothing.

Who it's for

Recruiters and sourcers who already have a shortlist of profile links and need them as a table instead of forty browser tabs. Sales teams who capture a LinkedIn URL on a form or in a CRM field and want the name, title, company and location filled in behind it before the first email goes out. Founders checking that an inbound lead's title still matches what their CRM said six months ago. And anyone building an agent or a workflow that has a profile link and needs the person behind it in a shape a script can read, without keeping a logged-in LinkedIn session alive somewhere.

If you do not have the profile links yet, this is the wrong tool: it looks up profiles you already name, it does not search LinkedIn for people matching a description.

Why this one

  • No cookies, no session token, no account. Every request is the plain public page. You are never asked to hand over a li_at cookie, and no LinkedIn account of yours can be restricted because of a run here.
  • Read from LinkedIn's own structured data. The row is built from the schema.org Person block in the page source, not from CSS selectors chasing a design that changes monthly. Field names stay put, which is what an agent or a Clay column needs.
  • It tells you when the page was reduced. LinkedIn often answers with a trimmed version of the profile in which job titles and past employers are replaced by rows of asterisks. Those never reach your table: the fields come back empty and the row is flagged masked: true, so you can filter or re-run instead of importing placeholder text into a CRM. See the note under "What you get" for how often that happens, measured rather than guessed.
  • A block is a labelled miss, not a silent hole. If LinkedIn asks the request to sign in, the row says status: BLOCKED with a plain explanation and costs nothing. A profile that no longer exists says NOT_FOUND. A company page pasted by mistake says BAD_FORMAT.
  • Never charged for a miss. Billing fires only on a row where a real profile came back.
  • Residential proxy by default. LinkedIn's sign-in wall is driven by the reputation of the IP asking, so the actor ships with a residential proxy already selected, and retries a blocked request on a fresh address rather than handing you the failure.

What you get

One row per profile you submit. Every row starts with the same five fields, then adds the profile fields you selected in "Which columns do you want?" (all of them by default).

FieldTypeDescription
querytextThe profile you submitted, echoed back
foundbooleantrue when a public profile was read
statustextOK on a hit, or NOT_FOUND, BLOCKED, BAD_FORMAT, REQUEST_FAILED on a miss
messagetextPlain-English reason for a miss, present only when found is false
scrapedAtISO 8601 datetimeWhen the page was fetched
profileUrllinkCanonical profile link, https://www.linkedin.com/in/<public id>
publicIdtextThe part of the link after /in/, LinkedIn's stable public identifier
fullNametextName as the public page shows it
headlinetextThe one-line headline under the name
locationtextLocation as shown, e.g. Seattle, Washington, United States
currentTitletextJob title of the first current role listed
currentCompanytextEmployer for that role
currentCompanyUrllinkThat employer's LinkedIn company page
experiencearrayCurrent roles the public page lists, each {title, company, companyUrl, location, startDate, endDate}
educationarraySchools the public page lists, each {school, degree, startDate, endDate}
followersnumberExact follower count, taken from the page's structured data rather than the rounded "41M" the top card prints
connectionstextConnection count as LinkedIn displays it, e.g. 500+, which is why it is text and not a number
profileImageUrlimageProfile photo on LinkedIn's media CDN
sourcetextjsonld when the row came from the page's structured-data block, html when it was assembled from the top card instead
maskedbooleantrue when LinkedIn served the reduced page and hid some titles or employers

Three honest limits on that table, stated here rather than left for you to discover in the data. education[].degree is null, because the logged-out page does not publish degree or field of study at all. experience covers the roles the public page presents as current; full career history is shown only to signed-in members and is not fetched. And there is no skills column, because no Skills section appeared in any of the fifteen public profile fetches this actor was built and tested against, so offering one would mean shipping a column that is always empty.

The bigger caveat is masked. LinkedIn decides per request whether to serve the complete profile page or a reduced one, and across those same fifteen fetches, of thirteen different profiles, on 2026-09-08, the complete page came back four times. That split did not track the route (a plain home connection got it 2 of 7 times, a residential proxy 1 of 6) and it did not track the profile either: the same profile served both versions inside fifteen minutes. On a reduced page the name, location, current employer, follower and connection counts, schools and photo still come through; the headline and job titles do not, and the row is flagged masked: true so you can see exactly which rows those are. Plan for headline and currentTitle to be present on a minority of rows, not on all of them.

Pricing

$8 per 1,000 profiles, plus a $0.00005 start fee. Misses (found:false) are never charged.

A run of 1,000 profiles costs about $8 if every one comes back, less when some are blocked or gone, and less again on a paid Apify plan. Compare that with a per-seat enrichment platform billing $0.08 to $0.40 per enriched row on top of a licence, or with LinkedIn profile actors listed at $100 per 1,000. Rows that come back found: false, for any reason, are free.

Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

curl "https://api.apify.com/v2/acts/accountable_eel~linkedin-profile-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-X POST \
-H "Content-Type: application/json" \
-d '{"profileUrls":["https://www.linkedin.com/in/williamhgates","satyanadella"]}'

n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~linkedin-profile-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"profileUrls":["https://www.linkedin.com/in/williamhgates","satyanadella"]} (swap in an expression from an earlier node for a real value).

Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~linkedin-profile-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"profileUrls":["{{profile}}"]}, mapping the row's profile into the profileUrls array.

MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "LinkedIn Profile Scraper, No Cookies | Apify" — the agent will find and run this actor.

How to use

  1. In the Apify Console. Open the actor page and click Start — the profileUrls field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
  2. Via the API. Call it directly with a POST request — no Console needed once you have an API token:
    curl "https://api.apify.com/v2/acts/accountable_eel~linkedin-profile-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"profileUrls":["https://www.linkedin.com/in/williamhgates","satyanadella"]}'
  3. On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
  1. Open the Input tab and paste your profile links into "LinkedIn profiles to look up", one per line. A full link, a bare linkedin.com/in/..., or just the identifier after /in/ all work.
  2. Leave "Try it first" on for the first run. It stops after 5 profiles so you can see the shape of the output before spending on the whole list.
  3. Leave the proxy on residential. It is the default, and it is the single biggest factor in how many of your profiles come back rather than blocked.
  4. Keep "Max concurrency" low, 2 to 3, on a long list. Speed here buys blocks, not throughput.
  5. Optionally narrow "Which columns do you want?", or use "Only keep rows containing" and "Skip rows containing" to filter by keyword, for example to keep only profiles whose row mentions a city or a job title.
  6. Turn "Try it first" off and press Start for the full list.

Input

{
"profileUrls": [
"https://www.linkedin.com/in/williamhgates",
"satyanadella"
]
}

One profile per line. Paste the full profile link, or just the part after /in/. Accepted formats: https://www.linkedin.com/in/williamhgates, linkedin.com/in/williamhgates, williamhgates.

Output

One row per profile submitted:

queryfoundstatusprofileUrlpublicIdfullNameheadlinelocationcurrentTitlecurrentCompanycurrentCompanyUrlexperienceeducationfollowersconnectionsprofileImageUrlsourcemaskedscrapedAt
williamhgatestrueOKhttps://www.linkedin.com/in/williamhgateswilliamhgatesBill GatesChair, Gates Foundation and Founder, Breakthrough EnergySeattle, Washington, United StatesCo-chairGates Foundationhttps://www.linkedin.com/company/gates-foundation[{"title":"Co-chair","company":"Gates Foundation","companyUrl":"https://www.linkedin.com/company/gates-foundation","location":null,"startDate":"2000","endDate":null},{"title":"Founder","company":"Breakthrough Energy","companyUrl":"https://www.linkedin.com/company/breakthrough-energy","location":null,"startDate":"2015","endDate":null},{"title":"Co-founder","company":"Microsoft","companyUrl":"https://www.linkedin.com/company/microsoft","location":null,"startDate":"1975","endDate":null}][{"school":"Harvard University","degree":null,"startDate":"1973","endDate":"1975"}]406320998https://media.licdn.com/dms/image/v2/D5603AQF-RYZP55jmXA/profile-displayphoto-shrink_200_200/B56ZRi8g.aGsAY-/0/1736826818802jsonldfalse2026-09-08T17:37:29.066Z

A profile that could not be read comes back as a row with "found": false, a status, and a message explaining which of the four reasons it was, and is never charged.

Tips

  • Run a handful of profiles you know by heart first. It is the fastest way to confirm the fields land where you expect before you point a long list at it.
  • Filter on masked: true rather than trusting an empty currentTitle. A masked row is LinkedIn trimming the page for that request, not the member leaving the field blank. If the headline matters to you, treat a masked row as "ask again later", not as "this person has no headline".
  • publicId is the join key, not fullName. People change their display name and their headline; the identifier after /in/ is what stays the same.
  • A wave of BLOCKED rows means the addresses you are running from are being asked to sign in. Lower "Max concurrency", leave residential proxy on, and re-run the blocked rows later. They cost you nothing the first time.
  • Store followers as a number and connections as text. LinkedIn caps the connection display at 500+, so forcing it into a numeric column silently loses the distinction between 500 and 30,000.

vs. alternatives

What it costsWhat you getTrade-off
This actor (linkedin-profile-lookup)$0.008 per profile found at the FREE tier, less on paid tiers, $0.00005 actor start, nothing for a missOne flat row per public profile: name, location, current company, current roles with dates, schools with dates, follower and connection counts, photo, and the headline and job title on the rows LinkedIn serves in fullPublic profile pages only. Current roles, not full career history; no degree, field of study or skills, because the logged-out page does not publish them; and the headline and job title arrive on a minority of rows, flagged by masked. It looks up profiles you name; it does not search for people.
HarvestAPI's LinkedIn profile actorslinkedin-profile-search is listed at $100 per 1,000 profilesA whole family: profile lookup, people search, company and post coverage, and the category's most-used profile scraper at a 4.77 ratingIf you need to find people by criteria rather than look up links you already hold, that is a search product and this is not one.
Clay$0.08 to $0.40 per enriched row in credits, on top of a seatA whole enrichment workspace: waterfalls across dozens of providers, plus the table and the sequencing around itIf you want one place that does everything and you are not counting rows, that is Clay. This is one column, priced per column, callable from Clay via its HTTP step.
Doing it yourselfYour time, plus residential proxy spend, plus keeping up with a sign-in wall that movesThe same fieldsWhat this absorbs: the structured-data parsing, the reduced-page detection so asterisks never reach your table, the block-versus-missing-versus-bad-input distinction, and retrying a blocked address instead of failing the row.

Prices for third-party tools are their published list prices as of September 2026 and are not tracked here. Check the vendor before relying on the comparison.

FAQ

Do I need a LinkedIn account, or to paste in a cookie? No. That is the point of this actor. It reads the public profile page exactly as a signed-out browser gets it. You are never asked for credentials, a session cookie or a li_at token, and no account of yours is put at risk by a run.

Why did a row come back with found: false? One of four reasons, and status says which. BLOCKED: LinkedIn asked that request to sign in instead of serving the page. NOT_FOUND: no public profile exists at that address any more, or the member has turned public visibility off. BAD_FORMAT: the input was not a member profile, most often a /company/ page pasted by mistake. REQUEST_FAILED: the request did not complete after retries. None of the four is charged.

What is masked: true? LinkedIn answers some requests with a reduced version of the profile in which job titles and past employers are replaced by rows of asterisks. Rather than pass that through, the actor leaves those fields empty and sets masked: true. Name, location, current employer, follower and connection counts, schools and photo still come through, so the row is worth having. Expect most rows to be flagged this way: on the fifteen fetches behind this build, the complete page came back four times. The decision looks like a per-request one on LinkedIn's side rather than a property of the profile or of where you run from, so re-running a masked row later is worth a try, and it costs you a second charge for that profile.

Why is education[].degree null? Because the logged-out profile page does not publish it. Degree and field of study are shown to signed-in members only. The field is kept in the row so the output shape never changes between runs, but it is left null rather than filled from a guess.

Why is there no skills column? Because the logged-out page has no Skills section. None of the fifteen public profile fetches this actor was built against carried one, in either version of the page, so a skills column would be empty on every row. It is better to say that here than to ship the column.

Does it return full career history? No. The public page shows the roles a member presents as current, and that is what experience contains. Everything earlier is behind the sign-in wall, and this actor does not go there.

Am I charged for a miss? No. Billing fires only when a real profile was read. Blocked rows, missing profiles and malformed input all produce a row explaining themselves, unless you turn on "Hide rows with no result", and none of them cost anything.

Do I need to configure a proxy? It is already configured. Residential proxy is the shipped default because LinkedIn's sign-in wall keys on the reputation of the address asking. You can change the group in the Advanced section, but lowering it is the most common reason a list comes back mostly blocked.

Is this a live fetch or a stored database? Live. Every run fetches the current page. Nothing is stored between runs, so a member who changed jobs yesterday shows the new one today.

Can an AI agent call this directly? Yes. It is on the Apify MCP server, so an agent in Claude, Cursor or any other MCP client can find and run it by name, and the REST endpoint above works from any script or workflow tool.

Personal data, and your responsibility

This actor reads public LinkedIn profile pages, which are personal data about identifiable people. It reads nothing behind the sign-in wall and it holds nothing between runs: each row is fetched live and written to your own dataset, which only you control.

Whether you may collect, store and use that data is a question about you and your purpose, not about this tool. If you are in the EU or the UK, or your subjects are, the GDPR applies to what you do next: you need a lawful basis, and duties around transparency, retention, and honouring a request to be erased. LinkedIn's own User Agreement also restricts automated collection, and it binds anyone using it under an account. Nothing here is legal advice, and running this actor is not a determination that your use is lawful. That call, and the compliance work behind it, is yours.