Back to Blog
LinkedIn

Why LinkedIn Says a Public Profile Isn't Available (and How to Still Get the Posts)

October 16, 2026
9 min read
S
By SociaVault Team
LinkedInpublic profileLinkedIn APILinkedIn posts

Why LinkedIn Says a Public Profile Isn't Available (and How to Still Get the Posts)

Here's a support conversation we have about once a week. Someone's pulling LinkedIn profiles. Most work. A few come back with "Account is private or just not publicly available." So they ask the person, who checks their settings and says: public profile visibility is on, and so is "Articles & activity." The profile even shows up in Google.

Then why is it blocked?

Short answer: it isn't the member's settings. LinkedIn decides, per profile, whether a signed-out visitor gets to see the page at all, and it makes that call before any privacy setting comes into it. We tested this properly to be sure, and the numbers are worse than most people expect.

What we tested

We took 73 profile URLs from people who'd recently published public posts about product management. These are people actively putting their work out there, about as public as LinkedIn users get. Then we did two things:

  1. Requested profiles straight from LinkedIn, as an ordinary signed-out browser would. No API involved.
  2. Requested profiles through our API, and compared the results.

What LinkedIn sends a signed-out visitor

When LinkedIn lets you in, you get the full public profile: in our run, pages between 233KB and 778KB. When it doesn't, you get a status code of 999 and a stub page of about 1KB that tells you to sign in.

Of the first 15 profiles we checked directly, 7 loaded and 8 returned the 999 wall. Same browser, same network, seconds apart. The only thing that changed was the profile.

And the API agreed with LinkedIn every time. The three profiles we picked that LinkedIn served came back through the API with full data, recentPosts and follower counts included. The three that hit the 999 wall came back as "Account is private or just not publicly available." Across the API sample overall, 5 of 14 profiles were available. That's the reality for ordinary members: you should expect most personal profiles to be blocked from signed-out access.

Why 999 means two different things

Halfway through our direct test, something interesting happened. We'd put a couple of very famous profiles in as controls, the kind LinkedIn always serves. The first one loaded fine. By the second control, about sixteen requests in, it was returning 999 too. By the end, every request did.

That's the other meaning of 999: LinkedIn is rate-limiting you. It uses the same code, and the same tiny sign-in page, for "this profile isn't available to guests" and "you've made too many requests."

This matters if you're debugging. If you test a profile from your laptop after hammering LinkedIn for a while, you'll get a 999 and conclude the profile is blocked, when really your IP is. Always test against a control profile you know is open. If the control fails, the problem is you, not the profile.

Why the member's settings don't fix it

The "Public profile visibility" toggle controls what appears on your public profile if LinkedIn decides to show it to a guest. It doesn't force LinkedIn to show it. The decision to serve or wall a profile happens first, and LinkedIn doesn't publish how it makes it.

That's also why a profile can appear in Google and still be blocked. Search engines are crawled under different terms than an anonymous visitor, and Google may simply be showing a copy it indexed earlier.

How stable is it? In our tests, very. The same profile gave the same answer across repeated attempts. We did once see a profile that normally loads return a single failure the next day, so treat it as "usually consistent," not guaranteed.

The route that does work: search, then fetch

Here's the useful part. A blocked profile doesn't mean blocked posts. LinkedIn treats individual posts differently from profiles, and public posts usually stay reachable.

So instead of going through the profile, go around it:

  1. Find their posts with search. /linkedin/search/posts takes a query, and searching a person's name usually surfaces their public posts.
  2. Fetch each post directly. /linkedin/post takes the post URL and returns the full text and engagement.

We tested this on one of the blocked people from our sample. Their profile returned the "not publicly available" error. Search still found their post, and fetching it returned the whole thing: 2,074 characters of text, 4,506 likes, 169 comments and the publish date.

const API = "https://api.sociavault.com/v1/scrape";
const KEY = process.env.SOCIAVAULT_API_KEY;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

// Some list fields arrive as index-keyed objects rather than arrays.
const toArray = (x) => (Array.isArray(x) ? x : x ? Object.values(x) : []);

async function get(path, params) {
  const res = await fetch(`${API}/${path}?${new URLSearchParams(params)}`, {
    headers: { "x-api-key": KEY },
  });
  return res.json();
}

// slug = the part after linkedin.com/in/, e.g. "jane-doe-123"
async function postsByPerson(name, slug, maxPages = 3) {
  const found = [];
  for (let cursor = 1; cursor <= maxPages; cursor++) {
    const body = await get("linkedin/search/posts", { query: name, cursor });
    const posts = toArray(body?.data?.posts);
    // Search returns other people's posts too. Keep only this person's.
    for (const p of posts) {
      if (String(p?.url ?? "").includes(`/posts/${slug}_`)) found.push(p);
    }
    if (!posts.length || !body?.data?.cursor) break;
    await sleep(800);
  }
  return found;
}

const posts = await postsByPerson("Jane Doe", "jane-doe-123");
for (const p of posts) {
  const full = await get("linkedin/post", { url: p.url });
  const d = full?.data ?? {};
  console.log(
    d.datePublished,
    d.likeCount,
    d.commentCount,
    String(d.description ?? "").slice(0, 80),
  );
  await sleep(800);
}

The same thing in Python:

import os, time, requests

API = "https://api.sociavault.com/v1/scrape"
HEADERS = {"x-api-key": os.environ["SOCIAVAULT_API_KEY"]}

def to_list(x):
    return x if isinstance(x, list) else list((x or {}).values())

def get(path, **params):
    return requests.get(f"{API}/{path}", params=params, headers=HEADERS, timeout=90).json()

def posts_by_person(name, slug, max_pages=3):
    found = []
    for cursor in range(1, max_pages + 1):
        body = get("linkedin/search/posts", query=name, cursor=cursor)
        posts = to_list((body.get("data") or {}).get("posts"))
        found += [p for p in posts if f"/posts/{slug}_" in str(p.get("url", ""))]
        if not posts or not (body.get("data") or {}).get("cursor"):
            break
        time.sleep(0.8)
    return found

Two details that'll save you time:

  • Filter by the URL slug. In our sample search, the ten results came from several different authors. A genuine post by a person has their profile slug right in the URL: linkedin.com/posts/jane-doe-123_.... Matching on that is far more reliable than matching on the display name, which other people share.
  • The cursor tops out at 11. Search pages are numbered, and cursor must be between 1 and 11. Add date_posted (last-day, last-week, last-month and so on) if you only want recent posts.

If you're monitoring the same people regularly, that's the whole loop: search by name on a schedule, keep the posts whose URL matches the slug, and fetch the full text of anything new. We've written separately about pulling LinkedIn data without the official API and getting transcripts from LinkedIn video posts.

When the profile does load

For the profiles LinkedIn does serve, the profile endpoint is still the richest source. A successful response includes name, location, followers, about, experience, education and the person's recent posts. Those posts are under recentPosts, not posts, which trips people up. If your code reads data.posts from a profile response, it'll look empty even when it worked.

A sensible pipeline tries the profile first and falls back to search when it gets the "not publicly available" error. You get full profile data where it exists, and posts everywhere else.

The honest limits

  • You can't unblock a profile. If LinkedIn walls it for guests, profile-level data (experience, education, connections) isn't available. Only the posts route remains.
  • Search finds what it finds. It relies on posts being indexed. A person who rarely posts, or posts only to their network, may not turn up at all.
  • Posts set to connections-only are private. We only fetch public content.
  • Common names need the slug filter. Without it, you'll collect strangers' posts.
  • It changes over time. LinkedIn adjusts guest access. What we measured here is a snapshot, not a promise.

Frequently Asked Questions

Why does LinkedIn say a profile is private when it's set to public?

LinkedIn decides per profile whether signed-out visitors can see it, before the member's privacy settings apply. A profile can have public visibility switched on and still be walled. The member can't change this from their settings.

What does LinkedIn's 999 error mean?

It's LinkedIn's request-denied status. It shows up both when a profile isn't served to guests and when you've sent too many requests. Test with a profile you know is open: if that fails too, you're being rate-limited.

Can I still get posts from a blocked LinkedIn profile?

Usually, yes. Public posts are handled separately from profiles. Search the person's name with /linkedin/search/posts, keep results whose URL contains their profile slug, then fetch each post with /linkedin/post.

Why does the profile show up in Google if it's blocked?

Search engines aren't treated like anonymous visitors, and the result may be an older indexed copy. Appearing in Google doesn't mean LinkedIn will serve the page to a signed-out request.

Is the block permanent?

It was consistent in our tests, with one transient failure on a profile that normally loads. LinkedIn changes its guest access over time, so treat any single result as current, not permanent.

Where are the posts in a LinkedIn profile response?

Under recentPosts. There's no posts field on a profile response, so code that reads data.posts will see nothing.


Need LinkedIn posts from people whose profiles keep failing? Sign up for 50 free credits and try the search-then-fetch loop on your own list.

Found this helpful?

Share it with others who might benefit

Ready to Try SociaVault?

Start extracting social media data with our powerful API. No credit card required.