# Unstop Scraper API - Hackathons, Competitions & Jobs (`dami_studio/unstop-scraper`) Actor

Unstop's public API never rejects a filter value it doesn't know: ask for oppstatus=banana and you get all 6,110 hackathons, not the 111 that are open. This one allows only verified values. Hackathons, jobs, internships, scholarships, with organiser emails where given. $2.50/1k.

- **URL**: https://apify.com/dami\_studio/unstop-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Jobs, Lead generation, Other
- **Stats:** 3 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 opportunity returneds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Unstop Scraper API - hackathons, competitions, internships and jobs

[Unstop](https://unstop.com), the platform formerly called Dare2Compete, does not validate the
filters on its public API. Ask the hackathons board for `oppstatus=banana` and it answers HTTP 200
with all 6,110 hackathons rather than the 111 whose registration is open. Re-checked 2026-08-21. On
a pay-per-result actor that gap is a bill, so this one refuses any filter value outside an
allow-list verified against the live API.

It's one of India's main boards for student and early-career opportunities, and the live counts it
was carrying when this was measured are in the table below.

You get one row per opportunity: what it is, who's running it, who can enter, when registration
closes, what you can win or earn, how many people have already registered, whether it's online or
in a particular city, and the link.

Every field comes from Unstop's own public JSON API, so there's no login and no key to configure.

***

### What you get

Live counts measured on 8 August 2026, registration open:

| Board | Live now | Archive (expired) |
|---|---:|---:|
| Jobs | 1,170 | large |
| Internships | 861 | large |
| Competitions | 275 | large |
| Hackathons | 111 | 5,893 |
| Cultural events | 43 | |
| Workshops | 42 | |
| Quizzes | 38 | |
| Hiring challenges | 28 | |
| Conferences | 17 | |
| Scholarships | 6 | |

Two of those boards are supergroups, which is worth knowing before you pay for the same row twice:

- **Competitions (275)** also contains all 111 hackathons and all 38 quizzes.
- **all (377)** is Competitions plus workshops, conferences and cultural events. It does **not**
  contain jobs, internships or scholarships.
- **Hiring challenges (28)** is a tag rather than a board. Those rows are drawn from competitions,
  quizzes and hackathons.

Unstop labels both internships and jobs with the same raw `type` of `jobs` and only separates them
in `subtype`. Every row here also carries a plain `kind` field that sorts that out for you.

Three real rows from a run on 8 August 2026:

```
Precision Care Challenge 2026 | GE HealthCare | hackathon, online
  deadline 2026-08-26 (17 days left) | top prize INR 150,000 | 596 registered, 25,841 views
  teams of 1-4 | open to Undergraduate, Postgraduate, Engineering Students
  https://unstop.com/hackathons/crp-precision-care-challenge-2026-ge-healthcare-1731208

Evil Corp CTF V2 | Nexploit | hackathon, online
  deadline 2026-08-18 (9 days left) | prizes INR 1,000 / 500 / 200 + certificates
  35 registered | teams of 1-4 | skills: Digital Forensics, Ethical Hacking
  https://unstop.com/hackathons/evil-corp-ctf-v2-nexploit-1733381

Business Development Executive | job, work from home, full time
  salary INR 240,000-300,000 per year (published by the employer) | open to Freshers
  https://unstop.com/jobs/...
```

#### Every field on every row

**Identity** — `id`, `shortId`, `title`, `url`, `shortUrl`, `kind` (hackathon / competition /
quiz / internship / job / scholarship / workshop / conference / cultural-event), plus Unstop's own
raw `type` and `subtype`, `status`, `registrationOpen`

**Organiser** — `organiserName`, `organiserId`, `organiserUrl`, `organiserLogo`, and with
"Fetch the organiser's contact details" on: `organiserEmail`, `organiserPhone`,
`organiserContactName`

**Where** — `isOnline`, `locationMode` (online / offline), `rawRegion` (Unstop's own unreliable
value — see below), `locations[]` (a job can list several work cities and all of them are kept),
`city`, `state`, `country`, `countryCode`, `venue`

**When** — `registrationDeadline`, `registrationOpensAt`, `startDate`, `endDate`, `daysLeft`,
`deadlineText`, `postedAt`, `updatedAt`, `rounds[]`

**Prize money** — `prizes[]` (rank, cash, currency, certificate, pre-placement offer, other
rewards), `prizeTopCash`, `prizeTotalCash`, `prizeCurrency`, `hasCashPrize`, `prizeSummary`

**Pay** — `payMin`, `payMax`, `payCurrency`, `payPeriod` (monthly / annually), `payType`
(paid / unpaid), `payIsDisclosed`, `payIsEstimate`, `workMode`, `employmentType`,
`minExperienceYears`, `maxExperienceYears`

**Who can enter** — `eligibilityTags[]` (Unstop's own badges: Undergraduate, Postgraduate,
Engineering Students, Fresher, Experienced Professionals, School Students …),
`eligibilitySectors[]`, `eligibilityCourses[]`, `eligibilityExperience[]`,
`eligibilityPassoutYears[]`, `eligibilityRaw`, `eligibleCountries[]`, `minTeamSize`, `maxTeamSize`

**Interest** — `registrationCount`, `participantCount`, `viewsCount`

**Other** — `skills[]`, `workFunctions[]`, `categoryTags[]`, `hasEntryFee`, `festivalName`,
`trustedTag`, `logoUrl`, `descriptionText`, optional `descriptionHtml`

***

### About the pay figures, before you build on them

Unstop has no salary-estimation feature. A stipend or salary is either typed in by the organiser
or it is not there at all. **`payIsEstimate` is `false` on every single row**, and it always will
be, because there is nothing on the platform that guesses.

What is there, measured over 300 live rows per board on 8 August 2026:

Over all 861 live internships and 600 live jobs pulled in one run each:

| | Internships (861) | Jobs (600) |
|---|---:|---:|
| Row carries a published figure | 456 (53%) | 472 (79%) |
| Marked paid by the organiser | 630 (73%) | 599 (100%) |
| Explicitly unpaid | 231 (27%) | 1 (<1%) |
| Platform estimates | **0** | **0** |

`payIsDisclosed` tells you which bucket a row is in, so you never have to guess whether a `null`
means "free" or "they did not say".

Prize money on the competition boards is patchier, and the row says so. Over all 275 live rows on
the competitions board: 190 (69%) list prizes and 142 (52%) list a cash amount. The rest offer
certificates, goodies or pre-placement offers, which are captured too.

***

### The filter trap, and what this actor does about it

Unstop's API does not validate filter values. Send it something it does not recognise and it
answers **HTTP 200 with the entire unfiltered archive**. Measured:

| Request | Rows returned |
|---|---:|
| `oppstatus=open` | 111 hackathons ✅ |
| `oppstatus=banana` | 6,047 hackathons ❌ |
| `oppstatus=open,closed` | 6,047 hackathons ❌ (commas are not multi-value) |
| `category=finance` | 11 competitions ✅ |
| `category=case-study` | 275 competitions ❌ |
| `paid_unpaid=maybe` | 630 internships ❌ (identical to `paid_unpaid=paid`) |

On a pay-per-result actor that is a bill for thousands of rows nobody asked for.

So: 150+ plausible domain slugs were tested against the live API. **Exactly 17 filter anything.**
Those 17 are the whole dropdown. Anything outside the verified vocabulary is refused before a
request goes out, and you get an uncharged diagnostic row telling you which value was dropped and
why.

One filter is missing from Unstop entirely: **there is no working server-side city filter.**
`location=Pune` is accepted and silently ignored, in every spelling and on every board. This actor
therefore filters cities client-side after the rows arrive. **Rows dropped that way are never
charged for.**

***

### Two Unstop quirks this actor corrects for you

**Unstop marks every job and internship as "online", even when it has an office and a city.**
Measured: 400 out of 400 in-office jobs carried `region: "online"`. So `isOnline` here is derived
from the actual work mode for those boards, and Unstop's raw value is kept beside it as
`rawRegion` if you want to see it.

**The city lives in two different places depending on the board.** Jobs and internships put one
entry per work city in `locations[]` and leave the venue block blank; competitions and events do
the opposite. Read only one and you lose the city on half the catalogue. Both are read here, and
`locations[]` keeps every city on a multi-city job. Measured on 400 live in-office jobs: a city on
398 of them.

***

### Limits, honestly

- **10,000 results per search.** Unstop's `total` saturates at 10,000, and asking for a page past
  the 10,000th row returns HTTP 500. Split a big pull by domain, status or keyword.
- **`all` is not everything.** Unstop's own "all" feed is a mixed stream of competitions,
  hackathons, quizzes, workshops, conferences and cultural events, 377 live. It does **not**
  include jobs, internships or scholarships. Select those explicitly.
- **Skill names are case sensitive.** `Python` returned 93 live jobs; `python` returned 0.
- **Short links are not supported.** `unstop.com/o/PGTJBPX` carries no numeric id.
- **India-centric.** Every in-person opportunity in the sample was in India. `eligibleCountries`
  was empty on all 40 detail pages checked, so international eligibility is generally not declared.
- **Organiser contacts are board-dependent** — 81% of competition rows carry an email, but only
  1-2% of job and internship rows do. See the FAQ for the full table.
- **`teamSize` and `entryFee` do nothing on jobs and internships** — they belong to the competition
  boards, and Unstop returns zero rows rather than ignoring them.

***

### What this does not do

- It does not log in, so anything behind an Unstop account — your applications, saved items,
  private college-only listings — is out of reach.
- It does not register you for anything, submit anything, or apply on your behalf.
- It does not scrape mentor profiles, blog posts, courses or the practice-question bank. Those live
  on different endpoints.
- It does not download attachments, banners or certificates.
- It does not resolve `unstop.com/o/XXXX` short links.
- It cannot reach past the 10,000th result of a single search. That's a server limit, not a choice.

***

### Speed and cost

Unstop's API is fast and open. Measured on 8 August 2026 from an Apify container:

- 24-72 ms per listing request from the plain container address; 600-2,000 ms through a proxy.
- Identical results (same `total`, same ids, same order) from three different network addresses.
- 40 consecutive requests from one address: 40 out of 40 succeeded, no throttling, no captcha.
- 40 detail pages at concurrency 8: 4.0 seconds.

So the default route is the plain container address, with a proxy held in reserve for retries.
No residential proxy is ever used.

#### Billing

**$2.50 per 1,000 opportunities**, plus a $0.002 start fee per run. One charge per opportunity row
you receive. Sample rows, diagnostics, failed requests and rows dropped by the city filter are all
free, and a run that finds nothing costs the start fee alone.

`maxItems` is a hard cap across every board and keyword in the run, so it doubles as your spending
limit.

***

### FAQ

**What is Unstop?**
Unstop, formerly Dare2Compete, is an Indian platform where companies and colleges post hackathons,
case competitions, quizzes, cultural fests, scholarships, internships and jobs aimed at students
and early-career professionals. On the hackathon board alone it was carrying 111 live listings and
5,893 expired ones on 8 August 2026.

**Does this scraper need an Unstop account or API key?**
No. Everything comes from Unstop's public JSON API, which needs no key, no cookie and no login.

**Can I get the organiser's email address?**
On the competition boards, usually. It depends heavily on the board, so here are the real numbers
from full runs on 8 August 2026, with "Fetch the organiser's contact details" on:

| Board | Rows | With an email | With a phone |
|---|---:|---:|---:|
| Competitions / hackathons / quizzes | 275 | 222 (81%) | 118 (43%) |
| Jobs | 600 | 10 (2%) | 5 (1%) |
| Internships | 861 | 10 (1%) | 4 (<1%) |

Employers posting jobs almost never publish a contact; event organisers almost always do. If you
are after contacts, run the competition boards.

**Can I scrape expired hackathons and competitions?**
Yes. Set "Registration status" to Expired. The archive is much larger than the live board: 5,893
expired hackathons against 111 live ones.

**How do I get only in-person events in a specific city?**
Set "Online or in person" to *In person only* and put the city names in "City". Unstop has no
working server-side city filter, so the city match happens after the rows arrive; rows that do not
match are dropped and are not charged for.

**How many results can I get in one run?**
Up to 10,000 per individual search. Run several boards, statuses or keywords in one go and each
gets its own 10,000-row window.

**Does it return prize money?**
Yes, when the organiser published it: each prize rank with its cash amount and currency, plus
`prizeTopCash` and `prizeTotalCash`. About half of live competitions and hackathons list a cash
figure; the rest offer certificates, goodies or pre-placement offers, which are also captured.

**Are the salary figures estimates?**
No. Unstop has no estimation feature. Every figure was typed in by the organiser, and
`payIsEstimate` is `false` on every row. `payIsDisclosed` tells you whether a figure exists at all.

**Is it charged when a run finds nothing?**
No. Sample rows, diagnostics, failed requests and rows dropped by the city filter are all
uncharged. You pay only for genuine opportunity rows.

**Can I paste a single Unstop link?**
Yes. Put the full URL, or just the numeric id at the end of it, into "Opportunity URLs".

**How much does it cost?**
$2.50 per 1,000 opportunities, plus a $0.002 start fee per run. Nothing is charged for sample rows,
diagnostics, failed requests or rows dropped by the city filter.

**How do I keep costs down?**
Set "Maximum results". It's a hard cap across every board and keyword in the run.

# Actor input Schema

## `listing` (type: `array`):

Unstop's opportunity boards. Live counts measured on 2026-08-08: jobs 1,170 · internships 861 · competitions 275 · hackathons 111 · cultural events 43 · workshops 42 · quizzes 38 · hiring challenges 28 · conferences 17 · scholarships 6. Two boards are supergroups: 'Competitions' (275) also carries all 111 hackathons and all 38 quizzes, and 'all' (377) is Competitions plus workshops, conferences and cultural events — it does NOT include jobs, internships or scholarships. Pick several and each is walked in turn; every row carries a plain 'kind' field (hackathon, competition, quiz, internship, job, scholarship, workshop, conference, cultural-event) so duplicates are easy to see.

## `searchQueries` (type: `array`):

Free-text searches, exactly as you would type them into Unstop's search box: a topic ("machine learning"), a technology ("blockchain"), or an organiser ("Flipkart"). Each keyword is run separately against every board you selected. Leave empty to take everything that matches the filters below.

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

Paste full Unstop opportunity URLs, for example https://unstop.com/hackathons/evil-corp-ctf-v2-1733381, or just the numeric id (1733381). Each is fetched directly with full detail, including the organiser's contact email. Short unstop.com/o/XXXX links do not carry the id and are not supported.

## `status` (type: `string`):

Live = registration is open right now. Expired = the deadline has passed (that archive is large: 5,893 hackathons against 111 live). Closed = the organiser closed registration early. Anything else is refused, because Unstop answers HTTP 200 with the ENTIRE archive for a status it does not recognise.

## `category` (type: `string`):

Unstop's domain taxonomy. These 17 values are the complete verified set: 150+ other plausible slugs ("marketing", "data-science", "case-study", "web-development") were tested against the live API and every one of them is silently ignored, returning the whole unfiltered corpus. Only the values in this list actually filter anything.

## `region` (type: `string`):

Online events run remotely; offline events have a venue and fill in city, state and country. Measured on 2026-08-08: 106 of the 275 live competitions are offline, held in cities such as Pune, Indore and Guwahati.

## `cities` (type: `array`):

Indian cities such as "Pune", "Delhi", "Bangalore", "Mumbai". Matched against each row's city and state. Unstop has no working server-side city filter — location=<city> is accepted and then silently ignored — so this is applied here after the rows arrive, and rows dropped by it are NEVER charged for. Best combined with "In person only".

## `workMode` (type: `string`):

How the role is worked. Measured on 2026-08-08 across 861 live internships: 441 work-from-home. Ignored on competition-style boards.

## `employmentType` (type: `string`):

Full time, part time or contract. Measured on 2026-08-08 across 1,170 live jobs: 1,152 full time, 5 part time.

## `paidOnly` (type: `string`):

Measured on 2026-08-08: 630 of 861 live internships are paid, the rest are explicitly unpaid. Careful — Unstop treats any value it does not recognise as "paid", so only these two are allowed through.

## `workingDays` (type: `string`):

Measured on 2026-08-08: 799 of 1,170 live jobs are 5 days a week.

## `eligibleFor` (type: `string`):

Unstop's own eligibility buckets. Measured on 2026-08-08 across 861 live internships: 515 are open to freshers. Across 1,170 live jobs: 992 to working professionals, 32 to college students.

## `postedWithinDays` (type: `string`):

Only opportunities published in the last N days. Measured on 2026-08-08: 512 of 861 live internships were posted in the past week.

## `teamSize` (type: `string`):

Solo entries, pairs, or teams of three and up. Only meaningful on competition-style boards; on jobs it returns nothing.

## `entryFee` (type: `string`):

Free to enter, or a paid entry. Only meaningful on competition-style boards.

## `skill` (type: `string`):

One skill tag, spelled the way Unstop spells it — this one IS case sensitive. "Python" returned 93 live jobs on 2026-08-08; "python" returned 0.

## `sortBy` (type: `string`):

Newest first is Unstop's default. Prize money and stipend/salary sort by the published figure; opportunities with no figure sink to the bottom.

## `sortDirection` (type: `string`):

Which end of the sort to start from. Only used when "Sort by" is set.

## `maxItems` (type: `integer`):

Stop after this many opportunities across every board and keyword. You are charged per opportunity returned, so this is your spending cap. Unstop lets any single search reach its first 10,000 results; past that, split the run with a domain, a status or a keyword.

## `includeDetails` (type: `boolean`):

Reads each opportunity's own page for the organiser's contact email and phone, the round schedule, the start date and the live participant count. Measured over 40 live opportunities on 2026-08-08: an email on 30, a phone number on 18, a round schedule on 25, a participant count on 40. It costs one extra request per row (about 100 ms) and nothing extra in money. Turn it off for the fastest possible listing-only run.

## `includeDescriptionHtml` (type: `boolean`):

Every row already carries descriptionText, the plain-text version. Switch this on to also keep descriptionHtml, the organiser's original markup. It makes the dataset roughly three times larger.

## `detailConcurrency` (type: `integer`):

How many opportunity pages to read at once when "Fetch the organiser's contact details" is on. 8 measured 40 pages in 4.0 seconds with no throttling.

## `egressMode` (type: `string`):

Unstop's API is open, fast and unmetered from anywhere: 24-72 ms from the plain container address against 600-2,000 ms through a proxy, and identical results from three different addresses. Leave this on Automatic unless you have a reason not to.

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

Optional. Supply your own proxy URLs here and they are used for every request instead of the routes above.

## Actor input object example

```json
{
  "listing": [
    "hackathons",
    "competitions"
  ],
  "searchQueries": [
    "machine learning",
    "fintech"
  ],
  "startUrls": [
    "https://unstop.com/hackathons/evil-corp-ctf-v2-1733381"
  ],
  "status": "open",
  "category": "",
  "region": "",
  "cities": [
    "Pune",
    "Bangalore"
  ],
  "workMode": "",
  "employmentType": "",
  "paidOnly": "",
  "workingDays": "",
  "eligibleFor": "",
  "postedWithinDays": "",
  "teamSize": "",
  "entryFee": "",
  "skill": "Python",
  "sortBy": "",
  "sortDirection": "desc",
  "maxItems": 50,
  "includeDetails": true,
  "includeDescriptionHtml": false,
  "detailConcurrency": 8,
  "egressMode": "auto",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per opportunity in the default dataset: title, organiser, type, eligibility, registration deadline, prize money, stipend or salary, participant count, online or offline location and the opportunity URL. Empty or blocked runs return a single uncharged row instead.

# 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 = {
    "listing": [
        "hackathons"
    ],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/unstop-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 = {
    "listing": ["hackathons"],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/unstop-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 '{
  "listing": [
    "hackathons"
  ],
  "maxItems": 50
}' |
apify call dami_studio/unstop-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/unstop-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/1G5MkwLEW7ZcnmaxJ/builds/lwD5zJPnf7pWy67Hi/openapi.json
