# Instahyre Scraper - India Tech Jobs & Company Data (`neverempty/instahyre-jobs`) Actor

Every job on Instahyre with the hiring company attached: company size, founding year, Instahyre’s own note about the company, locations and the skills each posting asks for. A rejected filter or a rate limit comes back as its own row and is never charged. Unofficial, not affiliated with Instahyre.

- **URL**: https://apify.com/neverempty/instahyre-jobs.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Jobs, Lead generation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.46 / 1,000 job returneds

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

## Instahyre Scraper - India Tech Jobs & Company Data

Pull jobs from **Instahyre** with the hiring company attached: **how many people the company has**, **what year it was founded**, Instahyre's own note about the company, the locations, and the exact skills each posting asks for.

*Unofficial. This Actor is not affiliated with, endorsed by, or sponsored by Instahyre. All product names are trademarks of their respective owners.*

No API key. Reads Instahyre's own public job feed.

***

### Why this one is different

#### It does not pretend to filter by things Instahyre cannot filter

Measured on 2026-09-03 against the live API: sending `location`, `city`, `company_size`, `experience` or `min_experience` **changes nothing** - the total stays at 13,844 jobs. The request answers HTTP 200 and quietly ignores what you asked for.

Only `job_functions` actually filters (id 10 narrows 13,844 → 3,869). So this Actor offers **only that**. A location field would look better on the input form and would be a lie.

#### A filter Instahyre rejects tells you so, and is not charged

An unknown job function id makes the API answer **HTTP 400**. You get one row naming the ids that do work:

```
10 = Backend Development   1 = Full-Stack Development
 9 = Data Science / ML    76 = Other Software Development
```

That row is **not charged**. The run does not fall back to "all jobs" and let you think you filtered.

#### You are not charged for jobs you did not ask for

Instahyre answers with **35 jobs per request no matter what `limit` is set to** (asking for 10 still returns 35). This Actor cuts the last page down to your `maxJobs`, so asking for 40 jobs charges 40 events - not 70.

#### The rate limit is handled, and told to you when it bites

Measured: about **20 requests in quick succession returns HTTP 429**, clearing after roughly an hour. With the Apify residential proxy on (default), sessions rotate so larger runs finish - measured on 2026-09-03: **300 jobs in 9 requests, 17 seconds, no 429, no duplicate ids**. If a run is still cut short, you get a row saying **how many jobs were returned before it happened** - and that row is not charged.

#### Nothing is invented

Instahyre's job feed carries **no salary, no years of experience and no posted date** - the detail endpoint returns the same 14 fields as the list. So those columns do not exist in the output. Empty columns that look like data are worse than no columns.

***

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `jobFunctions` | array | `[]` (all) | Instahyre job function ids. Several are combined as a union (10 + 1 = 4,900 jobs) |
| `maxJobs` | integer | 35 | 1-1000. One job = one row = one charged event |
| `useProxy` | boolean | `true` | Rotates the session so bigger runs are not cut off by the rate limit |
| `keywords` | array | — | Keep only jobs containing one of these words |
| `keywordMatch` | string | `any` | `any` or `all` |
| `excludeKeywords` | array | — | Drop jobs containing one of these |
| `companyNames` | array | — | Keep only these companies (partial match) |
| `postedWithinDays` | integer | 0 | 0 = no limit. **An unreadable date is kept** |
| `monitoringMode` | boolean | `false` | Return only jobs not returned on a previous run |
| `resetMonitoringState` | boolean | `false` | One-shot: forget what was already returned |

#### Filters are applied before you are charged

The filters narrow the jobs already read - **nothing extra is fetched from Instahyre** - and a job that does not match is never delivered and never charged. If the search returns jobs but none match your filters you get **one unpaid row saying exactly that** (`no-filter-match`), so you can tell "the filter was too tight" apart from "there is nothing there".

There is deliberately **no salary filter**: Instahyre's public search does not publish a salary, and a filter over a field that is always empty would be a filter that silently drops everything.

#### Monitoring mode turns this into a daily feed

Schedule it with `monitoringMode: true` and each run reads the newest jobs and returns **only the ones it has not returned before**. Jobs read but filtered out are remembered too, so changing a filter later does not resurrect them as false "new" postings.

The minimal call is an empty input: 35 jobs from the whole board.

***

### Output columns

| Column | Example |
|---|---|
| `jobId` | `434743` |
| `url` | the public job page |
| `title` | `Senior Business Consultant (Life Insurance)` |
| `company` | `Infosys BPM` |
| `companyTagline` | `Reboot, reconnect, revive` |
| `companyFounded` | `2002` |
| `companyEmployeeCount` | `1000` |
| `companyNote` | Instahyre's own description of the company |
| `companyLogo` | image URL |
| `locations` | `Pune` |
| `skills` | `["Business Analyst", "JIRA", "SQL", ...]` |
| `acceptsOutstation` | `true` |
| `status` / `note` | only on rows that carry no job, with the reason |
| `scrapedAt` | ISO timestamp of the fetch |

***

### Measured, not estimated

Checked against the live API on 2026-09-03, not read off documentation:

- **13,844 jobs** in the feed (`meta.total_count`).
- **`limit` is ignored**: 10, 35, 50 and 100 all return exactly 35 rows.
- **Only `job_functions` filters**: id 10 → 3,869 · id 1 → 1,890 · ids 10+1 → 4,900 (a union, not a sum).
- **Unknown ids return HTTP 400**, they are not silently ignored.
- **Rate limit**: 300 ms apart, the 20th request returned HTTP 429; it had cleared about 80 minutes later.
- `https://www.instahyre.com/robots.txt` is 62 bytes and contains **no Disallow rules at all**.

The Actor ships with **9 checks** run against a saved copy of the real API response, and a **mutation suite of 14 deliberate breakages - all 14 are caught**.

***

### Typical uses

- Build a live picture of who is hiring in Indian tech, with company size attached to every role.
- Track which skills a function is asking for right now (the `skills` array is the posting's own list).
- Feed a recruiter workflow or a job board with fresh roles and the company context already joined.
- Compare hiring volume between functions - Backend vs Data Science vs Full-Stack - from the counts the API returns.

***

### Notes and limits

- Instahyre is an Indian tech hiring platform. Roles and companies are India-based.
- There is no salary, experience or posted-date field in Instahyre's feed. See above - they are not invented here.
- `acceptsOutstation` is Instahyre's own flag for whether the employer considers candidates from other cities.

### Other tools by NeverEmpty

- **[Internshala Scraper - India Jobs & Internships, Salary](https://apify.com/neverempty/internshala-jobs)** - jobs and internships with pay parsed into numbers and the deadline as a date.
- **[Job Listing API - Career Site Jobs from Any ATS](https://apify.com/neverempty/ats-jobs-api)** - open roles straight from company career sites.

### Support

Found a row that looks wrong? Open an issue on the Actor page with the `url` from the row.

# Actor input Schema

## `jobFunctions` (type: `array`):

Instahyre's own job function ids. Leave empty to get every job. Known ids, measured on 2026-09-03: 10 = Backend Development (3,869 jobs), 1 = Full-Stack Development (1,890), 9 = Data Science / Machine Learning (1,477), 76 = Other Software Development (1,091). Several ids are combined as a union. An id Instahyre does not have makes the API answer HTTP 400, and you get one row saying so instead of a silently unfiltered result. Instahyre publishes no working filter for location, salary or experience, so those are not offered here - offering them would be a lie.

## `maxJobs` (type: `integer`):

How many jobs to return at most. One job = one row = one charged event. Instahyre always answers with 35 jobs per request regardless of what is asked, so this Actor cuts the last page to your number - you are never charged for jobs you did not ask for. Rows that carry no job (a rejected filter, a rate limit) are returned too and are never charged.

## `useProxy` (type: `boolean`):

Default: true. Instahyre rate-limits about 20 requests in quick succession (measured: HTTP 429 on the 20th, clearing after roughly an hour). The proxy rotates the session so larger runs finish. Turn it off to save proxy cost when you only need a page or two.

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

Keep only jobs whose title, company, company tagline, skills or location contains one of these words. Case is ignored. Nothing extra is fetched from Instahyre - this narrows the jobs already read, and jobs that do not match are never charged.

## `keywordMatch` (type: `string`):

`any` keeps a job that contains at least one keyword. `all` keeps only jobs that contain every keyword.

## `excludeKeywords` (type: `array`):

Drop any job containing one of these words - for example a staffing company you do not want. Applied after the keyword filter.

## `companyNames` (type: `array`):

Keep only jobs from companies whose name contains one of these (partial match, case ignored). Leave empty for all companies.

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

Keep only jobs posted in the last N days, when Instahyre states a posted date. 0 means no limit. A job whose date cannot be read is kept, not dropped.

## `monitoringMode` (type: `boolean`):

Default: false. Turn it on and schedule this Actor daily: each run reads the newest jobs and returns only the ones it has not returned before, so you pay for new postings instead of the same list again.

## `resetMonitoringState` (type: `boolean`):

Default: false. Turn it on for a single run to forget which jobs were already returned and start monitoring again from scratch.

## Actor input object example

```json
{
  "jobFunctions": [],
  "maxJobs": 35,
  "useProxy": true,
  "keywords": [],
  "keywordMatch": "any",
  "excludeKeywords": [],
  "companyNames": [],
  "postedWithinDays": 0,
  "monitoringMode": false,
  "resetMonitoringState": false
}
```

# Actor output Schema

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

One row per job: title, company with its size, founding year and Instahyre note, locations, and the skills the posting asks for. Rejected filters and rate limits come back as their own rows and are not charged.

# 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 = {
    "jobFunctions": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/instahyre-jobs").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 = { "jobFunctions": [] }

# Run the Actor and wait for it to finish
run = client.actor("neverempty/instahyre-jobs").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 '{
  "jobFunctions": []
}' |
apify call neverempty/instahyre-jobs --silent --output-dataset

```

## MCP server setup

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

```

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/FuLSZPJbRXvFUsKnw/builds/9FeE5trg0hf4VaEFC/openapi.json
