# SiteVerdict — Hiring Signal & Buying Intent Scorer (`siteverdict/siteverdict-hiring-signal-scorer`) Actor

Score companies by hiring momentum from official public ATS job-board APIs (Greenhouse, Lever, Ashby, Workable, SmartRecruiters): open roles, growth velocity, departments, tools named, and explained buying intent for CRM, data, cloud, security or AI. Monitoring + alerts.

- **URL**: https://apify.com/siteverdict/siteverdict-hiring-signal-scorer.md
- **Developed by:** [Aman Thakran](https://apify.com/siteverdict) (community)
- **Categories:** Lead generation, Jobs
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

## SiteVerdict — Hiring Signal & Buying Intent Scorer

**Know which accounts are spending right now. Paste company domains or names and get a 0–100 hiring score, growth velocity, the teams that are growing, the tools they name in job ads, and an explained "buying intent" score for CRM, data, cloud, security, AI or your own category — straight from the companies' own public job boards.**

No LinkedIn. No Indeed. No scraping of job sites. Only the official public job-board APIs that Greenhouse, Lever, Ashby, Workable and SmartRecruiters run for careers pages.

### Three ways teams use it

1. **Prioritise outbound.** Score 500 target accounts every Monday; work the "hot" ones first. Each row says *why* in plain English ("4 open roles mention Salesforce/HubSpot; 2 are dedicated hires: 'Salesforce Administrator', 'RevOps Manager'; 3 posted in the last 30 days").
2. **Catch the moment.** Monitor mode remembers last week's roles and tells you when an account opens a burst of new roles or hires its first Head of Data — with a Slack or webhook alert.
3. **Research a market.** Which fintechs are hiring security engineers? Which SaaS companies are building data teams on Snowflake vs BigQuery? The tools-mentioned table answers it.

### Before / after

**You give:**

```json
{ "companies": ["ramp.com", "greenhouse:discord", "https://jobs.lever.co/spotify", "Hugging Face"], "intentTopics": ["crm", "data-platform", "security", "ai-ml"] }
```

**You get (one row per company, trimmed):**

```json
{
  "company": "Discord",
  "hiringScore": 64, "hiringLevel": "hot",
  "openRoles": 49, "postedLast30Days": 17, "velocityLabel": "accelerating",
  "departments": [{ "department": "Engineering", "roles": 21, "share": 42.9 }, { "department": "Data & AI", "roles": 6, "share": 12.2 }],
  "leadershipRoles": 3,
  "toolsMentioned": [{ "tool": "Python", "roles": 9 }, { "tool": "Kubernetes", "roles": 4 }],
  "intent": [{ "topic": "ai-ml", "score": 81, "level": "high", "explanation": "Buying intent for AI / machine learning: HIGH (81/100). 9 open roles mention machine learning, llm ... 4 are dedicated hires ('Senior ML Engineer', ...)." }],
  "changes": { "newRoles": 6, "closedRoles": 3, "previousScore": 55, "scoreDelta": 9 },
  "alertTriggers": ["AI / machine learning intent 81 >= 70"],
  "highlights": ["49 open roles, mostly Engineering (21).", "Hiring is accelerating (17 new in 30 days vs 8 in the 60 days before)."]
}
```

(Numbers above illustrate the format; run sample mode to see the exact output on recorded real boards.)

### What is scored

| Signal | How |
|---|---|
| **Hiring score (0–100)** | volume (log-scaled open roles), velocity (roles posted in the last 30 days vs the 60 before), breadth (departments hiring), leadership hires (director/VP/C-level), and — in monitor mode — new roles since the last run. Weights are in the output (`scoreBreakdown`). |
| **Velocity** | `accelerating` / `steady` / `slowing` / `unknown` (when the board does not publish posting dates). |
| **Departments & seniority** | from job titles (sales engineers count as Sales, VPs as Executive, etc.) with the vendor department as a fallback. |
| **Tools mentioned** | 70+ tools (Salesforce, HubSpot, Snowflake, dbt, AWS, Kubernetes, Datadog, Okta, OpenAI…) matched as whole words; ambiguous names (React, Rust, Spark, SAP, Claude) only when written as names. |
| **Buying intent per topic** | dedicated hires (topic in the title) weigh 3×, passing mentions 1×, recent postings +25%; saturating 0–100 score with level, evidence (up to 5 roles) and a one-line explanation. 11 built-in topics + your own ("Video: Mux, transcoding"). |
| **Changes** | new/closed roles and score delta vs the previous run under the same monitor name. |
| **AI brief (optional)** | with YOUR Anthropic key: a 120-word sales brief per company (why now, growing teams, product fit, an opening line). |

### Input

| Field | Example |
|---|---|
| `companies` | `ramp.com`, `https://jobs.lever.co/spotify`, `greenhouse:discord`, `Hugging Face` |
| `intentTopics` | `crm`, `marketing-automation`, `data-platform`, `cloud-devops`, `security`, `ai-ml`, `customer-support`, `finance-erp`, `people-hr`, `payments`, `expansion` |
| `customIntentTopics` | `Video infrastructure: Mux, video streaming, transcoding` |
| `monitorStateName` + `onlyChanged` | weekly schedule that only returns (and only charges for) accounts that changed |
| `slackWebhookUrl` / `webhookUrl` | alert when hiring score ≥ 75, any intent ≥ 70, or ≥ 5 new roles (all configurable) |
| `enableAiBrief` + `anthropicApiKey` | optional AI brief on your own key |
| `sampleMode` | try it free on recorded real job boards |

### Output and exports

- Dataset views: **Hiring scores** (CSV/Excel friendly), **Buying intent (explained)**, **No board / errors**.
- `OUTPUT` record: run summary, leaderboard sorted by score, alert delivery status, charged events — an agent-ready JSON summary.

### Pricing (pay per event)

| Event | Price | When |
|---|---|---|
| `company-scored` | $0.02 | a company with a readable public job board was scored |
| `ai-explanation` | $0.01 | an AI brief was produced (your Anthropic usage is billed to your key) |

**Max cost per run: company data first.** Each requested company's `company-scored` charge is held back before anything else. An AI brief (only when `enableAiBrief` is on **and** you supplied your Anthropic key) is generated only if the budget left after holding one company charge per still-unprocessed company also covers the brief. Inputs that turn out free (no public board, errors, unchanged) release their hold as soon as they are checked, so briefs later in the run can use that money. If a brief cannot be covered, it is not generated (your Anthropic key is not used) and not charged. The company row is still delivered in full with `aiBrief: null`, `aiBriefStatus: "skipped_budget"` and an `aiBriefNote`, and OUTPUT shows `aiBriefsSkippedBudget`; the run is not reported as stopped. A failed AI call is never charged either (`aiBriefStatus: "error"`). Only when the budget cannot cover every company does the run stop (`stoppedAtChargeLimit: true`); each company it could not score gets a free `not-processed` row, so every requested company appears in the dataset.

Not charged: companies without a public board, errors, unchanged companies in `onlyChanged` mode, sample mode.
**Examples:** 100 accounts ≈ **$2.00**; a weekly monitor of 500 accounts where ~80 change ≈ **$1.60/week**; 100 accounts with AI briefs ≈ $3.00 + your Anthropic usage.

### FAQ

**Which companies work?** Any company whose careers page uses Greenhouse, Lever, Ashby, Workable or SmartRecruiters (very common for tech, SaaS, fintech, scale-ups). Companies on Workday, iCIMS, Taleo, SuccessFactors or their own systems return a free "no-board" row.

**How is the board found?** Direct identifiers/URLs are used as given. For domains we read the home and careers pages (robots.txt respected, max 5 pages) for a linked ATS board, then — if allowed — probe the ATS APIs with a slug from the domain or name. Probe matches say so in `discoveryNote`; check the company name.

**Is a high intent score proof of a purchase?** No. It means the company is hiring people who will use or own that category. Treat it as a reason to reach out, not a fact.

**Do you collect personal data?** No. We read job postings (organisational data). Recruiter names are never collected. The AI step sends only computed signals and job titles.

### Limits

- Only the five ATSs above. Unlisted/confidential roles are not visible.
- Posting dates are vendor-reported; some boards (e.g. Workable) publish fewer dates, which makes velocity `unknown`.
- SmartRecruiters descriptions need one detail call per posting (default max 25 per company).
- Website discovery skips pages blocked by robots.txt and never bypasses bot protection.

### Sources & compliance

- Greenhouse Job Board API (`boards-api.greenhouse.io`), Lever Postings API (`api.lever.co`), Ashby Posting API (`api.ashbyhq.com/posting-api`), Workable public jobs widget API (`apply.workable.com/api/v1/widget`), SmartRecruiters Posting API (`api.smartrecruiters.com/v1/companies/{id}/postings`). These are the public, unauthenticated endpoints the vendors document/provide for publishing a company's own job listings on its careers site. Terms/doc URLs checked 11 Oct 2026: developers.greenhouse.io/job-board.html, github.com/lever/postings-api, developers.ashbyhq.com/docs/public-job-posting-api, help.workable.com (jobs widget), developers.smartrecruiters.com/docs/posting-api.
- Company websites are read only to find the job-board link: honest User-Agent `SiteVerdict/hiring-signal-scorer (+hello@webrevenuescan.com)`, robots.txt respected, SSRF-guarded, low page limits.
- Never used: LinkedIn, Indeed, Glassdoor or any other job site.
- **UK GDPR / PECR:** output is organisational data about companies. If you use it for outreach, you are the controller: have a lawful basis (usually legitimate interests for B2B), respect PECR rules for electronic marketing to individuals and sole traders, and honour opt-outs.
- Disclaimer: hiring signals are inferences from public job ads, not facts about budgets or purchases. Not financial or investment advice.

Built by SiteVerdict (BharatFare Travel and Technologies Ltd, UK). Contact: hello@webrevenuescan.com.

# Changelog

This Actor's version history is a separate document: https://apify.com/siteverdict/siteverdict-hiring-signal-scorer/changelog.md

# Actor input Schema

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

One per line. Accepts a website domain (ramp.com), a job-board URL (https://jobs.lever.co/spotify, https://job-boards.greenhouse.io/discord), an identifier (greenhouse:discord, lever:spotify, ashby:ramp, workable:huggingface, smartrecruiters:ServiceNow) or a company name (Hugging Face - found by probing the ATS APIs).

## `intentTopics` (type: `array`):

Which product categories to score buying intent for. Each topic gets a 0-100 score, the evidence (job titles and terms) and a plain-English explanation.

## `customIntentTopics` (type: `array`):

Score intent for YOUR product category. One topic per line, e.g. "Video infrastructure: Mux, video streaming, transcoding". Keywords are matched as whole words in titles and descriptions.

## `discoverFromWebsite` (type: `boolean`):

For domains: read the home page and careers pages (max pages below, robots.txt respected) to find the linked Greenhouse/Lever/Ashby/Workable/SmartRecruiters board.

## `probeAtsApis` (type: `boolean`):

If no board is linked, try the official ATS APIs with a slug derived from the domain or name (one light request per ATS). Verify the company name in the result.

## `maxDiscoveryPages` (type: `integer`):

Max website pages per company (discovery).

## `maxJobsPerCompany` (type: `integer`):

Max postings read per company.

## `maxDetailCallsPerCompany` (type: `integer`):

SmartRecruiters lists postings without descriptions; this many postings get a detail call so tools and intent terms can be read. 0 = titles only.

## `includeTopRoles` (type: `integer`):

Newest roles to include per company.

## `monitorStateName` (type: `string`):

Each run remembers the roles it saw under this name (a named key-value store in your account) and reports new/closed roles and score changes next time. Use different names for different watch lists.

## `onlyChanged` (type: `boolean`):

Monitor mode for schedules: skip (and do not charge for) companies whose open roles did not change since the last run.

## `alertMinHiringScore` (type: `integer`):

Alert when hiring score is at least.

## `alertMinIntentScore` (type: `integer`):

Alert when any intent score is at least.

## `alertMinNewRoles` (type: `integer`):

Alert when this many new roles appeared since the last run (0 = off).

## `slackWebhookUrl` (type: `string`):

One Slack message per run listing companies that crossed a threshold. HTTPS only. Stored encrypted, never logged or written to output.

## `webhookUrl` (type: `string`):

HTTPS endpoint that receives a JSON summary of the alerts (Zapier, Make, n8n, your API). Private/internal addresses are refused. Stored encrypted, never logged.

## `enableAiBrief` (type: `boolean`):

Off by default. Sends only the computed signals and job titles (no personal data) to Anthropic with YOUR key and adds a 120-word brief: why now, growing teams, product fit, an opening line. Charged only when a brief is produced.

## `anthropicApiKey` (type: `string`):

Your own key from console.anthropic.com. Used only for the AI brief; stored encrypted by Apify, never logged or written to output.

## `aiModel` (type: `string`):

Anthropic model.

## `concurrency` (type: `integer`):

Companies in parallel.

## `sampleMode` (type: `boolean`):

Run on job boards recorded on 11 Oct 2026 (Discord, Ramp, Spotify, Hugging Face). No network calls, nothing charged.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:discord",
    "ramp.com",
    "https://jobs.lever.co/spotify"
  ],
  "intentTopics": [
    "crm",
    "data-platform",
    "cloud-devops",
    "security",
    "ai-ml"
  ],
  "discoverFromWebsite": true,
  "probeAtsApis": true,
  "maxDiscoveryPages": 5,
  "maxJobsPerCompany": 1000,
  "maxDetailCallsPerCompany": 25,
  "includeTopRoles": 10,
  "monitorStateName": "default",
  "onlyChanged": false,
  "alertMinHiringScore": 75,
  "alertMinIntentScore": 70,
  "alertMinNewRoles": 5,
  "enableAiBrief": false,
  "aiModel": "claude-sonnet-5-5",
  "concurrency": 3,
  "sampleMode": false
}
```

# Actor output Schema

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

No description

## `output` (type: `string`):

No description

## `files` (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 = {
    "companies": [
        "greenhouse:discord",
        "ramp.com",
        "https://jobs.lever.co/spotify"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("siteverdict/siteverdict-hiring-signal-scorer").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": [
        "greenhouse:discord",
        "ramp.com",
        "https://jobs.lever.co/spotify",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("siteverdict/siteverdict-hiring-signal-scorer").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": [
    "greenhouse:discord",
    "ramp.com",
    "https://jobs.lever.co/spotify"
  ]
}' |
apify call siteverdict/siteverdict-hiring-signal-scorer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,siteverdict/siteverdict-hiring-signal-scorer"
        }
    }
}
```

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/bMfgHILlCvdc395T1/builds/fchuFfrvboEgV25lp/openapi.json
