# CutShort Jobs Scraper (`khadinakbar/cutshort-jobs-scraper`) Actor

Scrape public CutShort.io India tech jobs by keyword, location, skills, experience, or CutShort hub/job URLs. Returns title, company, salary, skills, experience, location, posted date, and description. Cookieless HTTP JSON, MCP-ready.

- **URL**: https://apify.com/khadinakbar/cutshort-jobs-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (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 $4.00 / 1,000 job scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## CutShort Jobs Scraper

Extract **public CutShort.io India tech jobs** by keyword, city, skills, experience band, or CutShort hub/job URL. Each row includes title, company, location, experience, public salary when shown, skills, employment type, remote policy, posted date, and optional description.

Built for recruiters, talent-market researchers, and AI agents that need structured CutShort data without a CutShort login.

### Best fit

- You want India-focused tech/startup roles from [CutShort](https://cutshort.io) hubs such as `frontend-developer-jobs` or `python-jobs`
- You already have CutShort `/jobs/...` or `/job/...` URLs
- You need MCP/API-friendly JSON with honest empty and failure outcomes

### Not a fit

- Login-only candidate search, messaging, or apply workflows
- Guaranteed free-text search across every private CutShort job (public hub pages are the source of truth)
- Non-CutShort boards (use sibling Actors such as Naukri or Indeed scrapers)

### How it works

1. Resolves keywords/skills/location into public CutShort hub slugs, or uses your `startUrls`
2. Reads CutShort's public webpage JSON:
   - `GET /backend-api/webpage/jobs/{slug}?page=N`
   - `GET /backend-api/webpage/job/{slug}`
3. Validates, deduplicates, optionally enriches details, then charges **after** a successful `Actor.charge` + `pushData` write

No browser is required for the supported public routes.

### Input example

```json
{
  "keywords": ["frontend developer"],
  "location": "bangalore",
  "maxJobs": 10,
  "maxPagesPerHub": 1,
  "enrichDetails": true
}
```

URL mode:

```json
{
  "startUrls": ["https://cutshort.io/jobs/python-jobs"],
  "maxJobs": 20,
  "enrichDetails": false
}
```

### Output fields (selected)

| Field | Description |
|---|---|
| `title` / `companyName` / `jobUrl` | Core job identity |
| `location` / `locations` / `isRemote` | Location + remote flag |
| `experience` / `experienceMin` / `experienceMax` | Public experience band |
| `salaryText` / `salaryMin` / `salaryMax` | Public salary when CutShort shows it |
| `skills` / `employmentTypes` | Tags and role types |
| `postedAt` / `descriptionText` | Freshness + detail when enrichment is on |
| `sourceApiUrl` / `scrapedAt` | Provenance |

### Pricing

Pay per event + platform usage pass-through:

- `apify-actor-start`: **$0.00005**
- `job-scraped`: **$0.004** per validated dataset row

Invalid input and truthful zero-match runs are not billed for `job-scraped`. See the Actor **Pricing** tab for the live schedule.

### Outcomes

Every run writes `OUTPUT` + `RUN_SUMMARY` with one of:

`COMPLETE` | `PARTIAL` | `VALID_EMPTY` | `INVALID_INPUT` | `UPSTREAM_FAILED` | `CONFIG_ERROR`

### API example

```bash
curl "https://api.apify.com/v2/acts/khadinakbar~cutshort-jobs-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords":["python"],"maxJobs":5,"enrichDetails":false}'
```

### MCP / agent prompt card

> Use CutShort Jobs Scraper to fetch public India tech jobs for keyword "backend developer" in Bangalore, return at most 15 rows with title, company, salaryText, skills, and jobUrl. Prefer startUrls when I already have a cutshort.io/jobs hub link.

### Tips for best results

- Prefer exact hub URLs from CutShort when you know them
- Keep `maxPagesPerHub` small for canaries; raise it for deeper hub crawls
- Set `enrichDetails: false` when you only need listing-card fields
- Use `remoteOnly` / experience filters to reduce billed rows

### Builder's note

CutShort serves hub and detail data through public `/backend-api/webpage/...` JSON. That path is cookieless and paginates about 50 jobs per page. Free-text `/search-jobs` demo endpoints are not a reliable unauthenticated source, so this Actor resolves keywords onto public hubs (with a bounded category-catalog fallback) instead of fabricating search results.

### Portfolio neighbors

- [Naukri Jobs Scraper](https://apify.com/khadinakbar/naukri-jobs-scraper) — broader India jobs board coverage
- [Indeed Job Scraper](https://apify.com/khadinakbar/indeed-job-scraper) — multi-market Indeed listings
- [Ashby Jobs Scraper](https://apify.com/khadinakbar/ashby-jobs-scraper) — public ATS board postings

### Legal / responsible use

This Actor collects **publicly visible** CutShort job pages only. You are responsible for complying with CutShort terms, applicable employment/privacy laws, and your own outreach policies. Not affiliated with CutShort.

### Changelog

See `CLAUDE.md` for build notes and release evidence.

# Actor input Schema

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

Enter job-title or category keywords such as frontend developer or python. The Actor maps them to public CutShort hub pages (for example frontend-developer-jobs). Prefer known hubs when possible. This is not a login-gated free-text search across every private job.

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

Optional skill keywords such as golang or devops. Each skill is resolved to a public CutShort hub when one exists (for example python-jobs). Leave empty when keywords or startUrls already define the search.

## `location` (type: `string`):

Optional India city or region such as bangalore, pune, hyderabad, or delhi. Combined with keywords into hub slugs like frontend-developer-jobs-in-bangalore-bengaluru. Leave blank for India-wide hubs. This does not geocode arbitrary addresses.

## `startUrls` (type: `array`):

Paste public cutshort.io /jobs/{hub-slug} or /job/{job-slug} URLs. Explicit URLs are processed first and skip keyword resolution. Non-CutShort URLs are rejected as invalid input.

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

Caps validated job rows written and billed for this run. Defaults to 50. Accepts 1 through 500. This is a global output cap across every hub, not a page count.

## `maxPagesPerHub` (type: `integer`):

Maximum CutShort hub API pages to fetch per resolved hub (about 50 jobs per page). Defaults to 3. Accepts 1 through 20. Stop early when a page returns fewer than 50 jobs.

## `minExperience` (type: `integer`):

Optional client-side filter keeping jobs whose public experience band can include at least this many years. Leave blank to keep all experience bands.

## `maxExperience` (type: `integer`):

Optional client-side filter keeping jobs whose public minimum experience is at most this many years. Leave blank to keep all experience bands.

## `remoteOnly` (type: `boolean`):

When true, keep only jobs CutShort marks with a remote remoteType. Defaults to false. Does not infer remote eligibility from description text alone.

## `enrichDetails` (type: `boolean`):

When true (default), fetch each job detail endpoint for fuller description and posted-date fields. When false, return listing-card fields only for faster cheaper runs.

## `useApifyProxy` (type: `boolean`):

Reserved for future blocked routes. CutShort public webpage JSON currently works over direct HTTPS, so this flag does not change routing in v0.1.

## Actor input object example

```json
{
  "keywords": [
    "frontend developer",
    "python"
  ],
  "skills": [
    "python",
    "devops"
  ],
  "location": "bangalore",
  "startUrls": [
    "https://cutshort.io/jobs/frontend-developer-jobs"
  ],
  "maxJobs": 10,
  "maxPagesPerHub": 1,
  "minExperience": 2,
  "maxExperience": 8,
  "remoteOnly": true,
  "enrichDetails": true,
  "useApifyProxy": false
}
```

# Actor output Schema

## `jobs` (type: `string`):

Validated public CutShort job records returned by this run.

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

Compact outcome, item counts, warnings, and charged event totals.

## `runSummary` (type: `string`):

Detailed hub coverage, diagnostics, and billing information for this run.

# 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 = {
    "keywords": [
        "frontend developer"
    ],
    "maxJobs": 10,
    "maxPagesPerHub": 1,
    "remoteOnly": false,
    "enrichDetails": true,
    "useApifyProxy": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/cutshort-jobs-scraper").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 = {
    "keywords": ["frontend developer"],
    "maxJobs": 10,
    "maxPagesPerHub": 1,
    "remoteOnly": False,
    "enrichDetails": True,
    "useApifyProxy": False,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/cutshort-jobs-scraper").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 '{
  "keywords": [
    "frontend developer"
  ],
  "maxJobs": 10,
  "maxPagesPerHub": 1,
  "remoteOnly": false,
  "enrichDetails": true,
  "useApifyProxy": false
}' |
apify call khadinakbar/cutshort-jobs-scraper --silent --output-dataset

```

## MCP server setup

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

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/hZonXJdg8XAS7lKTV/builds/0xznKBVcgZxSZ8XLw/openapi.json
