# Naukri.com Scraper - Jobs, Salaries & Companies (`abotapi/naukri-com-scraper`) Actor

Scrape Naukri.com jobs by keyword or URL. Extract job title, company, skills, experience, salary, location and posting date, with optional full descriptions, education requirements and company details. Supports incremental monitoring and resume runs.

- **URL**: https://apify.com/abotapi/naukri-com-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 job records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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

## Naukri Scraper

Scrape [Naukri.com](https://www.naukri.com), India's largest job board, by keyword
or by link. Every record carries the title, company, skills, experience, salary,
location and posting date straight from the search results; with details on, each
record also carries the full description, key skills, education, employment type,
workplace label, industry, company details and view/apply counts from the job's
own page.

### Why a browser session

The search results are rendered by a client-side app that reads a same-origin
JSON interface guarded by a short-lived token generated inside the page. A plain
HTTP client is refused (HTTP 406) even with a valid cookie jar, so the actor
drives one persistent browser session for the whole run: it loads the first page
of each search, harvests the payload the app itself fetched, then reads later
pages through the page's own connection. One session per run, no per-page churn.

### Modes

- **Search**: one or more keywords, optionally with one location. Each keyword's
  results are walked forward page by page until they end or a cap stops the run.
- **URL**: paste links instead.
  - search pages (`https://www.naukri.com/python-developer-jobs-in-bangalore`)
    keep every filter you applied on the site, because the page path carries
    them; they are walked like a search.
  - single job pages (`https://www.naukri.com/job-listings-...-<jobId>`) are
    read directly.

### Output fields

Each dataset item includes: `jobId`, `title`, `url`, `companyName`, `companyId`,
`companyLogo`, `skills`, `experience`, `minimumExperience`, `maximumExperience`,
`salary`, `location`, `descriptionSnippet`, `vacancy`, `postedAt`,
`postedDaysAgoLabel`, `currency`, `walkinJob`, `searchScope`. With **Fetch full
job details** on it also carries `description`, `locations`, `education`,
`employmentType`, `jobType`, `industry`, `functionalArea`, `jobRole`,
`workFromHomeType`, `viewCount`, `applyCount`, `companyDetails`, `companyRating`
and the salary breakdown in `salaryDetail`.

### Limits and cost

- `maxItems` (default 20) is the total record cap across all keywords or links;
  set 0 for unlimited.
- `maxPages` (default 0) is unlimited; `maxItems` is the one cap that stops a run.
- **Fetch full job details** (default on) reads one job page per record. It is
  charged once per record whose job page read actually succeeded. Turn it off
  for the cheap card-only surface.

### Scheduled runs, incremental mode

Turn on **Incremental changes for scheduled runs** and run the same search daily:
the first run returns everything as NEW, later runs return only NEW, UPDATED and
REAPPEARED records. Records that vanished are marked EXPIRED once a run has
scanned the whole search (a run that was capped, resumed, or served fewer
results than the site reported skips expiry detection rather than guess).
`resumeFromRunId` continues one specific interrupted run.

### Connection

The actor runs through the Apify proxy on the standard shared pool by default.
Residential proxies in India are supported if your runs are refused, at the
usual per-GB premium.

### Send results into your apps (MCP connectors)

Optionally push results straight into another app when the run finishes. Add a
connector in the input under `mcpConnectors`, set `notionParentPageUrl` when
the connector is Notion, and cap the export with `maxNotifyListings`. Leave the
list empty to only write the dataset.

### Input parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `mode` | select | `search` or `url`. |
| `keywords` | list | Job keywords for search mode. |
| `location` | string | Optional city applied to every keyword. |
| `urls` | list | Job or search page links for URL mode. |
| `fetchDetails` | boolean | Read each job's page for the full detail set (per-job surcharge). |
| `maxItems` | integer | Total record cap, 0 = unlimited. |
| `maxPages` | integer | Pages per search, 0 = unlimited. |
| `proxyConfiguration` | object | Proxy settings; standard shared pool by default. |
| `resumeFromRunId` | string | Continue a previous run or dataset. |
| `incrementalMode` | boolean | Remember state between scheduled runs, return only changes. |
| `stateKey` | string | Name or share an incremental monitoring campaign. |
| `emitUnchanged` | boolean | Also return UNCHANGED rows (billed). |
| `emitExpired` | boolean | Also return EXPIRED rows once a full scan allows it. |
| `mcpConnectors` | list | Connector IDs for the export side-channel. |
| `notionParentPageUrl` | string | Parent page for the Notion connector. |
| `maxNotifyListings` | integer | Cap on exported records per run. |

### Usage notes

- Keyword searches match the site's own behaviour closely: nonsense keywords
  return few or no results, and the run then finishes with an honest "matched
  nothing" outcome.
- Job boards churn: postings move, expire and re-appear between runs. In
  incremental mode a re-appearing posting is REAPPEARED, not NEW, and its
  `firstSeenAt` stays from the first sighting.
- All URLs in the dataset point back to the live job page.

### Limitations

- Naukrigulf (the Gulf sister site) is not covered by this actor; naukri.com
  India search results do include some Gulf postings where the site serves them.
- The site serves 20 results per page; the actor respects that page size.
- Ages shown on cards ("14 Days Ago") are volatile display labels; the exact
  posting timestamp in `postedAt` is the reliable field.

# Actor input Schema

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

Search mode walks the job results for your keywords. URL mode reads the pasted links instead: search pages are walked like a search, single job pages are read directly.

## `keywords` (type: `array`):

Job search keywords, exactly as you would type them into the site's search box.

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

Optional city name applied to every keyword above, e.g. bangalore, mumbai, delhi ncr. Leave empty to search all India.

## `urls` (type: `array`):

Links to read. In URL mode this list is used; in Search mode it is ignored.

## `fetchDetails` (type: `boolean`):

Read each job's own page for the full description, key skills, education, employment type, workplace label, industry, company details and view/apply counts. Off keeps the lighter search-card fields. On adds the per-job detail surcharge, charged once per record whose job page read succeeded.

## `maxItems` (type: `integer`):

Maximum job records returned in total, across all keywords or links. 0 means unlimited (the run only stops when the results end).

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

Maximum result pages walked per keyword or search link. 0 (default) means no page limit, so Max items is the only cap that stops a run early.

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

The job board is read through a browser session. The standard shared pool serves it; pick Apify residential (India) only if your runs are refused, it is billed per GB.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large pull without returning items already collected there.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns every matching record as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED records. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately for each search, filter and URL setup; use State key to name or deliberately share a monitoring campaign. The days-ago age label shown on each card is excluded from change detection: the site re-renders it as time passes even when the posting date is unchanged, so a display flip alone never marks a job UPDATED.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the search and filter settings.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return records that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return records that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search; the source sometimes serves fewer results than it reports, and a run that could not see every matching job skips EXPIRED detection rather than guessing.

## `mcpConnectors` (type: `array`):

Connector IDs to export pushed records to when the run finishes.

## `notionParentPageUrl` (type: `string`):

When a Notion connector is used, the parent page the records are written under.

## `maxNotifyListings` (type: `integer`):

Cap on records sent through the connectors above per run.

## Actor input object example

```json
{
  "mode": "search",
  "keywords": [
    "python developer"
  ],
  "urls": [
    "https://www.naukri.com/python-developer-jobs"
  ],
  "fetchDetails": true,
  "maxItems": 20,
  "maxPages": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (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 = {
    "mode": "search",
    "keywords": [
        "python developer"
    ],
    "urls": [
        "https://www.naukri.com/python-developer-jobs"
    ],
    "fetchDetails": true,
    "maxItems": 20,
    "maxPages": 0,
    "proxyConfiguration": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "maxNotifyListings": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/naukri-com-scraper").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 = {
    "mode": "search",
    "keywords": ["python developer"],
    "urls": ["https://www.naukri.com/python-developer-jobs"],
    "fetchDetails": True,
    "maxItems": 20,
    "maxPages": 0,
    "proxyConfiguration": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "maxNotifyListings": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/naukri-com-scraper").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 '{
  "mode": "search",
  "keywords": [
    "python developer"
  ],
  "urls": [
    "https://www.naukri.com/python-developer-jobs"
  ],
  "fetchDetails": true,
  "maxItems": 20,
  "maxPages": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}' |
apify call abotapi/naukri-com-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/naukri-com-scraper"
        }
    }
}
```

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/bP1EqZknrmww4fJh0/builds/U51AvGKBXvZaAFaYe/openapi.json
