LinkedIn Profile Scraper
Pricing
from $2.67 / 1,000 results
LinkedIn Profile Scraper
Extract public LinkedIn profiles without cookies or an account: name, headline, location, follower count, current employer, education, work history, plus the person's public posts and articles. HTTP-only, no login, no browser.
Pricing
from $2.67 / 1,000 results
Rating
0.0
(0)
Developer
Farhan Febrian Nauval
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
13 days ago
Last modified
Categories
Share
Extract public LinkedIn profiles — no cookies, no account, no browser. Give it profile URLs or slugs and it returns the person's name, headline, location, follower count, work history, education, and the public posts and articles shown on their profile.
HTTP-only (curl_cffi), public data only. Nothing behind the login wall is touched.
Input
| Field | Type | Default | Description |
|---|---|---|---|
profiles | array | required | Profile URLs (https://www.linkedin.com/in/williamhgates) or bare slugs (williamhgates) |
includePosts | boolean | true | Public posts embedded in the profile page, plus their activity IDs |
includeArticles | boolean | true | LinkedIn articles authored by this person |
maxAttempts | integer | 4 | Retries (fresh exit IP + different country host) before accepting a redacted render |
maxConcurrency | integer | 4 | Profiles in parallel. Keep it low |
proxyConfiguration | object | RESIDENTIAL | Residential strongly recommended |
Output
One row per input, always — including failures, so downstream joins never silently lose a key.
{"_input": "https://www.linkedin.com/in/satyanadella","_source": "S1-jsonld+html","_scrapedAt": "2026-09-06T16:08:08Z","_host": "uk.linkedin.com", // which country host served this render"_proxyCountry": "GB","_masked": false, // true when LinkedIn redacted the work history"slug": "satyanadella","profileUrl": "https://www.linkedin.com/in/satyanadella",// --- raw schema.org Person node, upstream field names kept verbatim ---"name": "Satya Nadella","jobTitle": ["Chairman and CEO", "Member Board Of Trustees"],"description": "As chairman and CEO of Microsoft, I define my mission…","address": { "@type": "PostalAddress", "addressLocality": "Redmond, Washington, United States" },"worksFor": [{ "name": "Microsoft", "url": "…/company/microsoft","member": { "startDate": "2014-02" } }],"alumniOf": [{ "name": "Starbucks", "member": { "startDate": 2017, "endDate": 2024 } }],// --- derived conveniences ---"followerCount": 12152113,"experienceEducationCards": [{ "text": "…", "logo": "…" }],"posts": [ /* schema.org DiscussionForumPosting nodes */ ],"activityIds": ["7502385664945111040"] // feed into a post-detail run}
Failure rows carry _error (not_found, blocked, bad_input, unexpected_shape) and
_errorDetail, and no payload.
How it works
LinkedIn ships a <script type="application/ld+json"> block with a schema.org Person
node on every public profile. That is the primary source — it survives redesigns that break
CSS selectors. The HTML pass only adds the rendered Experience/Education cards.
Redacted work history, and why it retries
LinkedIn does not treat every anonymous visitor the same. On some renders the work history
comes back as asterisks ("jobTitle": ["********"]); on others, for the same profile, it is
complete.
It is worth being precise about what drives that, because the obvious explanations are all wrong. Measured on 2026-09-06, three profiles fetched under three proxy modes:
| Proxy | williamhgates | satyanadella | reidhoffman |
|---|---|---|---|
| Residential | complete | complete | redacted |
| Datacenter | complete | complete | complete |
| None | complete | redacted | redacted |
The same profiles flipped between redacted and complete across consecutive runs on the same proxy mode. So it is not the profile, not the country subdomain, and not the proxy type — it is decided per request.
That makes retrying the correct and only fix, with one catch: the retries have to be
genuinely independent. An earlier build walked nine country subdomains on a single shared
session and got a redacted render nine times in a row. Every attempt now gets its own exit
IP and its own cookie jar; the country subdomain is varied alongside it only to keep the
request coherent (a GB exit IP asking uk.linkedin.com is an ordinary visitor).
Measured effect on a 6-profile run with maxAttempts: 6:
| Shared session, 9 hosts | Independent sessions, 6 attempts | |
|---|---|---|
| Complete | 1 of 4 | 5 of 6 (4 on the first attempt) |
If every attempt is redacted the row is still emitted, with _masked: true and
_warning: experience_masked_by_linkedin. Name, headline, location and follower count are
correct on a redacted render — only parts of the work history are hidden.
Block detection
Two things are deliberately not used to detect a block:
- Status code alone. LinkedIn serves its guest sign-in wall as a
200with a full-size body, and answers a throttled request with999(its own status code, not an HTTP one). - Body substrings. Every LinkedIn page carries the LiX flag
data-recaptcha-v3-integration-lix-value, so a substring test for"captcha"marks good renders as blocked. That false positive threw away an entire cloud run's worth of valid data before it was caught.
What is used: the final URL (a redirect to /authwall, /checkpoint/, /uas/login),
and a positive data marker — the presence of the Person node. A render without one is
the wall, whatever its status code or size.
TLS fingerprinting
LinkedIn's guest surface does not gate on JA3/JA4. The profile ladder
chrome131 / chrome146 / firefox144 / safari2601 was run against /in/<slug> from one
IP: all four returned an identical 200 with the same JSON-LD payload. The gate here is IP
reputation and request rate. chrome146 is the default because it is the most common real
UA; rotation is deliberately not implemented because it buys nothing.
Known limits
| Limit | Detail |
|---|---|
| Work history redaction | Decided per request. maxAttempts: 6 cleared it for 5 of 6 profiles; raise it if you need higher completeness |
| No pagination of posts | /in/<slug>/recent-activity/ redirects back to the profile for anonymous visitors. You get the posts embedded in the profile page, nothing deeper |
| Rate limiting is aggressive | A single IP is throttled to 999 within a few dozen requests. Use a residential proxy; a bare local run will produce blocked rows almost immediately |
| Contact details | Email and phone are never exposed to anonymous visitors and are not returned |
| Not covered | company/<slug>/people/ and company/<slug>/posts/ redirect to the login wall — employee lists are not obtainable this way |
Related
- LinkedIn Company Profile Scraper — company overviews
- LinkedIn Jobs Scraper — public job postings via the guest jobs API
Use activityIds from this actor's output as input to a post-detail run.