# Greenhouse, Lever & Ashby Jobs Scraper + Tech Stack Signals (`anywhere-web-repair/tech-stack-hiring-monitor`) Actor

Detect technology-stack shifts at target companies from their public Greenhouse, Lever and Ashby job boards. Emerging, rising and fading stacks on the first run; diffs on every run after.

- **URL**: https://apify.com/anywhere-web-repair/tech-stack-hiring-monitor.md
- **Developed by:** [Jeremy](https://apify.com/anywhere-web-repair) (community)
- **Categories:** Jobs, Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 company profiles

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

## Tech Stack Hiring Signals Monitor: Greenhouse, Lever & Ashby

Find out **what technologies a company is hiring for right now, and how that differs from what it was hiring for before.** Point the Actor at a list of companies and it reads their public job boards, classifies every open posting by technology stack, and tells you which stacks are **emerging**, **rising** or **fading**: on the very first run. Schedule it and it also reports every posting opened or closed and every stack-count change since the previous run.

No login, no cookies, no LinkedIn. It uses the free public job-board APIs that companies on **Greenhouse**, **Lever** and **Ashby** expose on purpose.

### Who this is for

- **SaaS and dev-tool sales teams**: a company that starts hiring React engineers after years of Angular postings, or posts three "LLM engineer" roles in a month, is a buying signal. Get it before the competition.
- **Recruiters and staffing agencies**: see which stacks are heating up at target accounts before the reqs hit LinkedIn.
- **Competitive and market intelligence**: track a portfolio of competitors' technology bets over time.
- **Investors and analysts**: hiring shifts are a leading indicator of product direction.

### What you get

One row per company:

| Field | Meaning |
|---|---|
| `alerts` | Actionable findings above your threshold: `emerging` (stack appears in recent postings, none in older ones), `rising` (recent share ≥ 2× older share), `fading` (present in older postings, absent from recent), and after the first run `new-since-last-run` / `gone-since-last-run`. Each has a `level` (high/medium) and a plain-English `detail`. |
| `counts` | Open postings total, how many are recent vs older, how many are undated. |
| `stacks` | Every detected technology with total / recent / older counts and how many times it appears in a job **title** (a much stronger signal than a mention in the body). |
| `topRecentStacks`, `titleStacks` | Quick-glance summaries. |
| `openedSincePrevious`, `closedSincePrevious`, `stackDeltasSincePrevious` | Changes since the last run of this Actor for the same company. |
| `boardUrl`, `ats` | Where the data came from. |

Turn on **Include one row per posting** to also get every open posting with its detected stacks, age, department, location and URL.

The key-value store holds a `SUMMARY` record with the run totals and every alert in one place, handy for a Slack or email integration.

### How the analysis works

1. **Resolve the board.** A bare slug (`stripe`) is probed on Greenhouse, then Lever, then Ashby. A board URL (`boards.greenhouse.io/<slug>`, `jobs.lever.co/<slug>`, `jobs.ashbyhq.com/<slug>`) pins the ATS. Companies on other systems (Workday, iCIMS, SuccessFactors, LinkedIn-only) are reported as `not-found` and **are not charged**.
2. **Classify.** Every posting's title and description are matched against a built-in dictionary of ~55 technologies across frontend, languages, mobile, cloud, infrastructure, data, AI/ML, platforms and APIs, with the obvious traps handled ("Go to market" is not Go, "Reactive" is not React, "rust belt" is not Rust, Java is not JavaScript). Add your own keywords with **Extra stack keywords**.
3. **Split by age.** Every ATS publishes a posting date, so postings younger than the **Recent window** (default 90 days) form the "recent" set and older open postings form the baseline. That is what lets the Actor detect a shift on the first run, without waiting to accumulate history.
4. **Diff.** With **Compare with previous run** on (default), a compact snapshot per company is kept in a named key-value store, and each run reports what changed.

### Input

```json
{
  "companies": ["stripe", "https://jobs.lever.co/palantir", "https://jobs.ashbyhq.com/notion"],
  "recentDays": 90,
  "alertThreshold": 3,
  "extraStacks": ["Hasura", "Temporal"],
  "includePostingRows": false,
  "compareWithPreviousRun": true
}
```

An alert needs both `alertThreshold` postings *and* at least `minSharePercent` (default 3%) of the postings in its window, so a 600-posting board doesn't fire on 3 stray mentions while a 20-posting startup still does. Lower `alertThreshold` to 1 or 2 for tiny companies, or set `minSharePercent` to 0 to use the absolute threshold alone.

### Pricing

Pay per event: a small charge per **company analyzed** plus a per-run start fee. Companies that cannot be found, or whose board has no public postings, are reported for free. Set a max charge on the run and the Actor analyzes as many companies as that allows and tells you which were skipped.

### Limitations

- Coverage is limited to companies whose careers site runs on Greenhouse, Lever or Ashby. That is a large share of tech companies and startups, but not the Fortune 500 on Workday.
- The classifier counts mentions, not sentiment. A React posting that says "migrating away from Angular" still counts as one Angular mention. Title mentions (`titleStacks`) are the cleaner signal.
- Slugs are usually the company name but not always; if a company comes back `not-found`, open its careers page, find the board URL, and paste that instead.
- Only listed, public postings are visible. Confidential or internal reqs are not.

### Related

Built by [Anywhere Web Repair](https://anywherewebrepair.com). See also our [Website SEO Audit](https://apify.com/anywhere-web-repair/website-seo-audit), [EDGAR Filings Monitor](https://apify.com/anywhere-web-repair/edgar-filings-monitor) and [FDA Recalls & Enforcement Monitor](https://apify.com/anywhere-web-repair/fda-recalls-monitor).

# Actor input Schema

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

Company job-board slugs or URLs. Accepts a bare slug ("stripe", probed on Greenhouse, then Lever, then Ashby), or a board URL that pins the ATS: boards.greenhouse.io/<slug>, jobs.lever.co/<slug>, jobs.ashbyhq.com/<slug>. Companies on other ATSs (Workday, iCIMS, LinkedIn-only) are reported as not found and are not charged.

## `recentDays` (type: `integer`):

Postings published within this many days count as "recent"; older open postings form the baseline. Stack shifts are measured recent vs baseline.

## `alertThreshold` (type: `integer`):

Minimum number of postings behind a signal before it becomes an alert. Lower for small companies.

## `minSharePercent` (type: `integer`):

A signal must also involve at least this percentage of the postings in its window (recent postings for emerging/rising, older postings for fading). Keeps large boards from alerting on 3-of-400 mentions while a 20-posting startup still alerts on 3. Set 0 to use the absolute threshold only.

## `extraStacks` (type: `array`):

Additional technologies to track beyond the built-in dictionary of ~55 (frameworks, languages, clouds, data, AI, platforms). One keyword per line, matched case-insensitively on word boundaries.

## `includePostingRows` (type: `boolean`):

Also output every open posting with its detected stacks, age and URL. Off = one summary row per company only. Does not change the price.

## `compareWithPreviousRun` (type: `boolean`):

Keep a compact snapshot per company between runs and report postings opened/closed and stack-count changes since the last run. Schedule the actor to get a running monitor.

## `snapshotKeyPrefix` (type: `string`):

Optional. Use different prefixes to keep separate histories (e.g. one per client) in the shared snapshot store.

## Actor input object example

```json
{
  "companies": [
    "stripe",
    "https://jobs.lever.co/palantir",
    "https://jobs.ashbyhq.com/notion"
  ],
  "recentDays": 90,
  "alertThreshold": 3,
  "minSharePercent": 3,
  "extraStacks": [],
  "includePostingRows": false,
  "compareWithPreviousRun": true,
  "snapshotKeyPrefix": ""
}
```

# Actor output Schema

## `companies` (type: `string`):

One row per company with alerts, stack profile and changes since the previous run.

## `summary` (type: `string`):

Companies analyzed / not found / skipped and every alert, in one JSON object.

# 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 = {
    "companies": [
        "stripe",
        "https://jobs.lever.co/palantir",
        "https://jobs.ashbyhq.com/notion"
    ],
    "extraStacks": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("anywhere-web-repair/tech-stack-hiring-monitor").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 = {
    "companies": [
        "stripe",
        "https://jobs.lever.co/palantir",
        "https://jobs.ashbyhq.com/notion",
    ],
    "extraStacks": [],
}

# Run the Actor and wait for it to finish
run = client.actor("anywhere-web-repair/tech-stack-hiring-monitor").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 '{
  "companies": [
    "stripe",
    "https://jobs.lever.co/palantir",
    "https://jobs.ashbyhq.com/notion"
  ],
  "extraStacks": []
}' |
apify call anywhere-web-repair/tech-stack-hiring-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,anywhere-web-repair/tech-stack-hiring-monitor"
        }
    }
}
```

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/QY8ghPm0t5wOEzhmI/builds/ARqXGzE4T9wqFrL3L/openapi.json
