# LinkedIn Profile, Certifications & Company Data Extractor (`dataspryva/linkedin-profile-certifications-and-company-data`) Actor

Turn LinkedIn profile URLs into structured records with work history, education, certifications, honors, volunteer work, personal projects and current-employer company details, with no login required.

- **URL**: https://apify.com/dataspryva/linkedin-profile-certifications-and-company-data.md
- **Developed by:** [Dataspryva](https://apify.com/dataspryva) (community)
- **Categories:** Social media, Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## LinkedIn Profile, Certifications & Company Data Extractor

Give this actor a list of public LinkedIn profile URLs (or just usernames) and it returns one
structured record per person: identity, About text, current company and school, the public
connection indicator, work and education links, every self-authored section LinkedIn shows to
logged-out visitors, and firmographics for the person's current employer. No LinkedIn account,
cookie, session token, or proxy setup is required.

### What it does

- Reads the public guest view of each profile, plus the richer server-rendered view LinkedIn
  sends to link-preview crawlers when available
- Extracts certifications with credential IDs and verification links, honors and awards, test
  scores, organization memberships, volunteer work, projects, publications, patents, courses,
  instructor courses, language skills, services, recommendations received, public skill tokens,
  badges, and listed websites
- Reads the top-card layer for the current company link, current school, followers, and the
  public connections figure
- Optionally reads the current employer's own public LinkedIn page for company size, industry,
  headquarters, address, founded year, follower count, website, logo, description, slogan,
  organization type, and specialties
- Never invents data: a field LinkedIn withholds or masks is omitted from that record, and a
  profile that belongs to a different member is discarded rather than pushed
- Omits empty values recursively — no `null`, empty string, or empty list reaches the dataset

### Output per profile

- `name`, `headline`, `location`, `summary`
- `headlineRedacted` — `true` when LinkedIn replaced a withheld headline with the current company
  in its public preview line (the replacement itself is not pushed as a headline)
- `profileUrl`, `profilePicture`
- `currentTitle` — current role title when LinkedIn exposes it publicly for this profile
- `allTitles[]` — titles published in the profile's structured data (masked entries removed)
- `currentCompany` — current employer with `name`, `url`, `slug`, `companyId` when the company
  link is numeric. With `enrichCompany` on it also carries `employeeCount`, `size`, `industry`,
  `website`, `headquarters`, `address`, `foundedYear`, `followersCount`, `description`, `slogan`,
  `organizationType`, `logoUrl`, and `specialties[]`
- `currentSchool` — school shown on the profile top card (`name`, `url`)
- `currentPositions[]`, `pastPositions[]` — `company`, `companyUrl`, `startDate`, `endDate`,
  `location`, `description`; when LinkedIn renders the full Experience list, entries also carry
  `title`, `dateRange`, and `duration`
- `experiences[]` — `currentPositions` and `pastPositions` combined
- `education[]` and `educations[]` — the same list under both keys (`school`, `schoolUrl`,
  `startDate`, `endDate`, plus `degree`, `fieldOfStudy`, `gpa`, `dateRange` when LinkedIn's
  richer public view includes them)
- `followersCount`, `connectionsCount` (exact number when public), `connectionsText` (for example
  `"500+"` when only the capped indicator is public)
- `recentArticles[]` — recent posts or articles with `title`, `url`, `publishedDate`, `text`, and
  `likes`
- `certifications[]` — `name`, `issuer`, `issuerUrl`, `issueDate`, `credentialId`,
  `credentialUrl`
- `recommendations[]` — `recommender`, `recommenderUrl`, `text`
- `languages[]` — `language`, `proficiency`
- `services[]` — `name`, `url`
- `publications[]` — `title`, `url`, `publisher`, `date`, `description`
- `patents[]` — `title`, `url`, `filedDate`, `number`, `description`
- `courses[]` — `title`, `number`
- `instructorCourses[]` — `title`, `url`, `duration`
- `honorsAndAwards[]` — `title`, `issuer`, `date`, `description`
- `testScores[]` — `name`, `score`, `date`
- `organizations[]` — `name`, `position`, `description`
- `volunteerExperience[]` — `role`, `organization`, `description`
- `projects[]` — `title`, `dateRange`, `description`
- `skills[]` — public skill names when the profile exposes them
- `badges[]`, `isTopVoice`, `isCreator` — public profile badges
- `websites[]` — `label`, `url` for personal or portfolio links
- `inputUrl` — the value you supplied for this row
- `order` — zero-based position in your input list
- `scrapedAt` — ISO 8601 timestamp of extraction

When LinkedIn serves only a sign-up preview for a profile, the row is built from the available
preview metadata and contains the identity-level fields only.

#### Status rows

A run can add one status row (disable with `includeStatusRows: false`):

- No profiles readable: `_status: "no_data"`, `_reason`, `_message`, `_help`, `scrapedAt`
- Some profiles readable: `_status: "partial_results"`, `_reason`, `_failureBreakdown`,
  `_message`, `scrapedAt`, alongside the successful rows

Failure reasons: `auth_wall` (profile hides itself from guests), `not_found` (confirmed 404),
`blocked` (all access paths failed without a 404), `identity_mismatch` (LinkedIn resolved the URL
to a different member), `invalid_url`, and `error`. Filter on `_status` if you want only profile
rows.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `profileUrls` | array | – | Required. Public LinkedIn profile URLs or bare usernames. Accepts full URLs, `linkedin.com/in/name`, `in/name`, regional subdomains, and URLs with query parameters. |
| `enrichCompany` | boolean | `true` | Also read the current employer's public company page for firmographics. One fetch per unique company per run. |
| `includeStatusRows` | boolean | `true` | Add one structured status row when a run yields no profiles or only some of the requested profiles. |

#### Example: several profiles

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

#### Example: profile only, no employer enrichment

```json
{
  "profileUrls": ["https://www.linkedin.com/in/charlywargnier"],
  "enrichCompany": false
}
```

#### Example: records only, no status rows

```json
{
  "profileUrls": ["https://www.linkedin.com/in/abdulmananraja"],
  "includeStatusRows": false
}
```

### Use cases

- **Recruiting and candidate research** — review public certifications, education, languages,
  and project history before an outreach
- **Sales and CRM enrichment** — append current role, employer, and company firmographics to a
  list of profile URLs
- **Credential and award research** — collect public certifications, honors, publications, and
  patents across a population
- **Talent-market analysis** — study the distribution of public skills, languages, and employers
  in a cohort
- **Profile monitoring** — refresh a saved URL list and compare current employer, school, and
  public sections over time

### How access works

The actor selects the cheapest working public access path automatically: a direct browser-style
request, then LinkedIn's public link-preview view, then an anti-bot proxy only if both free
paths are blocked. For company pages it also tries a regional host and a public translation
mirror before the proxy. You never configure a proxy, and you never supply a cookie, login, or
API key.

### Honest limits

- LinkedIn withholds the real headline, per-role titles, and degree/field for most logged-out
  profiles. The actor pushes them only when the public page actually renders them; otherwise the
  field is absent.
- The exact connection count is usually hidden. The public `500+` form is returned as
  `connectionsText`; `connectionsCount` appears only when an exact number is public.
- Public skills are rare in the guest view, so `skills` is often absent.
- Email addresses and phone numbers are not public. The actor never guesses or fabricates them.
- A profile whose owner hides it from logged-out visitors returns a status row, not data.
- Search by name and company-page listing are separate actors in this suite; this actor starts
  from profile URLs or usernames.

### FAQ

**Do I need a LinkedIn account or cookies?**
No. The actor never asks for LinkedIn credentials, session cookies, or tokens.

**Does this work for ordinary profiles or only famous ones?**
It is built for everyday professional profiles. LinkedIn's public link-preview view serves the
same server-rendered sections for ordinary accounts; the actor reads that view, not a cached
snapshot.

**Why are some fields missing on a particular profile?**
LinkedIn either hides that field from logged-out visitors or the profile owner never filled it
in. The record omits it instead of returning a placeholder.

**Can I get an email address or phone number?**
No. Those are not part of the public guest view, and this actor does not use third-party contact
databases.

**Does it support non-US profiles?**
Yes. Regional LinkedIn profile URLs are normalized to the canonical profile, and the public
sections are read in the locale LinkedIn serves.

**Is the data live?**
Yes. Every record is read from the live public page at run time.

**Is this affiliated with LinkedIn?**
No. It reads publicly available pages and is not affiliated with or endorsed by LinkedIn.

# Actor input Schema

## `profileUrls` (type: `array`):

Public LinkedIn profile URLs (https://www.linkedin.com/in/username) or bare usernames. Full URLs, 'in/username' shorthand, regional subdomains and URLs with tracking parameters are all accepted.

## `enrichCompany` (type: `boolean`):

Also read the current employer's own public LinkedIn page for employee count, size range, industry, headquarters, address, founded year, followers, website, logo, description, slogan, type and specialties. Uses the actor's free public access path; one fetch per unique company per run.

## `includeStatusRows` (type: `boolean`):

Add one structured status row when a run returns no profiles or only some of the requested profiles (for example a 404 or a privacy-restricted profile). Turn off for a dataset of profile records only.

## Actor input object example

```json
{
  "profileUrls": [
    "https://www.linkedin.com/in/williamhgates"
  ],
  "enrichCompany": true,
  "includeStatusRows": true
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset containing all scraped LinkedIn profile records.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "profileUrls": [
        "https://www.linkedin.com/in/williamhgates"
    ],
    "enrichCompany": true,
    "includeStatusRows": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataspryva/linkedin-profile-certifications-and-company-data").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "profileUrls": ["https://www.linkedin.com/in/williamhgates"],
    "enrichCompany": True,
    "includeStatusRows": True,
}

# Run the Actor and wait for it to finish
run = client.actor("dataspryva/linkedin-profile-certifications-and-company-data").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "profileUrls": [
    "https://www.linkedin.com/in/williamhgates"
  ],
  "enrichCompany": true,
  "includeStatusRows": true
}' |
apify call dataspryva/linkedin-profile-certifications-and-company-data --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataspryva/linkedin-profile-certifications-and-company-data"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/iIXoObnaUV7HWGusQ/builds/0lmeugxvN8unWYVXn/openapi.json
