# Apna Jobs Scraper (`automation-lab/apna-india-job-listings-scraper`) Actor

Search public Apna India vacancies by role and location and export titles, employers, salaries, experience, qualifications, posting dates, and canonical URLs.

- **URL**: https://apify.com/automation-lab/apna-india-job-listings-scraper.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.48 / 1,000 item extracteds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Apna Jobs Scraper

Search public **Apna jobs** by role and Indian location, then export normalized vacancy records for recruiting research, salary analysis, and labor-market data pipelines.

The Actor reads public Apna search pages and enriches every accepted result from its public job page. Each row includes a stable job ID, title, employer, location, salary when shown, experience, qualifications, posting dates, and canonical URL.

### What does Apna Jobs Scraper do?

Apna Jobs Scraper turns public vacancy pages into analysis-ready JSON, CSV, Excel, XML, or RSS output through Apify datasets.

It can:

- search by job keyword and Indian city or region;
- collect a specific public `apna.co/jobs/...` page;
- paginate through up to 20 search-result pages;
- enrich cards with public detail-page metadata;
- keep only records matching the supplied keyword and location;
- stop at an exact maximum number of useful jobs;
- retry temporary blocks with a fresh proxy identity;
- produce stable source IDs and canonical links for deduplication.

It does not log in, apply for jobs, access candidate profiles, or invent missing fields.

### Who is it for?

#### Recruiters and sourcing teams

Build a structured shortlist of current public vacancies by role and location, compare employers, and identify hiring demand.

#### Labor-market researchers

Analyze advertised salary ranges, experience levels, qualifications, departments, and publication dates across Indian cities.

#### Job aggregators and HR technology teams

Feed normalized public records into a warehouse, search index, spreadsheet, or internal vacancy product.

#### Data and automation teams

Schedule repeat runs in Apify and compare stable `jobId` values in a downstream system to find additions and removals.

### Why use this Actor?

- **Detail enrichment:** output is not limited to card text; public JobPosting metadata supplies dates, salary units, descriptions, experience, and canonical URLs.
- **Stable identity:** `jobId` comes from Apna's source listing identifier.
- **Fail-closed extraction:** blocked pages and unrecognized HTML are errors, not misleading empty success.
- **Bounded collection:** `maxItems`, `maxPages`, and retries have explicit limits.
- **Lightweight HTTP:** no browser assets, images, fonts, or videos are downloaded.
- **India-aware routing:** common names such as Delhi NCR and Bengaluru map to their public Apna location routes.

### What Apna job data can I extract?

| Field | Meaning |
| --- | --- |
| `source` | Always `apna.co` |
| `jobId` | Stable source job identifier |
| `title` | Public job title |
| `employer` | Hiring organization shown by Apna |
| `location` | Public street/locality/city text |
| `salaryMin`, `salaryMax` | Numeric advertised range when present |
| `salaryCurrency`, `salaryPeriod` | Currency and source pay unit |
| `experience`, `experienceMonths` | Display requirement and structured duration |
| `qualifications` | Public education requirement |
| `englishLevel` | Public English requirement when shown |
| `employmentType` | Full-time, part-time, or another published type |
| `workMode` | Office, work-from-home, remote, or hybrid tag when shown |
| `shift` | Published shift |
| `department`, `category` | Source industry and occupational category |
| `description` | Public plain-text description when enabled |
| `datePosted`, `validThrough` | Source posting and validity metadata |
| `canonicalUrl` | Canonical public job page |
| `sourceSearchUrl`, `sourcePosition` | Search provenance and position |
| `scrapedAt` | UTC collection timestamp |

Optional values are omitted when Apna does not publish them.

### Getting started

1. Open the Actor input page.
2. Enter a `keyword`, a `location`, or one or more public Apna search URLs.
3. Keep `maxItems` small for the first run.
4. Leave the default Apify proxy enabled.
5. Click **Start**.
6. Open the default dataset when the run finishes.
7. Export the table or connect it to your workflow.

A useful first input is:

```json
{
  "keyword": "delivery",
  "location": "Delhi NCR",
  "maxItems": 10,
  "maxPages": 3,
  "includeDescription": false,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

### Input parameters

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `startUrls` | array | empty | Public `https://apna.co/jobs/...` search pages |
| `keyword` | string | empty | Every word must match public card text |
| `location` | string | empty | City or region used for discovery and filtering |
| `includeDescription` | boolean | `true` | Include the public detail-page description |
| `maxItems` | integer | `25` | Useful records to save, from 1 to 1,000 |
| `maxPages` | integer | `5` | Search pages per URL, from 1 to 20 |
| `maxRequestRetries` | integer | `3` | Fresh-session retries, from 0 to 5 |
| `proxyConfiguration` | object | Apify proxy | Network route used for Apna requests |

Provide at least one of `startUrls`, `keyword`, or `location`.

Supplied URLs must use HTTPS, the `apna.co` host, and the `/jobs` path. Keyword and location filters are still applied when you provide an explicit URL.

### Search by role and location

When a location is supplied, the Actor opens that public location feed and applies the keyword to titles, employers, locations, and visible work tags.

For example:

```json
{
  "keyword": "sales",
  "location": "Mumbai",
  "maxItems": 50,
  "maxPages": 5
}
```

This approach preserves source-visible results and avoids pretending that an unsupported free-text role is an official Apna category.

### Collect a specific Apna search page

Use `startUrls` when you already know the exact category or location page:

```json
{
  "startUrls": [
    { "url": "https://apna.co/jobs/freshers-jobs-in-delhi_ncr" }
  ],
  "maxItems": 25,
  "includeDescription": false
}
```

The Actor validates every URL before requesting it.

### Output example

A current output row has this shape:

```json
{
  "source": "apna.co",
  "jobId": "357713384",
  "title": "Delivery Associate",
  "employer": "Blinkit Private Limited",
  "location": "Janakpuri, New Delhi, Delhi, India",
  "salaryMin": 50000,
  "salaryMax": 125000,
  "salaryCurrency": "INR",
  "salaryPeriod": "MONTH",
  "experience": "Any experience",
  "qualifications": "10th or Below 10th",
  "englishLevel": "No English Required",
  "employmentType": "PART TIME",
  "shift": "Day Shift",
  "department": "Delivery / Driver / Logistics",
  "category": "Delivery",
  "datePosted": "2026-09-05T10:44:36.798Z",
  "validThrough": "2026-09-20",
  "canonicalUrl": "https://apna.co/job/new-delhi/delivery-associate-357713384",
  "sourceSearchUrl": "https://apna.co/jobs/jobs-in-delhi_ncr",
  "sourcePosition": 5,
  "scrapedAt": "2026-09-14T20:42:18.389Z"
}
```

Titles, employers, dates, and availability can change. Treat this as a schema example, not a guaranteed live vacancy.

### How much does it cost to extract Apna jobs?

The Actor uses pay-per-event pricing:

- a **$0.0005 start event** for each run;
- the Free tier pays **$0.00092 per saved job**;
- the Bronze tier pays **$0.0008 per saved job**;
- the Silver tier pays **$0.000624 per saved job**;
- Gold, Platinum, and Diamond pay **$0.00048 per saved job**.

At Bronze pricing, 10 saved jobs cost about **$0.0085**, 100 cost about **$0.0805**, and 1,000 cost about **$0.8005**. Apify platform usage and proxy transfer may also apply according to your plan. Failed, duplicate, filtered, and skipped records do not create item events.

### Scheduling and monitoring

Use an Apify Schedule for daily or weekly collection. Send each run's dataset to Google Sheets, a webhook, Make, Zapier, or your database.

This Actor does not persist a change history. For monitoring, use `jobId` as the source key in your destination and compare successive datasets. A missing record can mean the listing expired, moved beyond the requested page range, or no longer matched the filters.

### Export and integration workflows

Common workflows include:

1. **Salary research:** group `salaryMin` and `salaryMax` by location, category, and employer.
2. **Qualification demand:** count `qualifications`, `experienceMonths`, and `englishLevel` values.
3. **Hiring signals:** aggregate newly observed `jobId` values by employer and week.
4. **Vacancy feed:** index canonical URLs and titles in an internal search product.
5. **Spreadsheet review:** export the overview table to CSV or Excel.

### Run through the Apify API with cURL

Replace `YOUR_TOKEN` with an Apify API token:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~apna-india-job-listings-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keyword":"delivery","location":"Delhi NCR","maxItems":10}'
```

Use the returned run's `defaultDatasetId` to download items.

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/apna-india-job-listings-scraper').call({
    keyword: 'sales',
    location: 'Mumbai',
    maxItems: 25,
    includeDescription: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Run with Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("automation-lab/apna-india-job-listings-scraper").call(
    run_input={
        "keyword": "freshers",
        "location": "Pune",
        "maxItems": 25,
        "includeDescription": False,
    }
)
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use with MCP and AI agents

Add this Actor to Claude Code through Apify MCP:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/apna-india-job-listings-scraper"
```

**Claude Desktop, Cursor, and VS Code setup:** add this HTTP server configuration in the client's MCP settings:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/apna-india-job-listings-scraper"
    }
  }
}
```

Example prompts:

- “Find up to 20 delivery jobs in Delhi NCR and return employer, salary, and qualifications.”
- “Extract current fresher jobs from this public Apna search URL and group them by education requirement.”
- “Build a Mumbai sales-vacancy dataset with posting dates and canonical links.”

### Reliability, retries, and proxies

Apna may reject direct cloud traffic. The input therefore enables Apify proxy by default. Development tests found the complete public HTML route through datacenter proxy; no automatic residential or browser fallback is used.

A temporary 403, 429, 492, 5xx, timeout, or reset can trigger a bounded retry with a fresh proxy session. Deterministic bad URLs and malformed pages are not retried blindly.

For stable production use:

- keep the default proxy enabled;
- use moderate page limits;
- avoid many overlapping schedules;
- inspect warnings for skipped detail pages;
- retry a failed run later rather than raising retries to the maximum immediately.

### Limits and expected behavior

- Public search pages typically expose about 25 cards per page.
- `maxPages` limits discovery, so a rare keyword may not appear in a shallow run.
- Output reflects what was publicly visible at collection time.
- Salary, qualifications, and dates are omitted when the source omits them.
- One search card normally requires one detail-page request.
- Listings can expire between the search and detail requests.
- Apna can change routes, markup, JSON-LD, or anti-bot behavior.
- The Actor supports public jobs only; it does not submit applications.

### Troubleshooting

#### The run says no jobs matched

Check the spelling, use a broader keyword, increase `maxPages`, or try the public Apna URL in `startUrls`. A successful HTTP response without recognizable cards is treated as an error.

#### A URL is rejected before the run starts

Use a public HTTPS URL on `apna.co` whose path begins with `/jobs`. Individual `/job/...` detail URLs are not search inputs.

#### Requests return HTTP 492 or another block

Restore the default Apify proxy configuration and run again. Do not disable proxy routing for production unless direct access is known to work from your environment.

#### Some optional fields are missing

The source did not publish them for that job, or the relevant detail element was absent. The Actor omits missing values rather than guessing.

#### Fewer records were saved than requested

Filters may remove cards, detail pages may expire, or the page limit may be exhausted. Review logs and increase `maxPages` within the documented limit if appropriate.

### Data handling, AI, and storage

The Actor does not use AI or send input or scraped data to an AI provider. It makes public Apna HTTPS requests through the user-selected Apify proxy configuration and writes validated jobs only to the run's default dataset. It keeps no external cache or separate copy. Datasets, key-value store records, and logs follow the retention and deletion controls in your Apify account. Logs contain operational status, public source URLs, and job IDs; they do not intentionally include secrets or private account data.

### Responsible and legal use

Only collect public data for lawful purposes. Review Apna's current terms, robots guidance, and applicable employment, privacy, database, and data-protection rules before production use.

Job descriptions can contain personal or contact information supplied by an employer. Minimize collection, control access, set retention limits, and avoid using public vacancy data for unsolicited messaging, discrimination, candidate profiling, or decisions with legal effects.

You are responsible for your inputs, collection frequency, downstream use, and compliance. This Actor is not affiliated with or endorsed by Apna.

### Related Automation Lab Actors

- [Instahyre Jobs Scraper](https://apify.com/automation-lab/instahyre-jobs-scraper) for public India technology vacancies.
- [Internshala Scraper](https://apify.com/automation-lab/internshala-scraper) for public internships and entry-level roles.
- [India Job Inventory Feed](https://apify.com/automation-lab/india-job-inventory-feed) for a broader multi-source India workflow.

Choose this Actor when Apna is the required source and source-specific salary, requirement, and canonical-link fields matter.

### FAQ

#### Does it need an Apna account?

No. It uses public search and job pages without login.

#### Does it scrape candidate profiles?

No. It only processes public job vacancies.

#### Can I supply more than one search URL?

Yes. `maxItems` applies across all supplied URLs. Duplicate source job IDs are saved once.

#### Can I search the whole of India?

Yes. Supply only a keyword. Adding a location makes the scope more specific and usually more useful.

#### Does it guarantee every vacancy on Apna?

No. It collects the requested public pages within your item and page limits.

#### Can I disable descriptions?

Yes. Set `includeDescription` to `false` for smaller records and lower transfer.

#### What is the deduplication key?

Use `jobId`. It is the stable source listing identifier present in the canonical URL and JobPosting metadata.

#### Are empty runs charged per item?

No item event is charged unless a validated job record is saved. The one-time start event still applies.

# Actor input Schema

## `startUrls` (type: `array`):

Optional public https://apna.co/jobs/... pages. Filters below are also applied to supplied URLs.

## `keyword` (type: `string`):

Keep listings containing every word in the job title, employer, location, or visible tags.

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

Indian city or region, for example Delhi NCR, Mumbai, Pune, Bengaluru, or Hyderabad.

## `includeDescription` (type: `boolean`):

Include the public plain-text description from each job detail page.

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

Maximum matching job records saved across all search pages.

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

Maximum 25-job pages fetched per search URL.

## `maxRequestRetries` (type: `integer`):

Fresh-session retries for blocked or temporary upstream responses.

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

Apify datacenter proxy is enabled by default because Apna may reject direct cloud traffic.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://apna.co/jobs/jobs-in-delhi_ncr"
    }
  ],
  "keyword": "delivery",
  "location": "Delhi NCR",
  "includeDescription": true,
  "maxItems": 20,
  "maxPages": 5,
  "maxRequestRetries": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Normalized vacancies in the overview dataset view.

# 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 = {
    "startUrls": [
        {
            "url": "https://apna.co/jobs/jobs-in-delhi_ncr"
        }
    ],
    "keyword": "delivery",
    "location": "Delhi NCR",
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/apna-india-job-listings-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 = {
    "startUrls": [{ "url": "https://apna.co/jobs/jobs-in-delhi_ncr" }],
    "keyword": "delivery",
    "location": "Delhi NCR",
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/apna-india-job-listings-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 '{
  "startUrls": [
    {
      "url": "https://apna.co/jobs/jobs-in-delhi_ncr"
    }
  ],
  "keyword": "delivery",
  "location": "Delhi NCR",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call automation-lab/apna-india-job-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/apna-india-job-listings-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/NlgAbsaxpA7JLkB2a/builds/ehbTW1dGvxxcpHb7p/openapi.json
