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.
0.1.12 — 2026-11-03 — Resume after a platform restart (no duplicate rows, no double charge)
A run the platform migrates, reboots or resurrects now continues instead of re-emitting every company (or job) it already delivered — no duplicate row and no second charge for the same record.
No change to output, input or pricing. A run that is never restarted behaves exactly as before.
0.1.10 — 2026-10-25 — real posting dates: the velocity now comes from the job pages and from our own baseline
Shipped as 0.1.10. Builds 0.1.5 to 0.1.9 were steps of the same fix — the sitemap format, the
posting-date source, the page budget, the default maxResults and the charging threshold — and are
described together below.
Instahyre's sitemap stopped carrying posting dates, so the velocity this actor is bought for was
silently null (run LQHO8lwOnrUz6CpJp charged 10 rows with every velocity field empty). It is
back, on a better source than before.
What was measured first
sitemap-jobs.xml?p=N, the file this actor read, now answers HTTP 404; Instahyre publishes
sitemap-jobs-1.xml.gz … sitemap-jobs-16.xml.gz (gzip, no content-encoding).
Reading the new file is not enough: it no longer dates anything. Every page carries only the
last 14 dates — page 1 (job ids 14–36,069, years old) and page 16 (ids 432,195–447,950, this
week) both span 2026-10-11 … 2026-10-24. Using it made newJobsInWindow equal activeJobs for
10 of 10 companies (run FCoy5I1GTHLotTMqo: Accenture 146/146, Amazon 87/87) where this actor
once reported 13 of 28. A confident wrong number is worse than an empty one.
The job page itself carries the truth: "datePosted":"2026-10-19" in its JSON-LD (~135 KB).
What the actor does now
Ground truth, bought once. The posting date is read from the job page and cached for ever
in a named key-value store (instahyre-job-dates). A run spends at most 250 page reads, on the
companies it is about to deliver, newest listing first — so the same job is never paid for twice
and repeat runs get their dates for free.
Our own first-seen baseline. Every run records the day it first saw each job id. That series
is free (the ids come from the scan already being done), it is ours, and it grows into the most
reliable hiring signal available for this board.
A job that was already listed when the baseline started keeps no date. Its age is genuinely
unknown, and guessing it is what inflated the counts. Such rows report datedJobs, undatedJobs
and velocityBasis so the coverage is visible.
A company with no dated job gets null, never 0. "No new roles" is a claim; null is the
honest answer when every date is unknown.
Rows without velocity are not charged. Charging is per row now: company-signal is only
charged when newJobsInWindow is a real number. The summary reports charged and freeRows.
New row fields: datedJobs, velocityBasis (posted | first-seen | null). Nothing was
removed or renamed.
The sitemap path is kept behind DATES_FROM_SITEMAP and still has to pass a refresh-stamp
check, so it can come back the day Instahyre dates its sitemap again — without being trusted
blindly.
Every run says up front what it will do and what it can cost:maxResults caps the
delivered rows, not the scan (measured: 4,369 jobs, 254 requests, 226 s for a 10-row request).
First tests for this actor (npm test used to print "no tests"): 5/5 — sitemap shapes, the
refresh-stamp check, the first-seen/posted precedence with baseline-day jobs staying undated,
the fetch budget, and the JSON-LD reader.
The page-read budget scales with what a run can earn (min(250, maxResults × 8), at least 20):
measured on run MrVIXgIJoA08Ut9VF, 250 reads cost about 170 s of a 377 s run while the three rows
it could date earned less than the run cost. The cache means each run spends its budget on jobs it
has not dated before, so coverage grows instead of being re-bought.
Honest about the economics: a 10-row companies request is below break-even because the scan is a
fixed cost (4,369 jobs, 226 s) — at 200 rows the same scan costs $0.0124 against $1.28 of rows.
The default maxResults is 200, not 500, and a companies run that asks for fewer than 50 rows
without a watch list now says that the scan costs the same either way and points at the cheaper
ways (more rows, a narrower filter, or a companies watch list). Measured: a 10-row request
leaves +16% margin while the same scan serves 200 rows at ~99%. The README leads with that too.
The page budget is spent breadth first. Measured on run IuvvPxfKY5Tbw9Eu7: spending all 250
reads on the biggest employers dated 7 of 200 rows and 193 went out free. The same budget now gives
every candidate company a sample of up to 5 listings before it deepens the largest ones, so far more
rows can report a real velocity from the same spend.
A row is charged only when its date sample is a signal: at least three dated listings, or every
listing dated. One dated listing out of 146 is not a hiring velocity, so such a row goes out free
with datedJobs/undatedJobs showing the coverage.
Prices unchanged.
0.1.4 — 2026-10-08 — README: the Python example works with the current Apify client
The README's Python example read the results with run['defaultDatasetId']. With the current Apify client for Python (version 3) call() returns a run object, not a dict, and that line raised TypeError: 'Run' object is not subscriptable — after the run itself had finished. The example now reads run.default_dataset_id; with client version 1 or 2, keep run['defaultDatasetId']. Checked with apify-client 3.2.1, 2.5.1 and 1.12.2.
No code, output field or pricing change.
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.
agencyFlag is a narrow heuristic: true only when the employer describes itself as a staffing or recruitment business.
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.