LinkedIn Company Scraper & Change Monitor (No Login) avatar

LinkedIn Company Scraper & Change Monitor (No Login)

Pricing

from $1.20 / 1,000 companies

Go to Apify Store
LinkedIn Company Scraper & Change Monitor (No Login)

LinkedIn Company Scraper & Change Monitor (No Login)

Scrape public LinkedIn company pages: one row per company with name, About, industry, employee band, website, followers and founded year when shown. Use it to watch accounts. Only changes returns only changed companies, with old and new values. No employees or posts. Not affiliated with LinkedIn.

Pricing

from $1.20 / 1,000 companies

Rating

0.0

(0)

Developer

Kizuki

Kizuki

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 hours ago

Last modified

Security

Limited permissions

Share

LinkedIn Company Scraper & Change Monitor reads public LinkedIn company overviews as any visitor sees them and returns one clean row per company — name, About summary, industry, organisation type, employee band, headquarters, founded year, website, follower count and specialties — as JSON or CSV. With onlyChanges it becomes a monitor: a scheduled run returns only the companies whose fields changed, with the old and the new value of each field — follower count, employee band, summary, industry, headquarters, founded year, website, type and specialties. Under onlyChanges, a company with nothing new produces no row and no charge.

It needs no login, no account and no cookie, runs no browser and executes no JavaScript on the page. Pages it could not read come back as a row with a fixed reason and are not charged, so a wall or a timeout never looks like "no change".

This Actor is an independent tool. It is not affiliated with, endorsed by or sponsored by LinkedIn or Microsoft. Try it with an empty input: it reads the sample company apify and returns its overview.

Use cases

  • Competitor watch. Follow a list of companies and get a row only when followers, headcount band, description or industry move.
  • Account research. One row per company with industry, size, headquarters, website and specialties, ready for a CRM or a sheet.
  • Market mapping. Build a table of companies in one industry and compare employee bands and specialties.
  • Sales triggers. Use the follower jump or the employee-band change as the trigger for an alert, not a full re-read of every company.
  • Agent research. Let an assistant pull a company's public profile, and only what changed since its last run.

What data can you get?

FieldDescription
id, type, sourceRow ID (a hash of the slug), company, and the source label
statusok for successfully read companies, or failed for uncharged status rows
slug, urlThe company slug and the page that was read (https://www.linkedin.com/company/<slug>/)
nameCompany name as on the page
descriptionThe About us summary, up to 5,000 characters, as the company wrote it
industryThe industry LinkedIn lists
companyTypeOrganization type as shown (Public Company, Privately Held, …) or null
companySize, employeesMin, employeesMaxThe employee band as shown (10,001+ employees) and its numeric bounds (max is null for an open band)
headquartersHeadquarters as shown (Mountain View, CA)
foundedYearThe year the page says the company was founded, or null (many pages do not show it)
websiteThe company's own website, unwrapped from LinkedIn's redirect link
followersFollowers on LinkedIn at the time of the run
specialtiesThe specialties the page lists (up to 30)
capturedAtWhen the run read the page
changesWith onlyChanges: {baseline, previousCapturedAt, changedFields, diffs: [{field, from, to}]}, otherwise null
errorCode, errorMessageFor a status row: authwall, blocked, not_found, timeout or unexpected, with a fixed sentence; null for a company row

Every row has every field; a value the page does not show is null. Employee lists and personal profiles are not part of this Actor.

A company whose page LinkedIn has moved is read at its new address (mistral-ai → mistralai) and its row keeps the slug you asked for. When the new address belongs to a different company, the row is not_found with an explanatory message: that slug no longer names a company, and reading the other company's page would put its data under your slug.

How to use LinkedIn Company Scraper

  1. Put company URLs or slugs into Companies (companies: apify, https://www.linkedin.com/company/google/). Up to 100.
  2. For a one-off overview, leave Only changes since the previous run (onlyChanges) off: every named company is returned in full.
  3. For monitoring, turn it on, set maxItems to bound how many companies one run reads, and schedule the Actor (hourly, daily or weekly). Each run then returns only what changed.
  4. Send the rows to your sheet, warehouse, alert or model. A changes.diffs entry carries field, from and to.

Input example

{
"companies": ["apify", "https://www.linkedin.com/company/google/"],
"onlyChanges": true,
"maxItems": 10
}

Input

FieldDefaultWhat it does
companies["apify"]Company slugs or page URLs to read (up to 100). An empty input reads the sample company
onlyChangesfalseReturn only companies whose tracked fields changed since the previous run, with the old and new value. The first run for a company returns it in full
maxItems10Maximum companies one run reads (1 to 100). A row for a company the Actor could not read counts towards it, so the run never reads more than this many companies. A company it skipped as unchanged does not count, so with onlyChanges on, a run may read the first maxItems companies and return only the changed ones. The companies after the limit are listed in OUTPUT as unchecked and cost nothing
proxyConfigurationApify residential proxyProxy settings (country, groups, custom proxy URLs)

Output

One row per company. With onlyChanges the row also says what moved: changedFields lists the fields and diffs carries field, from and to.

Output example

Values below are illustrative.

{
"id": "1f0c2de6a4b39c88",
"type": "company",
"source": "LinkedIn public company page",
"status": "ok",
"slug": "apify",
"url": "https://www.linkedin.com/company/apify/",
"name": "Apify",
"description": "Thousands of Actors to automate your business, get real-time web data, and equip your AI agents.",
"industry": "Technology, Information and Internet",
"companyType": "Privately Held",
"companySize": "201-500 employees",
"employeesMin": 201,
"employeesMax": 500,
"headquarters": "Prague",
"foundedYear": 2016,
"website": "https://apify.com/",
"followers": 46813,
"specialties": ["Web scraping", "Browser automation", "AI agents"],
"capturedAt": "2026-11-06T04:40:00.000Z",
"changes": {
"baseline": false,
"previousCapturedAt": "2026-11-05T04:40:00.000Z",
"changedFields": ["followers", "companySize"],
"diffs": [
{ "field": "followers", "from": 46510, "to": 46813 },
{ "field": "companySize", "from": "51-200 employees", "to": "201-500 employees" }
]
},
"errorCode": null,
"errorMessage": null
}

A company the Actor could not read is a row with status: "failed", its errorCode and a fixed errorMessage — never a charged row and never a missing one.

Only changes, run after run

onlyChanges keeps one record per company (its tracked field values and when the record was last written) in the named key-value store state-linkedin-company-<actor id> of your Apify account. The order matters: a record is written only after the company row was written to the dataset, so a company left out by maxItems or by the spending limit is read and returned next run, and a company that was walled or blocked keeps its old record, so the next successful run compares against the last successful one.

  • First run for a company: changes.baseline is true, diffs is empty, the row carries the full overview.
  • A field changed: the row is returned, changedFields and diffs name the fields with the old and new value.
  • Nothing changed: no row, no charge. The run says so in its status message (no_new_items) and OUTPUT counts the unchanged companies.
  • A snapshot cannot be read: the company is returned without a comparison this run, and no record is written, so a failed read never overwrites a good record.
  • Do not run the same input concurrently: two runs can both see the old record and both return the same change.

How much does it cost?

LinkedIn Company Scraper uses pay-per-event pricing: you pay only for the company rows returned, not for the time it runs. At the Free tier 1,000 company rows cost $2.00; at Gold, $1.20.

Apify plan (discount tier)Price per 1,000 companiesPrice per company
Free$2.00$0.002
Starter (Bronze)$1.80$0.0018
Scale (Silver)$1.50$0.0015
Business (Gold)$1.20$0.0012

Apify's Free plan includes USD 5 of monthly usage, which covers about 2,500 companies at the Free tier price, run start fees aside.

  • Run start fee: the platform default per run (see the Pricing tab).
  • 1 company row = 1 company event. A status row (Authwall, refusal, 404, timeout, unreadable page) is written for visibility and is not charged.
  • With onlyChanges, an unchanged company is not written and not charged, so monitoring unchanged profiles incurs zero row cost.

Use with AI agents (MCP)

LinkedIn Company Scraper works as a tool for AI agents such as Claude, Cursor and n8n agents through the Apify MCP server. Load only this Actor with this server URL:

https://mcp.apify.com?tools=kizukidata/linkedin-company-monitor
  • Claude Code: run claude mcp add apify "https://mcp.apify.com?tools=kizukidata/linkedin-company-monitor" -t http.
  • Claude (web or desktop app): open Customize → Connectors, choose Add custom connector, name it Apify and paste the server URL above.
  • Cursor: add the server to ~/.cursor/mcp.json (or .cursor/mcp.json in a project):
{
"mcpServers": {
"apify": { "url": "https://mcp.apify.com?tools=kizukidata/linkedin-company-monitor" }
}
}
  • n8n: add the Apify node (on self-hosted n8n, install the community package @apify/n8n-nodes-apify) and choose Run an Actor and get dataset; for an n8n AI Agent, add Apify Tool as a tool.

The server signs you in to Apify with OAuth. A client that cannot use OAuth can send your Apify API token in an Authorization: Bearer <APIFY_TOKEN> header instead.

What to send from an agent

Pass a small companies array (the default is the sample company) and keep maxItems small so the call returns inside the agent's timeout. Each row is a self-contained company overview, and with onlyChanges: true it also says what changed since the last run.

Integrations and API

Run the Actor from your own code or from an automation tool. Replace <APIFY_TOKEN> with your API token.

Zapier, Make and n8n

Use the Apify integration, choose Run Actor, and pass companies with onlyChanges: true. Add Get dataset items. Run the workflow on a schedule: a run with no changes returns no items, so the next step simply does not fire. Map slug, followers and changes.diffs to Slack, Airtable, Google Sheets or your CRM.

LangChain

Use description as page_content and name, slug, industry, companySize, headquarters, followers and url as metadata. ApifyDatasetLoader from the Apify LangChain integration works with the run's dataset ID; load only the changed companies by running with onlyChanges: true.

cURL

curl -X POST "https://api.apify.com/v2/acts/kizukidata~linkedin-company-monitor/runs" \
-H "Authorization: Bearer <APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"companies":["apify","google"],"onlyChanges":true,"maxItems":10}'

Poll GET https://api.apify.com/v2/actor-runs/<RUN_ID> for the status, read defaultDatasetId, then fetch GET https://api.apify.com/v2/datasets/<DATASET_ID>/items?format=json.

Python

from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("kizukidata/linkedin-company-monitor").call(run_input={
"companies": ["apify", "google"],
"onlyChanges": True,
"maxItems": 10,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
print(row["slug"], row["followers"], [d["field"] for d in (row["changes"] or {}).get("diffs", [])])

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('kizukidata/linkedin-company-monitor').call({
companies: ['apify', 'google'],
onlyChanges: true,
maxItems: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((row) => `${row.name}: ${row.followers} followers`));

Limitations

  • Company pages only. Employee lists, personal profiles, posts, comments and jobs are not read, and nothing is written to LinkedIn.
  • Paced reads. Requests are spaced and retried automatically; if several companies in a row are refused, the run stops and lists the companies it did not reach in OUTPUT uncheckedInputs.
  • foundedYear is null on many pages; the Actor does not guess.
  • The summary is the company's own text, up to 5,000 characters; it is returned as written, not summarised.
  • The employee band is LinkedIn's own band, not a headcount; employeesMin/employeesMax are the band bounds.
  • A guest page can answer with the sign-in wall (Authwall) at any time. The Actor retries twice and then reports it; it never logs in. A wall row is not charged, so if it keeps coming back, run again later.
  • Two runs of the same input at the same time can both report the same change.
  • Changes on the page. The reader extracts structured fields from the public page. If LinkedIn changes them, rows come back as unexpected (not charged) and the Actor needs an update; report it in the Issues tab.
  • Each run writes an OUTPUT record with the counts, the inputs it skipped or did not reach, and a linkedinCompany summary (companies requested, read, failed, rows returned, changed, baseline, unchanged).

FAQ

Why is onlyChanges off by default?

Without it the Actor is a plain overview reader: every company you name comes back in full. Turn it on for scheduled monitoring, where the point is to hear about changes only.

Why did a company come back with errorCode: "authwall"?

LinkedIn answered with the sign-in wall instead of the company page. This Actor does not log in, so it reports the wall (not charged) and the next run tries again.

Why did a company come back with errorCode: "not_found" although the page exists?

LinkedIn moves a renamed page and answers the old slug with a redirect. When the slug you named now redirects to a different company, the Actor does not read that page (its rows would be another company's data), so the row says the address no longer names a company page. Use the company's current LinkedIn URL. A redirect to the renamed page of the same company is followed and read normally.

Why is foundedYear null?

The page does not show a Founded row for every company. The Actor returns what the page shows and never guesses.

Does followers change every run?

It can. That is exactly what onlyChanges reports; the follower count is one of the tracked fields, next to the employee band, the summary, industry, headquarters, founded year, website, type and specialties.

The Actor reads company pages that are public to any visitor, without logging in. LinkedIn's User Agreement prohibits automated means to scrape or copy data from the service, and whether your use is permitted is your decision. If you publish the rows, keep the url link and name LinkedIn as the source. This is not legal advice.

Other Actors from Kizuki that work well with this one:

Your feedback

Bugs, a field that stopped coming back, and feature requests go to the Actor's Issues tab in Apify Console. A company owner who wants a page left out can open an Issue with the company URL: the Actor keeps an exclusion list, and a request from a third party is not enough.