LinkedIn Public Profile Scraper (No Login)
Under maintenancePricing
from $1.25 / 1,000 results
LinkedIn Public Profile Scraper (No Login)
Under maintenanceScrape public LinkedIn profiles by slug or /in/ URL, with no login and no cookies. Each row carries the full name, headline, About text, dated work history and education with start and end years, location, current company, languages, profile photo and an exact follower count.
Pricing
from $1.25 / 1,000 results
Rating
0.0
(0)
Developer
String
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
1
Monthly active users
14 days ago
Last modified
Categories
Share
This Actor collects public LinkedIn profiles. You give it profile slugs or /in/ URLs and it
returns one row per person: the headline, the About text, work history and education with the years
attached, location, languages and an exact follower count. No LinkedIn account, cookie or session
token is used at any point.
What does the LinkedIn Profile Scraper do?
LinkedIn publishes each public profile as schema.org JSON-LD inside the page, and this Actor reads that structured data rather than handing rendered markup to a model. The difference shows up in three places a buyer cares about.
Work history comes back dated. positions and education are arrays, each entry carrying the
organisation, its LinkedIn URL and startYear and endYear, so tenure is a subtraction rather than
a parse of "3 yrs 4 mos". Values are stable: the same profile read twice gives the same strings,
where the model-driven extraction this replaced returned a job title as "Chair" on one run and
"Co-chair" on the next. And counts are exact, so followerCount arrives as 40560540 rather than
"40M".
The profile page's JSON-LD graph also holds the person's articles and posts, each with a stub author
node. The Actor picks the Person node that actually carries profile fields instead of the first
one it finds, so a prolific poster does not come back as an empty row.
What data does it extract?
| Field | Type | Description |
|---|---|---|
handle | string | The profile slug, e.g. "janedoe". Your join key |
fullName | string | Name as shown on the profile |
headline | string | The short line under the name |
about | string | The About section text |
jobTitles | string[] | Every title the profile lists, e.g. ["Founder", "Board Member"] |
location | string | City or region as stated on the profile |
country | string | Country from the same address block |
currentCompany | string | The first employer in positions, so the most recent one |
positions | object[] | Work history: { company, url, startYear, endYear } per role |
education | object[] | Schools: { school, url, startYear, endYear } per entry |
followerCount | number | Exact follower count, not rounded |
languages | string[] | Languages listed on the profile |
imageUrl | string | Profile photo URL |
sourceUrl | string | The canonical profile URL that was read |
collectedAt | string | ISO 8601 timestamp of the run |
An entry still in progress has endYear of null. Any field the profile does not publish is
null or an empty array, never a guess.
There are no email addresses and no phone numbers in this list, and the Actor does not look them up anywhere else. What you get is what the public profile shows.
Why scrape LinkedIn profiles?
Most of the value here is tenure. A job title on its own says very little; a title with a start year next to it tells you whether someone just took the seat or has been in it for six years, and that is usually what decides whether an outreach lands. Sales teams use it to enrich CRM records, recruiters use it to sort candidates by time in role without opening a single profile.
Other things people run it for:
- Executive move tracking. Re-run a watchlist weekly and diff
currentCompanyagainst the top entry ofpositions. - Org mapping before an account plan, from a list of slugs the team already has.
- Alumni and cohort lists, grouping people whose
educationyears overlapped at the same school.
How to use it
- Open the Actor on Apify Store and click Try for free.
- Paste your profiles into the Profiles field, one per line. Slugs (
janedoe) and full URLs (https://www.linkedin.com/in/janedoe) both work, and the two forms for the same person collapse to a single fetch. - Click Start. Profiles are fetched in parallel, five at a time by default.
- Export from the Dataset tab as JSON, CSV or Excel, or read it through the API. Slugs that did
not resolve are listed in the
SUMMARYrecord in the key-value store.
The Actor takes profiles you already have. It does not search LinkedIn, so pair it with a list you built elsewhere: from a CRM export, a conference attendee list, or the companies in a funding announcement.
Input
| Field | Type | Default | Description |
|---|---|---|---|
profiles | string[] | required | Public profile slugs or /in/ URLs, 1 to 500 per run |
maxItems | integer | 1000 | Cap on dataset rows, 1 to 50000. Free plans stop earlier, see below |
concurrency | integer | 5 | Profiles fetched in parallel, 1 to 10 |
{"profiles": ["janedoe", "https://www.linkedin.com/in/john-smith-7a3b21"],"concurrency": 5}
Only linkedin.com URLs are accepted. Anything else is rejected before it is fetched and reported
as a failed target, so a stray URL in a list of five hundred cannot route traffic somewhere else
under this Actor's pricing.
Output
One row per profile. Illustrative values for a fictional person, not a captured run.
{"handle": "janedoe","fullName": "Jane Doe","headline": "VP Engineering at Meridian Logistics","about": "I build platform teams and the tooling that keeps them shipping...","jobTitles": ["VP Engineering", "Engineering Manager"],"location": "Amsterdam","country": "NL","currentCompany": "Meridian Logistics","followerCount": 4821,"positions": [{ "company": "Meridian Logistics", "url": "https://nl.linkedin.com/company/meridian-logistics", "startYear": 2022, "endYear": null },{ "company": "Bellweather Systems", "url": "https://www.linkedin.com/company/bellweather-systems", "startYear": 2017, "endYear": 2022 }],"education": [{ "school": "Delft University of Technology", "url": "https://nl.linkedin.com/school/tudelft", "startYear": 2010, "endYear": 2014 }],"languages": ["Dutch", "English"],"imageUrl": "https://media.licdn.com/dms/image/v2/example/profile-displayphoto.jpg","sourceUrl": "https://www.linkedin.com/in/janedoe","collectedAt": "2026-08-20T09:31:02.118Z"}
Reliability
Measured across 30 profile slugs in one run: every profile that exists was collected, 19 of 19. The other 11 were slugs that do not resolve on LinkedIn, and they were reported as failures rather than emitted as empty rows.
Because fields come from the profile's own structured data, a value is either present and correct or absent. It does not drift between runs for the same profile.
A profile that cannot be read lands in the run's SUMMARY under failures with the URL and the
error, and the rest of the batch still returns. A run where every profile failed exits with an
error, so a schedule notices instead of silently recording an empty day.
Limitations
Public profile fields only. No connections, no posts or activity feed, no skills or endorsements, no recommendations, and no search or discovery. Profiles set to private publish no JSON-LD, so they return nothing and are reported as failures.
positions and education carry years, not months, because years are what the public profile's
structured data holds. Up to 500 profiles per run, one row each.
How much does it cost?
Pay per event: you are charged per result row written to the dataset, plus Apify's own platform usage for the run. The current per-result price is on this Actor's Store page under Pricing.
A slug that does not resolve writes no row and costs nothing, and duplicate entries for the same person are fetched and billed once.
Runs started from an Apify free plan stop at 250 requests and 250 results, and say so in the
run's status message. Any paid plan runs the full input and whatever maxItems you set. The limit
exists because this Actor fetches through our own anti-bot infrastructure, which Apify does not
cover for free-plan runs. It binds on requests as well as rows so that a long input list cannot
spend those fetches on rows the run will never return.
Using it with the Apify API
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('usestring/linkedin-profiles').call({profiles: ['janedoe', 'https://www.linkedin.com/in/john-smith-7a3b21']});const { items } = await client.dataset(run.defaultDatasetId).listItems();const thisYear = new Date().getFullYear();for (const person of items) {const current = person.positions.find((role) => role.endYear === null);const years = current?.startYear ? thisYear - current.startYear : null;console.log(person.fullName, person.currentCompany, years === null ? '' : `${years} yrs in role`);}
The Python client and the REST API take the same input. The run's SUMMARY record, with the item
count and every slug that failed, is in the default key-value store.
Is it legal to scrape LinkedIn profiles?
This Actor reads public LinkedIn profiles as a logged-out visitor. It sends no account credentials,
no session cookie and no li_at token, and it reads nothing that a signed-in member can see but a
signed-out one cannot. It does not create accounts, send connection requests or interact with the
platform in any way.
It returns no contact details. Email addresses and phone numbers are not on the public profile, and the Actor does not enrich, guess or look them up from another source.
What it does return is still personal data. Names, employers and education relate to identifiable people, so GDPR, the CCPA and their equivalents apply to what you do with the rows once you have them: you need your own lawful basis for holding and using them, and a person may have the right to ask you to delete their record. Whether the collection itself is permitted is a separate question from whether your intended use is, and the second one is the one that usually bites.
Please treat this section as orientation rather than legal advice. If people data is core to what you are building, get your own.
Related actors
- TikTok Profile Scraper
- Indeed Job Listings Scraper with Salaries
- Glassdoor Jobs Scraper - Pay and Ratings
- Upwork Freelance Jobs and Budgets Scraper
- Wellfound Startup Jobs Scraper
A common pairing is this Actor with one of the job scrapers: the job board tells you a company is hiring, and the profiles tell you who already runs the team.
FAQ
Do I need a LinkedIn account, cookies or a session token? No. Only the public, logged-out profile page is read, and no credentials of any kind are supplied.
Does it return email addresses or phone numbers? No. Those are not on the public profile, and this Actor does no contact enrichment of any kind. If you need contact data, that is a different tool and a different legal analysis.
Does the work history include dates?
Yes. Each entry in positions has startYear and endYear, with endYear null for a current
role, and education follows the same shape. Years, not months.
Is the follower count exact?
Yes. It comes from the profile's structured data as an integer, so you get 4821 rather than
"4.8K".
Can I search LinkedIn for people to scrape? No. You supply the profiles. There is no keyword search, no filter by company or title, and no discovery step in this Actor.
What happens with a private profile or a slug that does not exist?
It is recorded under failures in the run's SUMMARY and the rest of the batch still returns. A
private profile publishes no structured data, so there is nothing to read and nothing is invented in
its place.
Feedback
If a profile came back with a field you expected to see filled, open an issue from this Actor's Store page and include the slug. Requests for fields that are on the public profile but not in the table above are worth sending too.