# LinkedIn Jobs Monitor — New Hiring at Target Companies (`agency-shift/linkedin-jobs-monitor`) Actor

Track newly observed LinkedIn jobs by keyword, location and company filters. Export job links, titles, companies and source dates with persistent deduplication. Collects public job cards directly; no paid source Actor or LinkedIn cookies required.

- **URL**: https://apify.com/agency-shift/linkedin-jobs-monitor.md
- **Developed by:** [Mako](https://apify.com/agency-shift) (community)
- **Categories:** Jobs, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.98 / 1,000 delivered qualifying jobs

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Jobs Monitor

Track newly observed LinkedIn jobs by keywords, location and target company filters. Keep a reusable hiring watchlist with original job links, source dates and saved history, so repeat scans avoid delivering the same job again.

**This Actor collects public job-search cards directly. It does not call a paid source Actor and does not require LinkedIn cookies or a LinkedIn account.** It also accepts an existing compatible Apify dataset. Public access can be blocked or incomplete; failed access is reported rather than presented as zero jobs.

### Quick start

```json
{
  "sourceMode": "public",
  "keywords": "Revenue Operations",
  "location": "United States",
  "postedLimit": "week",
  "companyIds": [],
  "mode": "new",
  "monitorName": "revops-hiring",
  "maxScanJobs": 25,
  "maxPages": 1,
  "maxResults": 25,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

Run again with the same monitor name and search/filter settings to receive newly observed job IDs. Set `emitInitial: false` to save the first matching baseline without delivering job-result events. If you want recurring scans, add an Apify schedule yourself; the Actor does not create one automatically.

For a company watchlist, use numeric LinkedIn `companyIds`. You can obtain these from the `f_C` parameter of a LinkedIn Jobs search URL after selecting the company filter. Up to ten IDs are supported. These filters are passed to LinkedIn; the source can broaden search results, and unknown company IDs remain null in output.

Use `includePhrases` or `excludePhrases` to filter the collected title, company name and location using literal case-insensitive substrings. Matching evidence includes the actual words and offsets. This does not inspect a full job description or prove a company's purchasing plans.

### What is included

- Job ID and available direct LinkedIn job URL.
- Job title, company name/link when available, and location.
- The source's listed date at its original precision and any relative date label.
- Observation and collection times, kept separate from the listed date.
- Literal filter evidence, source page provenance and a stable event ID.

This version reads search cards. **Full descriptions, recruiter contact details, applicants, salary enrichment and applications are not collected.** It does not publish messages or apply for jobs. “New” means newly observed by this monitor, not proof of a newly created vacancy. Changes to existing jobs do not create new-job events; missing jobs never imply that a role is closed or filled.

`SUMMARY` reports source mode, page/request counts, coverage and saved output. `ERROR` records failures. `SOURCE_DATA` retains the bounded raw observations from a successful collection for inspection. Apify datasets provide JSON, CSV and Excel exports.

### Source and limits

The collector reads the public LinkedIn Jobs search page and, if requested, its public guest pagination used by LinkedIn's own website. It does not use an authenticated session. Defaults allow one page and 25 examined jobs; limits are at most four pages and 100 examined jobs per run. LinkedIn can return more cards on a page than the requested examination cap; unexamined cards are not saved as seen.

Results can be ranked, broadened, delayed, regional or incomplete. A successful bounded scan is not a complete job database. A repeat run with zero output does not prove no new jobs exist. A failed required page fails the collection before new history is saved.

Direct requests are the default. If they are blocked from your runtime, explicitly choose an Apify proxy in the input, for example the UNBLOCKER group. Proxy availability depends on your account, and its usage is billed separately. The Actor does not automatically switch to a paid proxy, purchase a third-party scraper, or change your plan. Each request has a timeout, and pages are bounded.

For existing data, use `sourceMode: "dataset"` and choose `sourceDatasetId`. Rows should include `jobId` or `id`, `jobUrl` or `url`, `title`, optional `company: { name, url, id }`, `location`, `listedAt` and `postedAgo`. Dataset mode reads the first `maxScanJobs` rows; it does not reapply live keyword/location/company/date filters. Literal include/exclude phrases still apply.

### Pricing

**$0.98 per 1,000 delivered job observations**, plus a $0.00005 startup event per allocated GB of memory (minimum one event). Apify compute, storage and any explicitly enabled proxy usage are separate.

For example, delivering 25 job observations has a result fee of **$0.0245**, plus startup and actual platform/proxy usage. In new mode, previously delivered or rejected jobs have no new job-result fee, but a repeat scan can still incur platform/proxy costs.

`maxResults` limits delivered records. It does not cap request or proxy charges. The Apify maximum Actor charge limits this Actor's events, not every underlying platform cost. `maxPages`, `maxScanJobs` and `requestTimeoutSecs` bound collection work.

### Saved progress

Qualified overflow is saved before output and drained on the next run before another search. Keep the same monitor name and settings. Keyword, location, company, window, source or phrase-filter changes create separate history; changing only the output cap does not.

A lock prevents concurrent writers. Delivery is at least once: a crash after output but before its saved checkpoint can repeat and charge the same `eventId`; deduplicate that field downstream. History never silently expires. At the configured history limit or 16 MB state limit, the Actor stops instead of forgetting jobs and replaying old results.

# Actor input Schema

## `sourceMode` (type: `string`):

Public LinkedIn job search uses our own collector, without a paid source Actor. Dataset mode reads compatible rows you already have.

## `keywords` (type: `string`):

Public search terms, for example Revenue Operations. LinkedIn can return semantic or broadened matches; use includePhrases for literal matching after collection.

## `location` (type: `string`):

Location text passed to LinkedIn, for example United States or Ireland. Source matching is not an independently verified geography guarantee.

## `companyIds` (type: `array`):

Optional numeric LinkedIn company IDs, up to 10. Copy values from f\_C in a LinkedIn Jobs search URL after choosing company filters. These are passed to LinkedIn; unknown output company IDs remain null.

## `postedLimit` (type: `string`):

Passed to live search. Dataset mode does not independently reapply keyword, location, company or date search filters.

## `sourceDatasetId` (type: `string`):

Dataset mode requires compatible job-card records. Read access only.

## `includePhrases` (type: `array`):

Optional literal substring match against the title, company name and location. Exact evidence is included. This happens after public collection.

## `excludePhrases` (type: `array`):

Optional literal substring exclusions applied to the same title/company/location text.

## `mode` (type: `string`):

New mode remembers delivered job IDs. Snapshot returns all qualifying observations each collection. Missing jobs never produce closed-job or filled-role claims.

## `monitorName` (type: `string`):

Reuse this name for repeat scans. Search/source/filter changes create separate history. A new name deliberately starts fresh.

## `emitInitial` (type: `boolean`):

Disable to establish an initial qualifying baseline without job-result fees. Platform and proxy work may still cost money.

## `maxScanJobs` (type: `integer`):

Bounded source sample, not complete coverage. Public pages can contain more cards than this cap; unexamined jobs are not saved as seen.

## `maxPages` (type: `integer`):

One initial public page plus optional public guest pagination. No job detail requests. A failed required page fails the collection without updating history.

## `maxResults` (type: `integer`):

Qualifying overflow is saved for the next run before another search. This cap does not control public request or proxy costs.

## `requestTimeoutSecs` (type: `integer`):

Each request is bounded and is never silently retried through a more expensive route.

## `proxyConfiguration` (type: `object`):

Direct access is the default. If LinkedIn blocks it, you may explicitly select an Apify proxy such as UNBLOCKER. Proxy charges are separate and are not limited by the Actor result-charge ceiling.

## `maxHistoryItems` (type: `integer`):

History does not silently expire. At the configured count or 16 MB state limit, processing stops instead of forgetting delivered jobs.

## Actor input object example

```json
{
  "sourceMode": "public",
  "keywords": "Revenue Operations",
  "location": "United States",
  "companyIds": [],
  "postedLimit": "week",
  "includePhrases": [],
  "excludePhrases": [],
  "mode": "new",
  "monitorName": "default",
  "emitInitial": true,
  "maxScanJobs": 25,
  "maxPages": 1,
  "maxResults": 25,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxHistoryItems": 20000
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `error` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("agency-shift/linkedin-jobs-monitor").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("agency-shift/linkedin-jobs-monitor").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 '{}' |
apify call agency-shift/linkedin-jobs-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,agency-shift/linkedin-jobs-monitor"
        }
    }
}
```

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/AbSjkniNq7Zj9BBdR/builds/KCfwQeFbbnl1U4gfy/openapi.json
