Read a public LinkedIn profile

The signed-out profile page, as JSON, from a linkedin.com/in URL.

People searching for how to scrape LinkedIn usually want the public profile: headline, location, about, experience, and a follower count. That page is what a signed-out visitor sees. GET /v1/linkedin/profile returns it. The route is in beta. It is not LinkedIn's official API, and it does not log in.

Send your SocialScrape key in x-api-key. See authentication.

The request#

The only data parameter is url, and it is required. The shape is linkedin.com/in/<slug>. There is no name search on this route. If the member hides the public profile, the answer is not_found. A URL this route does not accept is unsupported_url. A broken parameter is invalid_params. Do not retry those three.

The recorded request is a public profile URL.

curl
curl -G "https://api.socialscrape.io/v1/linkedin/profile" \
  -H "x-api-key: $SOCIALSCRAPE_API_KEY" \
  --data-urlencode "url=https://www.linkedin.com/in/williamhgates"
Python
import os
import requests

params = {
    "url": "https://www.linkedin.com/in/williamhgates",
}
res = requests.get(
    "https://api.socialscrape.io/v1/linkedin/profile",
    headers={"x-api-key": os.environ["SOCIALSCRAPE_API_KEY"]},
    params=params,
)
body = res.json()

if body["ok"]:
    print(body["data"])
else:
    print(body["error"]["code"], body["error"]["message"])
TypeScript
const url = new URL("https://api.socialscrape.io/v1/linkedin/profile");
url.search = new URLSearchParams({
  "url": "https://www.linkedin.com/in/williamhgates"
}).toString();
const res = await fetch(url, {
  headers: { "x-api-key": process.env.SOCIALSCRAPE_API_KEY! },
});
const body = await res.json();

if (body.ok) {
  console.log(body.data);
} else {
  console.error(body.error.code, body.error.message);
}

trim, raw and max_age_days work as on other GETs. This endpoint is cacheable for 30 days. A cached hit costs 0 credits. See caching.

What you get#

data is a profile. platform is linkedin. Shared fields: id, handle, name, headline, url, bio (the about text), avatar_url, banner_url, location, verified, is_private, external_url, links, created_at. stats.followers is the follower count shown publicly. stats.following, stats.posts, stats.likes and stats.views are null when the public page does not have them.

The LinkedIn-specific blocks are in extra:

  • experience: title, company, company_slug, company_url, start, duration, is_current.
  • education: school, school_url, start_year, end_year.
  • current_companies: strings.
  • articles: title, url, summary, published_at, likes, comments, image_url.
  • recent_posts: id, text, url, likes, published_at.
  • similar_profiles: name, headline, location, url, followers.
  • connections and connections_count. connections is the text LinkedIn prints, not an array of members.
  • badges and source.

The endpoint description also lists skills, courses and recommendations. The recorded sample is shortened and does not include those keys. If a live response omits them, they were not on the page. Do not backfill.

Sample. The recorded profile is shortened. Follower counts and experience rows in that file are the sample. Author-style placeholders are not an issue on this particular recording the way they are on anonymised comment samples, but the numbers are still a recording, not a live pull you should cite as today's total.

extra.recent_posts is a short list, not the member's archive. To read one of them in full, pass url to GET /v1/linkedin/post. That returns the full text, reactions, comment count and the top public comments in extra.top_comments. Company pages are a different route, GET /v1/linkedin/company, and their posts are GET /v1/linkedin/company/posts. A person URL will not work on the company route.

Cost#

One successful profile is 1 credit. Opening a recent post is another credit. Failures are free, including not_found when the profile is hidden. Cached repeats are free with max_age_days.

New accounts get 100 credits once, no card. Pack credits never expire. Monthly credits reset. See pricing and credits.

Limits#

You get the signed-out page. You do not get email, phone, a connection list, InMail, or anything a member limited to logged-in viewers. not_found is the honest answer for a hidden profile. Treat it as hidden or unknown, not as an empty career history.

connections_count can disagree with a rounded connections string. Keep both. Experience start and duration are the strings LinkedIn showed. They are not a guaranteed ISO date range on every row.

The team allows 30 requests a minute on free credits, 300 with a paid pack, and 120 to 1,200 on monthly plans. 429 rate_limited is retryable and costs 0. See rate limits and errors.

The API is in early access. This route is beta, so fields can be added. Null stays null.

Next#

The sample and the parameter table are on the LinkedIn profile API page, the tutorial and the reference. One post is the LinkedIn post API. Company posts are covered in Get public LinkedIn posts. The hub is the LinkedIn API.

Company pages and person pages are different objects. Do not send a /company/ URL to this route.

Questions

Can I pass a name instead of a URL?

No. The parameter is url, a linkedin.com/in/<slug> link. A person who hides the public profile answers not_found.

Do I get their connections?

You get extra.connections (the text LinkedIn shows) and extra.connections_count when it is on the public page. You do not get the list of people they are connected to.

Are skills always present?

The endpoint description includes skills, courses and recommendations. A shortened sample can omit keys. A missing key or a null means that block was not in the payload. Do not invent an empty list.

How do I read one of the recent posts in full?

extra.recent_posts has id, text, url, likes and published_at. Pass that url to GET /v1/linkedin/post for the full post and top public comments.

Build on social data early.

Developers and agent builders get the first keys.

Get early access