Developer Docs

LinkedIn Scraper API Guide

Scraping is asynchronous: submit a run → poll → fetch data. The full flow is in Quick Start; the shared response envelope / run state machine / billing / error codes are in Auth & Error Handling. This page only lists each endpoint's submit target fields and output fields.


Common Conventions

Item Value
Base URL https://api.antsdata.com/v1
Method POST (submit run)
Auth Authorization: Bearer ants_xxxxxxxxxxxx
Content-Type application/json

The submit body is always { "deliveryMode": "async", "recordLimit": 1000, "targets": [ … ] }; the fields of each targets[] element are listed in the "Target fields" table for each endpoint below. Submit returns HTTP 201 + { "code": 0, "message": "ok", "data": { "id": <run id>, "status": "queued" } }. Then poll GET /v1/scraper/runs/{id} until succeeded and fetch records via GET /v1/scraper/runs/{id}/records.

💡 You can also use deliveryMode: "sync" (small jobs block until terminal, auto fallback to polling on timeout) — see quick-start · Sync mode.

Endpoints:

Endpoint Path Description
Profile /v1/scraper/linkedin/profile Personal profile (with experience / education / skills / languages / certifications)
Company /v1/scraper/linkedin/company Company page details
Jobs /v1/scraper/linkedin/jobs Job listing search
Profile Posts /v1/scraper/linkedin/posts Posts from a personal profile
Company Posts /v1/scraper/linkedin/posts-company Posts from a company page

Profile

Extract a profile's public information by URL (including work experience, education, and skills). Each URL is one target; submit multiple in a single run for batching.

Endpoint: POST /v1/scraper/linkedin/profile

Target fields (each targets[] element):

Field Type Required Description
profileUrl string ✅ Required Profile URL (one per row; must contain /in/<vanity>)

Output fields (each record):

Field Type Description
fullName string Full name
headline string Headline
location string City
industry string Industry
summary string Detailed bio
profileUrl string Profile URL
profileImageUrl string Avatar URL
bannerImageUrl string Banner image URL
connections number Number of connections
followersCount number Follower count
experience array Work experience
experience.title string Job title
experience.company string Company name
experience.companyUrl string Company URL on LinkedIn
experience.dateRange string Date range of the position
experience.location string Location of the position
experience.description string Description of the position
experience.isCurrent boolean Whether this is the current position
education array Education
education.school string School name
education.degree string Degree
education.fieldOfStudy string Field of study
education.dateRange string Date range of the education entry
skills array Skill tags
languages array Languages
languages.name string Language name
languages.proficiency string Proficiency level
certifications array Certifications
certifications.name string Certification name
certifications.authority string Issuing authority
certifications.issueDate string Issue date

Submit example (one run scraping 2 profiles):

curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/profile" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "deliveryMode": "async",
    "recordLimit": 1000,
    "targets": [
      { "profileUrl": "https://www.linkedin.com/in/williamhgates/" },
      { "profileUrl": "https://www.linkedin.com/in/satyanadella/" }
    ]
  }'

Returns 201{ "code": 0, "data": { "id": 1287345, "status": "queued" } }. Record the id, poll GET /v1/scraper/runs/1287345 until succeeded, then fetch records.


Company

Extract a company page's public information by URL. Each URL is one target; submit multiple in a single run for batching.

Endpoint: POST /v1/scraper/linkedin/company

Target fields (each targets[] element):

Field Type Required Description
companyUrl string ✅ Required Company page URL (one per row; must contain /company/<slug>)

Output fields (each record):

Field Type Description
companyId string Internal LinkedIn company ID
name string Full company name
description string Company description
website string Official website URL
industry string Industry
companySize string Company size range
foundedYear number Founded year
headquarters object Headquarters
headquarters.city string HQ city
headquarters.country string HQ country
headquarters.address string HQ street address
followers number Follower count on LinkedIn
employeesOnLinkedIn number Number of employees registered on LinkedIn
specialties array Business specialty tags
locations array Office locations
locations.city string City
locations.country string Country
locations.address string Street address
companyUrl string Company URL

Submit example:

curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/company" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "deliveryMode": "async",
    "recordLimit": 1000,
    "targets": [
      { "companyUrl": "https://www.linkedin.com/company/microsoft/" }
    ]
  }'

Returns 201{ "code": 0, "data": { "id": 1287346, "status": "queued" } }. Poll that id until succeeded, then fetch records.


Jobs

Search job listings by keywords, location, experience level, and more. One search condition is one target.

Endpoint: POST /v1/scraper/linkedin/jobs

Target fields (each targets[] element):

Field Type Required Description
keywords string Search keywords (e.g. software engineer; passing keywords is recommended, otherwise a trending list is returned)
location string Location (e.g. United States / Berlin)
resultsLimit number Max jobs to return (1–1000, default 100, capped by the max_count billing limit)
experienceLevel string Experience level: INTERNSHIP / ENTRY_LEVEL / ASSOCIATE / MID_SENIOR / DIRECTOR / EXECUTIVE
jobType string Employment type: FULL_TIME / PART_TIME / CONTRACT / TEMPORARY / VOLUNTEER / INTERNSHIP / OTHER
workplaceType string Workplace type: ON_SITE / REMOTE / HYBRID
postedWithinDays number Posted within (days; only 1 / 7 / 30 valid)
companyNames array Filter by an array of company names (the spider resolves company IDs via typeahead first)
salaryMin number Minimum annual salary (USD)
country string Country ISO code (e.g. US / DE)

Output fields (each record):

Field Type Description
jobUrl string Job detail page URL
jobId string LinkedIn job ID
title string Job title
description string Job description (extracted from HTML)
applyUrl string Application URL (may be empty)
postAt string Published time (may be empty)
company object Company info
company.name string Company name
company.link string Company URL on LinkedIn
company.logo string Company logo URL (may be empty)
company.industries string Industry of the company
location string Location
jobLevel string Seniority level (e.g. Mid-Senior; may be empty)
jobType string Employment type (e.g. Full-time; may be empty)
jobFunction string Job function (e.g. Engineering; may be empty)
applicantsCount string Number of applicants as a numeric string (may be empty)
requirements object Requirements
requirements.skills string Skill requirements (may be an empty string)
requirements.education string Education requirements
requirements.experience string Experience requirements (may be missing)
salary object Salary range
salary.currency string Salary currency
salary.minAmount number Lower bound of the salary range
salary.maxAmount number Upper bound of the salary range
salary.payPeriod string Pay period (e.g. YEAR)

Submit example:

curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/jobs" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "deliveryMode": "async",
    "recordLimit": 1000,
    "targets": [
      {
        "keywords": "data engineer",
        "location": "United States",
        "resultsLimit": 100,
        "experienceLevel": "MID_SENIOR",
        "jobType": "FULL_TIME",
        "workplaceType": "REMOTE"
      }
    ]
  }'

Returns 201{ "code": 0, "data": { "id": 1287347, "status": "queued" } }. Poll that id until succeeded, then page through the job list.


Profile Posts

Extract posts published by a person. At least one of profileUrls / companyUrls must be non-empty.

Endpoint: POST /v1/scraper/linkedin/posts

Target fields (each targets[] element):

Field Type Required Description
profileUrls array either/or Profile URL list (containing linkedin.com/in/…); at least one of profileUrls / companyUrls non-empty
companyUrls array either/or Company URL list (containing linkedin.com/company/…)
resultsLimit number Max posts per URL (1–200, default 25, capped by the max_count billing limit)
includeComments boolean Fetch top-level comments per post (off by default, output has no comments field; roughly doubles cost when on)
country string Export country ISO code (e.g. us); omit for global mix

Output fields (each record):

Field Type Description
postId string Post URN (urn:li:activity:<id> format)
permalink string Post permalink
text string Body text
createdAt string Posted time (ISO 8601 UTC)
author object Author info (type always matches the entry side, person or company)
author.type string Author type (person / company)
author.name string Author display name
author.url string Author profile URL
metrics object Engagement metrics
metrics.reactionsCount number Total reaction count
metrics.commentsCount number Comment count
media array Post media (a reshared original post is classified as article, url points to that original post)
media.type string Media type (image / video / article / document)
media.url string Media URL
media.thumbnailUrl string Video thumbnail URL (present only when type=video)
media.title string Article/document title (present only when type=article/document)
comments array Top-level comments (present only when includeComments=true)
comments.commentId string Comment ID
comments.text string Comment content
comments.authorName string Comment author name
comments.createdAt string Comment time

Submit example:

curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/posts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "deliveryMode": "async",
    "recordLimit": 1000,
    "targets": [
      {
        "profileUrls": ["https://www.linkedin.com/in/williamhgates/"],
        "resultsLimit": 25,
        "includeComments": false
      }
    ]
  }'

Returns 201{ "code": 0, "data": { "id": 1287348, "status": "queued" } }. Poll that id until succeeded, then fetch post records.


Company Posts

Extract posts published by a company page, using the company page URL as the main entry. At least one of companyUrls / profileUrls must be non-empty.

Endpoint: POST /v1/scraper/linkedin/posts-company

Target fields (each targets[] element):

Field Type Required Description
companyUrls array either/or Company URL list (containing linkedin.com/company/…); at least one of companyUrls / profileUrls non-empty
profileUrls array either/or Profile URL list (containing linkedin.com/in/…)
resultsLimit number Max posts per URL (1–200, default 25, capped by the max_count billing limit)
includeComments boolean Fetch top-level comments per post (off by default, output has no comments field; roughly doubles cost when on)
country string Export country ISO code (e.g. us); omit for global mix

Output fields (each record, same as Profile Posts):

Field Type Description
postId string Post URN (urn:li:activity:<id> format)
permalink string Post permalink
text string Body text
createdAt string Posted time (ISO 8601 UTC)
author object Author info (type always matches the entry side, person or company)
author.type string Author type (person / company)
author.name string Author display name
author.url string Author profile URL
metrics object Engagement metrics
metrics.reactionsCount number Total reaction count
metrics.commentsCount number Comment count
media array Post media (a reshared original post is classified as article, url points to that original post)
media.type string Media type (image / video / article / document)
media.url string Media URL
media.thumbnailUrl string Video thumbnail URL (present only when type=video)
media.title string Article/document title (present only when type=article/document)
comments array Top-level comments (present only when includeComments=true)
comments.commentId string Comment ID
comments.text string Comment content
comments.authorName string Comment author name
comments.createdAt string Comment time

Submit example:

curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/posts-company" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "deliveryMode": "async",
    "recordLimit": 1000,
    "targets": [
      {
        "companyUrls": ["https://www.linkedin.com/company/microsoft/"],
        "resultsLimit": 25,
        "includeComments": false
      }
    ]
  }'

Returns 201{ "code": 0, "data": { "id": 1287349, "status": "queued" } }. Poll that id until succeeded, then fetch post records.


Fetching Data & Polling

After submitting, every endpoint follows the same run lifecycle to retrieve data:

  1. Poll GET /v1/scraper/runs/{id} (back off 1s→2s→5s) until succeeded / failed (terminal).
  2. Page through records via GET /v1/scraper/runs/{id}/records?page=1&pageSize=20; items[] matches the "Output fields" above.
  3. Or download the full result via GET /v1/scraper/runs/{id}/download?format=csv.

An end-to-end example (Python submit / poll / fetch) is in Quick Start; the envelope, state machine, billing, and error codes are in Auth & Error Handling.


FAQ

Q: Does the call return data directly?

No. Scraping is asynchronous: submit to get a run id, poll until succeeded, then fetch records by id.

Q: Can I scrape multiple profiles / companies in one run?

Yes. For Profile / Company, each URL is one target, and a single run can hold multiple targets; per-target success or failure is in the run object's tasks[] (see Auth & Error Handling).

Q: Which endpoint should I use for profile vs company posts?

Use /posts (main entry profileUrls) for personal profile posts; use /posts-company (main entry companyUrls) for company page posts. Both endpoints share the same output fields.

Q: Do I need to log into the target account?

No. Only public data is extracted; private accounts cannot be scraped.


Next Steps