# India Tech Hiring Signals — Instahyre Jobs & Company Velocity (`foxlabs/india-tech-hiring-signals`) Actor

Hiring velocity per Indian tech employer from Instahyre: open roles, new roles this week and in your window, function and skill mix, headcount bucket, founded year — or PII-free job rows. No recruiter names, no login, no API key.

- **URL**: https://apify.com/foxlabs/india-tech-hiring-signals.md
- **Developed by:** [Berkan Kaplan](https://apify.com/foxlabs) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 company hiring signals

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

## India Tech Hiring Signals — Instahyre Jobs & Company Velocity 🇮🇳

**foXLabs hiring series:** [LinkedIn Hiring Signals](https://apify.com/foxlabs/linkedin-hiring-signals) · [Company Hiring Signals (any ATS)](https://apify.com/foxlabs/company-hiring-signal-multi-ats) · [LinkedIn Jobs](https://apify.com/foxlabs/linkedin-jobs-scraper) · [Greenhouse](https://apify.com/foxlabs/greenhouse-job-board-scraper) · [Lever](https://apify.com/foxlabs/lever-job-board-scraper) · [Ashby](https://apify.com/foxlabs/ashby-job-board-scraper) · [Workday](https://apify.com/foxlabs/workday-job-board-scraper) · [SmartRecruiters](https://apify.com/foxlabs/smartrecruiters-job-board-scraper) · [Personio](https://apify.com/foxlabs/personio-job-board-scraper) · [Teamtailor](https://apify.com/foxlabs/teamtailor-job-board-scraper) · India firmographics: [Indian Company Data](https://apify.com/foxlabs/indian-company-data)
**foXLabs India series:** [Company registry](https://apify.com/foxlabs/indian-company-data) · [Government tenders](https://apify.com/foxlabs/india-government-tenders) · [NSE filings](https://apify.com/foxlabs/india-listed-company-filings) · [IndiaMART suppliers](https://apify.com/foxlabs/indiamart-supplier-data)

🎉 Turn Instahyre's public job board into a hiring-velocity signal for Indian tech companies — no login, no API key, one row per employer with open roles, new roles this week and in your window, function and skill mix, headcount bucket and founded year. Or one PII-free row per listing.
Built for B2B sales and go-to-market teams selling into Indian tech, and for VC and analyst teams tracking which startups are scaling.

### 🔍 What is India Tech Hiring Signals — and when should you use it?

Instahyre is an Indian tech-hiring marketplace where employers — from 10-person startups to Accenture and Amazon — post open roles. This actor reads its public job search and turns it into **company-level hiring signals**: for every employer that matches your filters it counts the open roles, how many of them appeared in the last 7 days and in your chosen window, which functions and skills they hire for, and the employer's headcount bucket and founded year. Switch to jobs mode for one clean row per listing instead.

**Use it when you need:** a list of Indian tech companies that are hiring right now (for outbound or account prioritisation); the hiring velocity of a fixed watch list of companies, run weekly; a read on which startups in a city, function or industry are scaling; or PII-free job-posting data for market analysis.

**Use something else when:** you need recruiter or hiring-manager contacts (not collected — by design), salaries (Instahyre does not publish them), or companies that do not hire on Instahyre — use [LinkedIn Hiring Signals](https://apify.com/foxlabs/linkedin-hiring-signals) or [Company Hiring Signals (any ATS)](https://apify.com/foxlabs/company-hiring-signal-multi-ats). For registry firmographics (CIN, directors, financials) pair it with [Indian Company Data](https://apify.com/foxlabs/indian-company-data).

### 🤖 Use with AI agents

**Already on the Apify MCP server?** Ask for this Actor by name: `foxlabs/india-tech-hiring-signals`.

**Your agent can pay for its own runs.** This Actor is pay-per-event with agentic payments, so an agent can discover it, run it and settle the bill over **x402 (USDC on Base)** or **Skyfire** — no Apify account or API token of its own. Billing is the same either way: per delivered company or job row, never for summary or error rows.

Otherwise paste this into Claude, ChatGPT, Cursor or any MCP-enabled assistant:

```
I want hiring signals for Indian tech companies from Instahyre using the Apify Actor
`foxlabs/india-tech-hiring-signals`.

Input: `mode` is "companies" (one row per employer with open roles and new roles in the last
7 days / last N weeks) or "jobs" (one row per listing). Filters: `locations` (e.g. "Bangalore"),
`jobFunctions` (e.g. "category:software-engineering"), `companySize` ("small" | "medium" | "large"),
`companies` (a watch list of employer names), `skills`, `industryTypes`, `experienceYears`.
`weeksWindow` (1-8) sets the velocity window; `maxResults` caps the rows.

Start with:
{"mode":"companies","locations":["Bangalore"],"jobFunctions":["category:software-engineering"],"companySize":"medium","weeksWindow":4,"maxResults":200}

Ask me which city, function or companies to track, run the Actor, then rank the companies
by newJobsInWindow and summarise the top ones as a table.
```

Things you can ask your agent for:

- "Which 50–200-person software companies in Bangalore opened the most engineering roles in the last four weeks?"
- "Track Razorpay and Zepto every Monday and tell me whose hiring is speeding up."
- "Which banking and fintech employers are hiring data and ML people right now?"

The machine-readable API, MCP config and OpenAPI definition live at `apify.com/foxlabs/india-tech-hiring-signals.md`.

### 📋 Overview

Everything you need to turn Instahyre's public job board into a clean hiring-velocity table — in one actor, with no login, cookies or API key.

**Why teams pick this actor:**

- ✅ **Company-first, not another job dump** — one row per employer with open roles, new roles in the last 7 days and in your window, top functions, top skills and sample titles.
- 📅 **Posting dates Instahyre's search doesn't show** — resolved from Instahyre's own job sitemap; accuracy measured against each job page's `datePosted` (see *How to read the numbers*).
- 🔒 **PII-free by design** — recruiter names, designations and profile photos never reach your dataset: the default path never requests them, and with `includeDescriptions` the detail record is reduced on arrival to description, experience, category, functions and the internship/active flags.
- 🎯 **Filters that match the site** — cities, 107 job functions in 19 categories, 74 industries, company size, skills, experience, and a company watch list.
- 🧮 **Complete counts** — companies mode scans the whole filtered set, split so every part fits Instahyre's 10,000-result window (a part that still exceeds it is read up to the window and flagged in the log), and de-duplicates by job ID; `maxResults` only caps the output.
- 💰 **Pay only for results** — summary and error rows are never billed.
- 🤖 **Agent-ready** — MCP + x402 agentic payments.

### ✨ Features

- 🏢 **Companies mode (default)** — hiring velocity per employer: `activeJobs`, `newJobsLast7Days`, `newJobsInWindow`, `topFunctions`, `topSkills`, `sampleTitles`, headcount bucket, founded year, tagline, Instahyre company page.
- 📄 **Jobs mode** — one row per listing: title, company, locations, skill tags, category/functions, job type, posting date, public URL; optional plain-text description and required experience.
- 👀 **Watch lists** — track named companies; a misspelled name is reported and skipped, the rest of the list still runs.
- 🕳️ **Honest empty results** — a valid filter that matches nothing returns one `SUMMARY` row that says so and suggests what to change; the run still succeeds.
- 🐢 **Rate-limit aware** — when Instahyre answers HTTP 429, every worker pauses and the run slows down; each pause is counted in the run's `SUMMARY` record.

### 🎬 Quick Start

```bash
curl -X POST "https://api.apify.com/v2/acts/foxlabs~india-tech-hiring-signals/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"companies","locations":["Bangalore"],"jobFunctions":["category:software-engineering"],"companySize":"medium","weeksWindow":4,"maxResults":200}'
```

The run-sync endpoint waits for the run and returns the rows. In a local run without a proxy this input took 117 s and 43 requests and returned 200 company rows (`run-a3-prefill`, 2026-09-10); with the default Apify Proxy on the platform it has not been timed yet.

### 🚀 Getting Started (3 steps)

1. **Pick the output** — `companies` for hiring velocity per employer, `jobs` for one row per listing.
2. **Narrow the market** — a city, a function or category, a company size, skills or industries — or a watch list of company names.
3. **Run and export** — JSON, CSV or Excel from the dataset; schedule it weekly for a time series.

### 📥 Input

```json
{"mode":"companies","locations":["Bangalore"],"jobFunctions":["category:software-engineering"],"companySize":"medium","weeksWindow":4,"maxResults":200}
```

| Field | Type | Description |
|---|---|---|
| `mode` | string | `companies` (default) — one row per employer; `jobs` — one row per listing. |
| `locations` | array | City names as Instahyre spells them: `Bangalore`, `Gurgaon`, `Hyderabad`, `Pune`, `Mumbai`, `Chennai`, `Noida`, `Delhi`, `Work From Home`. Several = OR. An unknown name stops the run with a clear error. |
| `jobFunctions` | array | Whole categories (`category:software-engineering`) or single functions (`function:backend-development`) — the form lists all 19 categories and 107 functions. Several = OR. |
| `skills` | array | Skill tags as they appear on listings (`Python`, `React.js`, `Machine Learning`). Case does not matter. |
| `companies` | array | Watch list of employer names as shown on Instahyre (`Razorpay`, `Zepto`). Case does not matter. |
| `companySize` | string | `any` (default), `small` (up to 50 employees), `medium` (50–200), `large` (200+) — Instahyre's own size classes. |
| `industryTypes` | array | Employer industries as Instahyre classifies them, e.g. `banking-financial-services`, `computer-software-it-internet`. |
| `experienceYears` | integer | Keeps roles whose required experience range covers this many years (`3` → e.g. 2–5 years). |
| `weeksWindow` | integer | Velocity window in weeks for `newJobsInWindow`, 1–8 (default 4). |
| `maxResults` | integer | Companies mode: employer rows to emit, best velocity first. Jobs mode: listings. `0` = no limit (default 500). |
| `includeDescriptions` | boolean | Jobs mode only: adds the plain-text description, required experience and exact functions (one extra request per job). |
| `requestDelayMs` | integer | Pause after every request, per worker (default 600). |
| `maxConcurrency` | integer | Requests in flight, 1–3 (default 2). |
| `proxyConfiguration` | object | Apify Proxy (default on). |

Leave every filter empty — for example an API call with `{}` — and the actor scans every open role on Instahyre (13,386–13,610 when we measured on 2026-09-10), which takes several hundred requests. Start with a city and a function, as in the example above.

### 📤 Output

#### Companies mode — one row per employer (default)

Rows are sorted by `newJobsInWindow`, then `newJobsLast7Days`, then `activeJobs`; `maxResults` keeps the top of that list. Fill rates measured on the prefilled example input (local run `run-a3-prefill`, 200 rows, 2026-09-10).

| Field | Description | Filled |
|---|---|---|
| `companyName` | Employer name as shown on Instahyre | 100% |
| `instahyreEmployerId` | Instahyre's employer ID — the stable join key across runs | 100% |
| `tagline` | The employer's one-line tagline on Instahyre | 100% |
| `about` | Instahyre's short company description | 100% |
| `foundedYear` | Founding year as listed on Instahyre; Instahyre's `1900` placeholder is returned as `null` | 98% (5 of 297 employers in the final test runs carried the placeholder) |
| `headcountBucket` | Instahyre's headcount bucket: `0-10`, `10-50`, `50-200`, `200-500`, `500-1000`, `1000+` | 100% |
| `companySizeClass` | `small` / `medium` / `large`, derived from `headcountBucket` | 100% |
| `instahyreCompanyUrl` | The employer's Instahyre careers page | 100% |
| `locations` | Cities of its matching open roles, most frequent first | 100% |
| `activeJobs` | Open roles matching your filters | 100% |
| `newJobsLast7Days` | Of those, roles posted in the last 7 days (today included) | 100% |
| `newJobsInWindow` | Roles posted in the last `weeksWindow` weeks | 100% |
| `weeksWindow` | The window you asked for, echoed for time series | 100% |
| `undatedJobs` | Open roles without a resolved posting date — posted before the date horizon, or all of them if the sitemap could not be read (then the velocity counts are `null`) | 100% |
| `earliestPostedAt` / `lastPostedAt` | Oldest and newest posting date among its dated open roles (ISO) | 40.5% (81/200) — see *The date horizon* |
| `topFunctions` | Up to 10 `{function, count}` — the function mix of its open roles | 100% |
| `topSkills` | Up to 10 `{skill, count}` from the listings' skill tags (case-merged) | 100% |
| `sampleTitles` | Up to 5 titles, newest first | 100% |
| `source`, `scrapedAt` | `Instahyre`; run timestamp (ISO) | 100% |

Real row from `run-a3-prefill`:

```json
{
  "companyName": "NuPlay AI",
  "instahyreEmployerId": 49316,
  "tagline": "AI agents that get better on the job",
  "about": "NuPlay AI is a GenAI company building self-improving autonomous AI agents that automate customer engagement and complex enterprise workflows through voice, chat, and seamless business-system integrations.",
  "foundedYear": 2024,
  "headcountBucket": "50-200",
  "companySizeClass": "medium",
  "instahyreCompanyUrl": "https://www.instahyre.com/jobs-at-nuplay-ai/",
  "locations": [
    "Bangalore"
  ],
  "activeJobs": 17,
  "newJobsLast7Days": 2,
  "newJobsInWindow": 7,
  "weeksWindow": 4,
  "undatedJobs": 6,
  "earliestPostedAt": "2026-08-07",
  "lastPostedAt": "2026-09-10",
  "topFunctions": [
    {
      "function": "Backend Development",
      "count": 9
    },
    {
      "function": "Full-Stack Development",
      "count": 9
    },
    {
      "function": "Other Software Development",
      "count": 4
    },
    {
      "function": "Software Testing / QA / SDET",
      "count": 4
    },
    {
      "function": "Engineering Management",
      "count": 3
    },
    {
      "function": "Frontend Development",
      "count": 3
    },
    {
      "function": "Data Engineering / DWH / ETL",
      "count": 1
    }
  ],
  "topSkills": [
    {
      "skill": "AWS",
      "count": 10
    },
    {
      "skill": "Python",
      "count": 10
    },
    {
      "skill": "Azure",
      "count": 9
    },
    {
      "skill": "GCP",
      "count": 9
    },
    {
      "skill": "JavaScript",
      "count": 5
    },
    {
      "skill": "Kubernetes",
      "count": 5
    },
    {
      "skill": "Next.js",
      "count": 5
    },
    {
      "skill": "Node.js",
      "count": 5
    },
    {
      "skill": "React",
      "count": 5
    },
    {
      "skill": "Cypress",
      "count": 4
    }
  ],
  "sampleTitles": [
    "Software Engineer (Backend)",
    "QA / SDET Engineer",
    "Machine Learning Engineer",
    "QA Engineer",
    "QA Engineer"
  ],
  "source": "Instahyre",
  "scrapedAt": "2026-09-10T14:17:54.213Z"
}
```

#### Jobs mode — one row per listing

Fill rates measured on `{"mode":"jobs","locations":["Bangalore"],"skills":["python"],"maxResults":100}` (local run `run-b-jobs-python`, 100 rows) and, for the detail fields, on `run-f-jobs-descriptions` (`includeDescriptions: true`).

| Field | Description | Filled |
|---|---|---|
| `jobId` | Instahyre job ID — unique per row | 100% |
| `title` | Job title | 100% |
| `companyName`, `instahyreEmployerId`, `instahyreCompanyUrl` | The employer, as in companies mode | 100% |
| `locations` | Cities of the role | 100% |
| `keywords` | Skill tags on the listing (average 6.4 per row) | 100% |
| `jobCategory` | Category the job was found under (exact from the detail record with `includeDescriptions`) | 100% in `run-b-jobs-python`; empty in watch-list runs unless `includeDescriptions` is on |
| `jobFunctions` | Functions — filled when you filter by function (without a watch list) or turn on `includeDescriptions` | 0% in `run-b-jobs-python` (no function filter); 100% (5/5) in `run-f-jobs-descriptions` |
| `jobType` | `full-time` or `internship` | 100% |
| `experienceMinYears` / `experienceMaxYears` | Required experience — `includeDescriptions` only | 100% (5/5) in `run-f-jobs-descriptions`; empty otherwise |
| `headcountBucket`, `companySizeClass`, `foundedYear` | Employer firmographics | 100% |
| `publicUrl` | The public job page on instahyre.com | 100% |
| `postedAt` | Posting date (ISO) — see *How to read the numbers* | 43.0% (43/100) — older roles predate the horizon |
| `postedAtSource` | `sitemap-lastmod`, or `id-newer-than-sitemap` for roles newer than the sitemap (dated to the run day) | same as `postedAt` |
| `description` | Plain-text description — `includeDescriptions` only | 100% (5/5) in `run-f-jobs-descriptions`; field absent otherwise |
| `source`, `scrapedAt` | `Instahyre`; run timestamp | 100% |

Real row from `run-b-jobs-python`:

```json
{
  "jobId": 442436,
  "title": "Ai Engineer",
  "companyName": "Altimetrik",
  "instahyreEmployerId": 2292,
  "instahyreCompanyUrl": "https://www.instahyre.com/jobs-at-altimetrik/",
  "locations": [
    "Bangalore",
    "Chennai",
    "Pune"
  ],
  "keywords": [
    "Python",
    "Machine Learning",
    "TensorFlow",
    "LLMs",
    "PyTorch"
  ],
  "jobCategory": "Software Engineering",
  "jobFunctions": null,
  "jobType": "full-time",
  "experienceMinYears": null,
  "experienceMaxYears": null,
  "headcountBucket": "1000+",
  "companySizeClass": "large",
  "foundedYear": 2012,
  "publicUrl": "https://www.instahyre.com/job-442436-ai-engineer-at-altimetrik-bangalore-chennai-pune/",
  "postedAt": "2026-09-09",
  "postedAtSource": "sitemap-lastmod",
  "source": "Instahyre",
  "scrapedAt": "2026-09-10T14:08:24.226Z"
}
```

#### Empty or rejected runs — one `SUMMARY` row

A valid filter that matches nothing does not end silently: the run **succeeds** with one `SUMMARY` row (never billed) that names the filters and suggests what to relax. A value Instahyre rejects (for example an unknown city) stops the run with the same kind of row and a clear error. Real row from `run-e-valid-zero`:

```json
{
  "type": "SUMMARY",
  "status": "empty",
  "message": "Instahyre returned no jobs for: locations=Bangalore, skills=Python, companySize=small, experienceYears=25.",
  "hint": "Locations are matched as Instahyre spells them — common ones: Bangalore, Gurgaon, Hyderabad, Work From Home, Pune, Mumbai, Chennai, Noida, Delhi. Skills match the listing's skill tags, e.g. \"Python\", \"React.js\", \"Data Structures\". experienceYears keeps only roles whose experience range covers that value.",
  "cells": [
    {
      "label": "all functions",
      "total": 0
    }
  ],
  "warnings": [],
  "source": "Instahyre",
  "scrapedAt": "2026-09-10T14:22:35.610Z"
}
```

#### How to read the numbers

- **Posting dates.** Instahyre's search does not return dates. The actor reads Instahyre's own job sitemap (one request per 1,000 jobs) and dates each job by the earliest `lastmod` among it and every newer job, which corrects most later edits. On 2026-09-10 we checked 10 jobs posted between 13 Aug and 10 Sep against the `datePosted` on their own job pages: **10 of 10 exact** (run `run-b-jobs-python`; 2 of them were newer than the sitemap and correctly dated to the run day). A second sample of 12 job pages saved earlier that day, 7 of them edited after posting, matched 11 of 12 — the miss was one day late. In these 22 checks the date was never early.
- **The date horizon.** Dates are resolved back to your window plus two weeks (with the default 4-week window it reached back to 2026-07-24 in `run-a3-prefill`). Older open roles are counted in `activeJobs` and `undatedJobs` but can never be "new".
- **Velocity counts listed roles.** A role that opened and closed inside the window is no longer listed, so it is not counted.
- **Function mix.** With a function or category filter, `topFunctions` is exact per function. Without one it is at category level. For watch-list rows it is Instahyre's own function breakdown for that employer, which lists its top 4 functions.
- **Size classes.** Instahyre's `companySize` filter uses its own classification; for 3 of 200 employers in `run-a3-prefill` it disagreed with the employer's `headcountBucket` (for example Locus.sh, `200-500`, returned under *medium*). The row always shows the employer's bucket.
- **`foundedYear`** is Instahyre's value, except Instahyre's `1900` placeholder, which is returned as `null`. 5 of the 297 employers in the final test runs carried it — all long-established groups such as Taylor & Francis Group, Aditya Birla Group and MUFG.
- **Jobs mode with `maxResults`** stops as soon as it has enough listings, scanning tech categories first (Software Engineering, Data Science & Analytics, IT Operations, …), then returns them newest first — the newest *N* listings of that scan, not necessarily of all of Instahyre.

### 💼 Use cases

**1. GTM lead lists — sell to companies while they hire.** A company opening five backend roles this month is buying developer tooling, cloud and recruiting services.
*Input:* a city + function + company size (the prefilled example input). *Output:* employers ranked by new roles in the window, with headcount bucket, founded year and sample titles. *Use:* a prioritised account list for outbound, refreshed weekly.

**2. VC and analyst signals — spot who is scaling.** Hiring velocity is one of the earliest public signs that a startup raised money or found traction.
*Input:* a watch list of portfolio or target companies, scheduled weekly. *Output:* one row per company with open roles and new roles per window. *Use:* a company × week time series — flag accelerations and freezes before the press release.

**3. Talent-market mapping — who competes for your hires.** See which employers hire for the same skills in the same city.
*Input:* `skills` + `locations`, jobs or companies mode. *Output:* listings or employers with their skill mix. *Use:* salary benchmarking lists, employer-branding targets, competitive hiring maps.

### 🔗 Integration

**JavaScript / Node.js**

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('foxlabs/india-tech-hiring-signals').call({"mode":"companies","locations":["Bangalore"],"jobFunctions":["category:software-engineering"],"companySize":"medium","weeksWindow":4,"maxResults":200});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

**Python**

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('foxlabs/india-tech-hiring-signals').call(run_input={"mode":"companies","companies":["Razorpay","Zepto"],"weeksWindow":4})
for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['companyName'], item['activeJobs'], item['newJobsInWindow'])
```

**Automation (n8n / Zapier / Make):** a weekly schedule → HTTP request to the actor API with your watch list → append the dataset to a sheet or warehouse table keyed on `instahyreEmployerId` + run date → alert when `newJobsLast7Days` jumps.

### 📊 Pricing

Pay-per-event: **`company-signal` per delivered company row** and **`job-record` per delivered job row**. `SUMMARY` rows (empty results, rejected input) are never billed. [View current pricing.](https://apify.com/foxlabs/india-tech-hiring-signals)

You pay for the rows you receive, so `maxResults` is also your spending cap. For scale: the prefilled example input scanned 656 open roles with 43 requests and returned 200 company rows (`run-a3-prefill`).

### ❓ FAQ

**Do I need an Instahyre account, login or API key?** No. The actor reads the same public job search the website uses, plus the public job sitemap for posting dates.

**How current is the data?** Every run queries Instahyre live. Open-role counts are as of the run; posting dates come from Instahyre's job sitemap, and roles newer than the latest sitemap are dated to the run day — correct for both such roles in our date check, but it can be a day late for a role posted on the sitemap's own last day.

**How accurate are the posting dates?** On 2026-09-10, 10 of 10 jobs checked against their job page's own `datePosted` were exact (13 Aug – 10 Sep, run `run-b-jobs-python`), and 11 of 12 in a second sample that included postings edited after publication; the one miss was a day late. Roles posted after Instahyre last rebuilt its sitemap are dated to the run day.

**Why are `earliestPostedAt` / `lastPostedAt` or `postedAt` sometimes empty?** Dates are resolved only for roles posted since the date horizon — your window plus two weeks (about six weeks with the default window). Older roles that are still open are counted in `activeJobs` and `undatedJobs`, never in the new-role counts. With the prefilled example input, 481 of the 633 open roles behind the 200 rows (76.0%) predated the horizon (2026-07-24), so 119 of the 200 companies have no dated role (`run-a3-prefill`).

**Does `newJobsInWindow` count roles that were opened and already closed?** No. Instahyre's search returns the roles listed at run time and drops closed ones (its total fell from 13,610 to 13,387 within eight minutes while we measured), so velocity means new roles that are still listed at run time.

**Why no recruiter names or contacts?** By design. Instahyre's job records name the recruiter who posted a role; that is personal data (India's DPDP Act, GDPR), so the actor drops those fields the moment a record arrives and never stores them. Company-level data is what a hiring signal needs.

**How long does a run take?** Measured locally without a proxy on 2026-09-10: the prefilled example input (656 roles, 43 requests) took 117 s, of which 50 s were three rate-limit pauses (5, 15 and 30 s), after which the run slowed itself by 2 s per request (`run-a3-prefill`); 100 jobs-mode rows took 14 s (`run-b-jobs-python`); a three-name watch list took 12 s (`run-c-watchlist`). A scan costs one request per 35 matching roles in each function it reads, plus about 9 fixed requests (7 for posting dates, a probe and an internship check) and any rate-limit retries. On Apify, with the default proxy, these timings have not been measured yet.

**How many new roles appear per day?** Instahyre-wide, 71–186 new roles per weekday (median 139) and 7–27 per weekend day between 26 Aug and 8 Sep 2026, counted from Instahyre's job sitemap with the same dating method. A 7-day window always contains a weekend, so compare weeks with weeks.

**Can I export to CSV / Excel / JSON?** Yes — directly from the Apify dataset. For CSV, `topFunctions` and `topSkills` are lists of `{function, count}` and `{skill, count}` objects; flatten them in your tool of choice.

### 🐛 Troubleshooting

- **"Instahyre rejected the query — locations: Invalid location."** — the city is not spelled the way Instahyre spells it; use one of the names in the input description. The run stops without charging.
- **A watch-list company has no row** — the log and the `SUMMARY` record say why: either the name is not an Instahyre employer name (check the spelling on the company's Instahyre page) or it has no open role matching your other filters.
- **One `SUMMARY` row and nothing else** — your filters are valid but match no open role right now; the row's `hint` suggests which filter to relax.
- **"HTTP 429 — pausing all requests"** in the log — Instahyre's rate limit; the actor waits and continues on its own. Keep `maxConcurrency` at 2 or lower.
- **Velocity counts are empty (`null`)** — the job sitemap could not be read in that run (for example a Cloudflare check on the proxy IP); the log says so. Open-role counts are still correct; run it again later.

### ⚠️ Trademark

Independent, third-party tool. Not affiliated with, endorsed by or connected to Instahyre or Blob Infotech Private Limited. "Instahyre" and related marks belong to their owners and are used here for identification only.

### ⚖️ Is it legal to scrape this data?

This actor reads publicly listed job postings and employer profiles from Instahyre without logging in, at a polite rate, and deliberately collects no personal data — recruiter names, designations and profile photos are discarded. Instahyre's Terms of Use govern how its content may be used; review them for your use case. Job descriptions (optional) are published text and could still mention a person; personal data is protected by India's DPDP Act, the GDPR and similar laws, so only process it with a legitimate basis. See Apify's blog post on the legality of web scraping.

### 🤝 Support & contact

- 🌐 **Website:** [data.foxlabs.com.tr](https://data.foxlabs.com.tr)
- 📧 **Email:** info@foxlabs.com.tr
- 🐛 **Issues:** open a ticket in the Actor's **Issues** tab
- 🧰 **More clean B2B data actors:** [Fox Labs on Apify](https://apify.com/foxlabs)

### Changelog

#### 0.1 — 2026-09-10 — initial release

- `agencyFlag` / `agencySignals` removed before release. Instahyre lists an agency-posted role under the client company, so a self-description heuristic flagged none of 244 employers in testing, and a column that is always `false` would mislead.
- `foundedYear` returns `null` for Instahyre's `1900` placeholder (5 of 297 employers in testing).
- Two outputs from Instahyre's public job search: **companies** (one row per employer with hiring velocity — open roles, new roles in the last 7 days and in a 1–8 week window, function and skill mix, sample titles, headcount bucket, founded year, tagline, Instahyre page) and **jobs** (one PII-free row per listing, optional plain-text description and required experience).
- Filters mapped to Instahyre's own facets: locations, 19 categories / 107 job functions, skills, a company watch list, company size, 74 industries, experience years.
- Posting dates from Instahyre's job sitemap (earliest `lastmod` at or above each job ID). Checked on 2026-09-10 against job pages' own `datePosted`: 10 of 10 exact, and 11 of 12 in a second sample (the miss was a day late). If the sitemap cannot be read, velocity counts and `postedAt` are `null`, never a misleading `0`.
- Watch lists: a name Instahyre does not know is reported and skipped; the rest of the list still runs. Companies with no matching open role are named in the log and the `SUMMARY` record.
- A valid filter that matches nothing succeeds with one explanatory `SUMMARY` row; a rejected value (e.g. an unknown city) fails with the same explanation. `SUMMARY` rows are never billed.
- Rate limits: an HTTP 429 pauses every worker (5, 15, 30, then 60 s) and slows the rest of the run; network resets are retried on their own counter.
- Large result sets: every part of a scan stays inside Instahyre's 10,000-result window; a part that cannot be split further is read up to the window and flagged in the log instead of failing the run. A pick that mixes whole categories with single functions is checked with one combined function query, so it cannot come back falsely empty.
- Privacy: recruiter name, designation and profile fields never reach the dataset — the default path never requests them, and detail records (`includeDescriptions`) are reduced on arrival to description, experience, category, functions and the internship/active flags.

# Changelog

This Actor's version history is a separate document: https://apify.com/foxlabs/india-tech-hiring-signals/changelog.md

# Actor input Schema

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

**Companies** gives one row per employer with hiring velocity (open roles, new roles in the last 7 days and in your window, function and skill mix, headcount, founded year). **Jobs** gives one row per listing — title, company, locations, skills, posting date, public URL — with no recruiter data.

## `locations` (type: `array`):

City names as Instahyre spells them: `Bangalore`, `Gurgaon`, `Hyderabad`, `Pune`, `Mumbai`, `Chennai`, `Noida`, `Delhi`, `Work From Home`. Several locations are combined with OR. Leave empty for all of India.

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

Pick whole categories (e.g. *Software Engineering — all functions*) or single functions (e.g. *Backend Development*). Several picks are combined with OR. Leave empty for every function — companies rows then report the mix at category level.

## `skills` (type: `array`):

Skill tags as they appear on listings: `Python`, `React.js`, `Machine Learning`, `Kubernetes`. Matched against the job's skill tags; case does not matter.

## `companies` (type: `array`):

Employer names as shown on Instahyre, e.g. `Razorpay`, `Zepto`. Use this to track the hiring velocity of a fixed set of companies. Case does not matter.

## `companySize` (type: `string`):

Instahyre's own size buckets: small = up to 50 employees, medium = 50–200, large = 200 and more.

## `industryTypes` (type: `array`):

Employer industry, as classified by Instahyre. Several picks are combined with OR.

## `experienceYears` (type: `integer`):

Keep only roles whose required experience range covers this many years — `3` returns roles asking for e.g. 2–5 years. Instahyre filters on a single value, not a range. Leave empty for all levels.

## `weeksWindow` (type: `integer`):

How many weeks back count as "new" for `newJobsInWindow`. 1–8 weeks. `newJobsLast7Days` is always reported as well.

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

Companies mode: how many employer rows to emit (the best-velocity ones first). Jobs mode: how many listings. `0` = no limit. Companies mode always scans the whole filtered job set so the counts are complete; this only caps the output.

## `includeDescriptions` (type: `boolean`):

Jobs mode only. Fetches each listing's detail record for the plain-text description, required experience (min/max years) and exact functions. One extra request per job; recruiter fields in that record are discarded on read and never stored.

## `requestDelayMs` (type: `integer`):

Pause after every request, per worker. 600 ms is polite. When Instahyre answers HTTP 429 (rate limit) every worker pauses — 5 s, 15 s, 30 s, then 60 s — before retrying, and the rest of the run slows down (+0.5 s per request, doubling on each further 429, at most +4 s). The run summary counts those pauses.

## `maxConcurrency` (type: `integer`):

How many requests run at once. Keep it at 2 unless you have a reason.

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

Apify Proxy, automatic group, is on by default; a residential proxy is not required. If Instahyre answers with a Cloudflare challenge, the log says so and the run keeps everything it could read.

## Actor input object example

```json
{
  "mode": "companies",
  "locations": [
    "Bangalore"
  ],
  "jobFunctions": [
    "category:software-engineering"
  ],
  "companySize": "medium",
  "weeksWindow": 4,
  "maxResults": 200,
  "includeDescriptions": false,
  "requestDelayMs": 600,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "locations": [
        "Bangalore"
    ],
    "jobFunctions": [
        "category:software-engineering"
    ],
    "companySize": "medium",
    "maxResults": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("foxlabs/india-tech-hiring-signals").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 = {
    "locations": ["Bangalore"],
    "jobFunctions": ["category:software-engineering"],
    "companySize": "medium",
    "maxResults": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("foxlabs/india-tech-hiring-signals").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 '{
  "locations": [
    "Bangalore"
  ],
  "jobFunctions": [
    "category:software-engineering"
  ],
  "companySize": "medium",
  "maxResults": 200
}' |
apify call foxlabs/india-tech-hiring-signals --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,foxlabs/india-tech-hiring-signals"
        }
    }
}
```

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/Agpy31WujZFWCsPnE/builds/UIiXads4SvrPkSKZ9/openapi.json
