# Indian Job Boards Scraper — Hirist, Internshala, Instahyre (`teodor_banea/indian-job-boards-scraper`) Actor

Scrape Hirist, Internshala and Instahyre jobs and internships into one aligned row: full descriptions, salary and stipend as numbers, experience range, absolute posting dates, applicants, perks and company data. Keyword, city, remote, experience and date filters.

- **URL**: https://apify.com/teodor_banea/indian-job-boards-scraper.md
- **Developed by:** [Banea Teodor](https://apify.com/teodor_banea) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.35 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Indian Job Boards Scraper — Hirist, Internshala, Instahyre

### What does Indian Job Boards Scraper do?

Indian Job Boards Scraper searches three Indian job boards at once — [Hirist](https://www.hirist.tech) (tech jobs, ~30,000 live), [Internshala](https://internshala.com) (internships and fresher jobs, ~7,000 internships + ~6,500 jobs) and [Instahyre](https://www.instahyre.com) (tech jobs with company profiles, ~12,600 live) — and returns **one aligned row per job**: title, company, locations, experience range, salary or stipend as numbers, skills, the **full job description** (clean text and sanitised HTML), an **absolute posting date**, applicants, openings, apply-by date, perks and company data (AmbitionBox rating, size, founding year, industry). Search by keyword, city or remote, experience and posting date — or paste job page URLs. No login, no browser.

### Why use this Actor?

- **One schema for three boards.** Every row has the same 57 fields whichever board it comes from; values a board does not publish are `null` or `[]`, never missing keys. Load the output straight into one table.
- **Numbers, not strings.** Salaries and stipends become `salaryMin` / `salaryMax` with `salaryCurrency` and `salaryPeriod` (Hirist "12-18 LPA" → 1,200,000-1,800,000 INR per year; Internshala "₹ 10,000 /month" → 10,000 per month), experience becomes years, applicants and openings are integers.
- **Absolute dates.** Internshala shows "3 days ago"; the Actor reads the exact posting time. Hirist times are exact to the second.
- **Full descriptions.** The whole job description from the job page, plus Internshala's apply-by date, openings, start date, duration, perks, CTC breakup and employer track record, Hirist's applicant count and AmbitionBox company rating, and Instahyre's job functions and company profile.
- **Filters that cost nothing.** Keyword, city, experience and posting date are applied by the boards' own search wherever they exist, so you only pay for matching jobs.
- **Fair split.** "Maximum results" is shared equally between the boards you pick; when one board runs out of matches, the others fill its part.

### How much does it cost?

You pay a small start fee per run plus a price per 1,000 jobs returned (see the Pricing tab; planned: **$1.00 per 1,000 jobs + $0.005 per run**). Platform usage and proxy are included.

| Run | Jobs | Cost at $1.00 / 1,000 |
|---|---|---|
| 30 "python" jobs from the three boards, last 7 days (the prefilled input) | 30 | ~$0.035 |
| 300 "data analyst" jobs in Bangalore with full details | 300 | ~$0.31 |
| Daily feed: every Internshala internship of one keyword posted in the last day (the whole keyword listing is checked, up to 60 pages) | ~20-100 | ~$0.03-0.11 |
| 5,000 Hirist jobs without details | 5,000 | ~$5.01 |

Turning off *Include full job details* makes runs several times faster (Hirist reads 100 jobs per request, Internshala 40-50). Internshala job pages are large and take a few seconds each.

### Input

| Field | Description | Example |
|---|---|---|
| `boards` | `hirist`, `internshala`, `instahyre` (default: all three) | `["hirist", "instahyre"]` |
| `query` | Skill, role or keyword. Empty = the newest jobs of each board | `"python"` |
| `location` | Indian city or `Remote` / `Work from home`. Bengaluru, Gurugram, New Delhi, Bombay… are understood | `"Bangalore"` |
| `jobUrls` | Job page URLs instead of a search (up to 1,000): Hirist `https://www.hirist.tech/j/…-<id>` or `hirist:<id>`; Internshala `https://internshala.com/internship/detail/…` or `/job/detail/…`; Instahyre `https://www.instahyre.com/job-<id>-…` or `instahyre:<id>` | `["instahyre:444586"]` |
| `employmentType` | `any` (default), `job`, `internship` | `"internship"` |
| `postedWithinDays` | Jobs posted in the last N days (1-90) | `7` |
| `experienceMinYears` / `experienceMaxYears` | Your experience range; jobs whose required range overlaps it | `2`, `5` |
| `includeDetails` | Open every job page for the full description and details (default on) | `false` |
| `maxResults` | Jobs in total, shared between the boards (default 200; 0 = no limit, capped at 10,000 without any keyword, location or date filter; Instahyre is capped at 500 when neither a keyword nor an experience filter narrows it, because it ignores dates and locations) | `100` |
| `maxJobsPerBoard` | Optional cap per board (0 = none) | `50` |

```json
{
    "boards": ["hirist", "internshala", "instahyre"],
    "query": "data analyst",
    "location": "Bangalore",
    "postedWithinDays": 7,
    "maxResults": 100
}
```

#### How the filters work on each board

| Filter | Hirist | Internshala | Instahyre |
|---|---|---|---|
| Keyword | Hirist search (ordered by relevance — the Actor reads all matches, up to 10,000, and delivers them newest first) | Internshala keyword listing | Instahyre skill search (a phrase without results is retried word by word) |
| Location | Hirist city filter (159 cities + Remote); unknown city → warning, no location filter | City listing / work-from-home listing | **Filtered by the Actor** (Instahyre has no location search) — it reads more pages per job delivered, at most 2,100 jobs scanned per run |
| Experience | Hirist range filter | Jobs: "at most N years" (maximum) | Instahyre experience filter (minimum) |
| Posted within | Hirist date filter + exact check | Exact check on the posting time. Keyword / city / remote listings mix several newest-first blocks, so they are read to the end (up to 60 pages, disclosed in the status); the plain listing stops after 4 pages in a row without a match | Not available — Instahyre publishes no posting dates (rows have `postedAt: null`); never counts as a filter for the 500-job cap |
| Employment type | Jobs only (internship runs say "Hirist lists jobs only — no internships") | Internships and/or jobs listings | Instahyre job type |

Keywords are matched by each board's own search, which is fuzzy and board-specific: "python" on Internshala also returns roles that merely list Python among many skills (e.g. robotics trainers), Hirist matches titles and skill tags, and Instahyre matches skill keywords. Expect some loosely related jobs, and filter on `title` or `skills` downstream when you need precision.

### Output

One row per job. Every row has every field; missing values are `null` or `[]`.

```json
{
    "board": "internshala",
    "jobId": "3319766",
    "url": "https://internshala.com/internship/detail/sales-internship-in-bhopal-at-example-careers-private-limited1792392038",
    "title": "Sales",
    "designation": null,
    "companyName": "Example Careers Private Limited",
    "companyId": "example-careers-private-limited-1597411295",
    "companyLogoUrl": null,
    "companySize": null,
    "companyFoundedYear": null,
    "companyRating": null,
    "companyReviewsCount": null,
    "companyIndustry": "Education",
    "companyHq": null,
    "companyWebsite": null,
    "employmentType": "internship",
    "isInternship": true,
    "locations": ["Bhopal"],
    "isRemote": false,
    "experienceMinYears": 0,
    "experienceMaxYears": null,
    "salaryMin": 4000,
    "salaryMax": 10000,
    "salaryCurrency": "INR",
    "salaryPeriod": "month",
    "salaryText": "₹ 4,000 - 10,000 /month",
    "skills": ["Effective Communication", "English Proficiency (Written)", "Interpersonal skills", "MS-Office"],
    "category": "Sales",
    "descriptionText": "About the internship\nRoles & Responsibilities\n1. Visit schools, colleges, and other educational institutions…",
    "descriptionHtml": "<h3>About the internship</h3>Roles &amp; Responsibilities<br>1. Visit schools, colleges…",
    "postedAt": "2026-10-19T06:40:38.000Z",
    "applyBy": "2026-11-18",
    "openings": 6,
    "applicantsCount": null,
    "applicantsText": "Be an early applicant",
    "hasExpired": false,
    "stipendText": "₹ 4,000 - 10,000 /month",
    "durationMonths": 2,
    "startDate": "immediately",
    "perks": ["Certificate", "Job offer"],
    "ppoOfferText": "Job offer upto ₹ 3.5LPA post internship",
    "fixedPay": "₹ 2,000 - 5,000 /month",
    "variablePay": "₹ 2,000 - 5,000 /month",
    "employerHiringSince": "2020-07",
    "employerOpportunitiesPosted": 270,
    "employerCandidatesHired": 75,
    "activelyHiring": true,
    "companyTagline": null,
    "companyNote": "Example Careers Private Limited focuses on the overall development of students…",
    "jobFunctions": [],
    "acceptsOutstation": null,
    "tags": [],
    "isPremium": null,
    "functionalArea": null,
    "detailsScraped": true,
    "searchQuery": "sales",
    "scrapedAt": "2026-10-23T08:00:00.000Z"
}
```

| Field | Notes |
|---|---|
| `board` + `jobId` | The board and its job id. Use both together to deduplicate (ids are per board). The same job posted on two boards appears twice, once per board. |
| `salary*` | In the board's unit: Hirist shows salaries as lakhs per annum on 2-5 % of jobs (converted to yearly INR); Internshala stipends are per month, job CTCs per year, and lump-sum stipends (paid once for the whole internship) have `salaryPeriod: "total"`; Instahyre publishes no salaries. Unpaid internships have `salaryMin: 0`. `salaryText` keeps the board's text. |
| `experienceMinYears` / `experienceMaxYears` | Required experience in years. Internships have a minimum of 0. |
| `postedAt` | ISO 8601 UTC. Instahyre publishes no posting date (`null`). |
| `applicantsCount` | Applicants as an integer. When the board shows a floor ("1000+ applicants") the number is that floor (1000); `applicantsText` keeps the board's wording. |
| `functionalArea` | Reserved: Hirist sends a functional-area id but does not publish its names, so it is `null` for now. |
| `hasExpired` | `true` for closed jobs. Old Hirist jobs opened by URL are still delivered (with `hasExpired: true`) rather than reported as not found. |
| `company*` | Hirist: AmbitionBox rating, reviews, size band, founding year, industry, HQ and description. Instahyre: exact employee count, founding year, tagline and note. Internshala: industry, website, description, hiring since, opportunities posted and candidates hired. Confidential Hirist jobs have no company. |
| `employmentType` | `full_time`, `part_time`, `internship` or `contract`; `null` for Hirist (it does not say) and for Instahyre jobs without details. |
| `detailsScraped` | `false` when *Include full job details* is off, or when a job page could not be read (the row then has the search-result fields and the job is listed in ERRORS). |

Fields that need the job page are empty with *Include full job details* off: `descriptionText`, `descriptionHtml`, `applyBy`, `openings`, `applicantsCount` (Hirist, Internshala), `hasExpired`, `startDate`, `perks`, `fixedPay`, `variablePay`, `employer*`, `companyNote` (Internshala), `companySize` / `companyRating`… (some Hirist companies), `jobFunctions`, `category` and experience (Instahyre).

The Actor never outputs recruiter names, designations, photos or profile links, even where a board sends them. Job descriptions are kept as the employer published them; some very old ads (e.g. Hirist jobs from 2012 opened by URL) contain the recruiter's contact details inside the ad text.

#### Problems

Jobs that could not be read — removed jobs, invalid URLs, jobs delivered without details, list pages that failed — are listed in the run's key-value store under `ERRORS` with the public job page and a reason. The run's status message shows the jobs per board and any shortfall.

### Tips and tricks

- **Complete listings vs. samples.** A keyword search reads every Hirist match (up to 10,000) and delivers them newest first. Internshala listings are read in the board's order (blocks of new jobs with older promoted ones in between); with *Posted within* a keyword / city listing is checked to the end (up to 60 pages). Instahyre returns at most 10,000 jobs per search in its own order (the status says when that limit is reached); with a location the Actor checks at most 2,100 Instahyre jobs.
- **Cheaper runs:** turn off *Include full job details* when the title, company, location, salary and skills are enough.
- **One board at a time** for large exports: `"boards": ["hirist"]` with `"maxResults": 0` and a keyword.

### Scheduling

The Actor keeps nothing between runs. For a daily feed, schedule it with *Posted within* = 1 or 2 days (Hirist and Internshala) and de-duplicate downstream by `board` + `jobId`; a date-filtered Internshala keyword or city listing is checked page by page to the end (up to 60 pages), so no new job hidden behind older promoted ones is missed. Instahyre has no dates: schedule it with a keyword and a small *Maximum results*, and de-duplicate by id.

### Integrations

Export the dataset as JSON, CSV or Excel, or connect it to Google Sheets, Zapier, Make, Slack or your own API client through the Apify integrations. Each run's dataset has an Overview view and one view per board.

# Changelog

This Actor's version history is a separate document: https://apify.com/teodor_banea/indian-job-boards-scraper/changelog.md

# Actor input Schema

## `boards` (type: `array`):

Choose the boards to search. Hirist: tech jobs. Internshala: internships and fresher jobs. Instahyre: tech jobs with company profiles.

## `query` (type: `string`):

Enter a skill, role or keyword, e.g. "python", "data analyst", "react native". Leave empty to list the newest jobs of each board.

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

Enter an Indian city (e.g. "Bangalore", "Mumbai", "Gurgaon", "Delhi", "Hyderabad") or "Remote" / "Work from home". Common spellings such as Bengaluru and Gurugram work. Instahyre has no location search, so the actor filters its jobs itself.

## `jobUrls` (type: `array`):

Paste job page URLs to fetch exactly those jobs (up to 1,000 per run): https://www.hirist.tech/j/…-<id>, https://internshala.com/internship/detail/… or /job/detail/…, https://www.instahyre.com/job-<id>-…. Hirist and Instahyre also accept "hirist:<id>" / "instahyre:<id>". When set, the search fields are ignored.

## `employmentType` (type: `string`):

Choose jobs, internships or both. Hirist lists jobs only; Instahyre and Internshala have both.

## `postedWithinDays` (type: `integer`):

Keep only jobs posted in the last N days (1-90). Instahyre publishes no posting dates, so this filter does not apply to it.

## `experienceMinYears` (type: `integer`):

Your experience range: keep jobs whose required experience overlaps it. Used by Hirist and Instahyre.

## `experienceMaxYears` (type: `integer`):

Upper end of your experience range. Used by Hirist and Internshala jobs (jobs asking for at most this many years).

## `includeDetails` (type: `boolean`):

Open every job page for the full description, apply-by date, openings, applicants, perks, salary breakdown and company profile. Off = faster, cheaper rows from the search results only.

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

Stop after this many jobs in total, shared fairly between the boards. 0 = no limit (capped at 10,000 without any keyword, location or date filter).

## `maxJobsPerBoard` (type: `integer`):

Optional cap for each board. 0 = no per-board cap.

## Actor input object example

```json
{
  "boards": [
    "hirist",
    "internshala",
    "instahyre"
  ],
  "query": "python",
  "location": "Bangalore",
  "jobUrls": [
    "https://www.hirist.tech/j/example-backend-engineer-1676704",
    "instahyre:444586"
  ],
  "employmentType": "any",
  "postedWithinDays": 7,
  "includeDetails": true,
  "maxResults": 30,
  "maxJobsPerBoard": 0
}
```

# Actor output Schema

## `results` (type: `string`):

Every job row of the run as JSON.

## `overview` (type: `string`):

Board, title, company, locations, experience, salary, skills and posting date.

## `resultsCsv` (type: `string`):

The same rows as a CSV download.

## `errors` (type: `string`):

Jobs or pages that could not be read (removed jobs, invalid URLs, jobs delivered without details). Only present when something went wrong.

# 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 = {
    "boards": [
        "hirist",
        "internshala",
        "instahyre"
    ],
    "query": "python",
    "postedWithinDays": 7,
    "maxResults": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("teodor_banea/indian-job-boards-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 = {
    "boards": [
        "hirist",
        "internshala",
        "instahyre",
    ],
    "query": "python",
    "postedWithinDays": 7,
    "maxResults": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("teodor_banea/indian-job-boards-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 '{
  "boards": [
    "hirist",
    "internshala",
    "instahyre"
  ],
  "query": "python",
  "postedWithinDays": 7,
  "maxResults": 30
}' |
apify call teodor_banea/indian-job-boards-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,teodor_banea/indian-job-boards-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/ZtpaaWFNCVlSUb03C/builds/aM3ssRhSWagx4kFXi/openapi.json
