# Internshala Scraper \[💰$0.38] - Internships, Jobs & Employers, (`corvuslab/internshala-scraper`) Actor

Scrape Internshala internships, jobs and fresher jobs across India: stipend and salary with CTC breakup, duration, skills, perks, applicant count, apply-by date and full description, plus each employer's track record (hiring since, opportunities posted, candidates hired). Multi-city, alerts.

- **URL**: https://apify.com/corvuslab/internshala-scraper.md
- **Developed by:** [Corvuslab](https://apify.com/corvuslab) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.38 / 1,000 results

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

### What does Internshala Scraper do?

Internshala Scraper extracts **internships, jobs and fresher jobs from [Internshala.com](https://internshala.com/)**, India's largest internship and entry-level job board, as clean structured records with **79 fields** each: stipend or salary as numbers, duration, experience, skills, perks, applicant count, start and apply-by dates and the full description. Every record also carries the **employer's track record on Internshala**: hiring since, opportunities posted and candidates hired. It's no-code, and the output goes to JSON, CSV, Excel, the API or an AI agent.

Search by keyword, category, city and any of the site's filters, or paste Internshala search and listing URLs. Schedule it in incremental mode and get only new and changed listings, with alerts to Telegram, Slack, Discord or any webhook.

> New to Apify? Sign up free and use the included monthly platform credit to try this Actor. No credit card needed.

***

### What data can you extract from Internshala?

Every record carries **79 fields**, grouped like this:

| Group | What you get |
|---|---|
| **Listing** | Title, listing type (internship / job / fresher job), URL, labels, actively-hiring flag, employment type, occupational category, course-exclusive flag |
| **Pay & offer** | Stipend/salary text plus `salaryMin` / `salaryMax` / currency / period, unpaid flag, **CTC breakup** with fixed and variable pay as numbers, and **probation** length and pay on jobs, job-offer flag + text on internships |
| **Role** | Duration in text and months (internships), experience in text and min/max years (jobs), skills, perks, who can apply, other requirements, number of openings, full description as text, HTML and Markdown |
| **Dates & demand** | Start date, apply-by date (as text and as an ISO date), posted age + days ago, **exact posted and valid-through dates** where the listing publishes them, **applicant count**, early-applicant flag |
| **Location** | City, all cities, state/region, work mode (onsite / remote / hybrid), work-from-home flag, in-office days per week on hybrid roles, part-time flag |
| **Company & track record** | Company name, logo, Internshala company page, website, industry, about text, **hiring since**, **opportunities posted**, **candidates hired** |

On top of that come tracking fields (search keyword, search URL, scrape time, content hash) and, in incremental mode, the change-feed fields (`changeType`, first/last seen, expired at, repost detection).

***

### Key features

- 🎓 **Internships, jobs and fresher jobs**: all three Internshala sections, each with its own filters, from one Actor.
- 🗂️ **Several categories and several cities in one run**: e.g. Web Development + Data Science across Bangalore, Pune and Mumbai. Results are merged and de-duplicated.
- 🎚️ **Every filter the site has**: keywords, minimum stipend, minimum salary, experience, maximum duration, with job offer, fast response, early applicant, part-time, work from home and for women. Internshala applies the filters itself, and listings it pads a thin result with (another listing type, a lower stipend, a full-time role in a part-time search) are left out and never billed.
- 🏢 **Employer track record**: how long each company has hired on Internshala, how many opportunities it has posted and how many candidates it has hired, so you can tell established employers from first-time posters. We haven't seen another Internshala scraper return these fields.
- 💵 **Salary breakup & probation on jobs**: annual CTC split into fixed and variable pay (as numbers), plus probation length and pay where the job has one.
- 📅 **Exact dates & applicant demand**: posted and valid-through dates, the apply-by date and the live applicant count.
- 🛡️ **No surprise bills from typos**: a category or city Internshala doesn't recognise is skipped with a warning instead of expanding into the whole site (see the FAQ).
- ♻️ **Incremental monitoring**: scheduled runs return only what changed, unchanged listings cost nothing, and reposts can be skipped.
- 🔔 **Notifications**: Telegram, Slack, Discord or any webhook (n8n / Make / Zapier).
- 📓 **Straight into Notion**: every listing becomes a page in your Notion database as the run goes, with typed, filterable columns created for you.
- 🤖 **AI-ready**: compact and drop-empty output modes keep payloads small for LLMs and MCP.

***

### 🚀 How to scrape Internshala

1. Open the Actor and choose a **listing type**: internships, jobs or fresher jobs.
2. Add **keywords**, **categories** and **cities** (all optional), then pick filters. You can also paste an Internshala URL instead.
3. Set **Max results** and choose whether to **fetch full details**.
4. (Optional) Turn on **incremental mode** and a **notification** channel, then **Schedule** it.
5. Click **Start**. Results stream into the Output tab. Download them as **JSON, CSV or Excel**, or pull them from the **API**.

No login, no cookies, no setup. Even an empty input works: it returns the **25 newest internships across India** with full details.

#### Quick-start example input

```json
{
  "listingType": "internship",
  "categories": ["Web Development", "Data Science"],
  "locations": ["Bangalore", "Pune"],
  "minStipend": 10000,
  "maxResults": 100
}
```

This finds up to 100 web-development and data-science internships in Bangalore and Pune paying at least ₹10,000 a month. They come de-duplicated across both cities, with the full description, applicant count and each employer's hiring track record.

***

### Input

Configure it in the visual editor (no code needed) or pass JSON through the API.
**42 inputs** are available, grouped exactly as in the editor.

#### 🔎 Search

| Field | Type | What it does |
|---|---|---|
| `listingType` | enum | `internship` (default), `job` or `fresher-job` (0–1 year experience). |
| `query` | string | Keywords, e.g. `react` or `content writing`. Separate several with commas. Each runs as its own search and the results are merged. |
| `categories` | array | Internshala categories as named on the site, e.g. `Web Development`, `Python/Django`, `Data Science`, `Marketing`, `Human Resources (HR)`. Several values widen the search. |
| `locations` | array | Cities, e.g. `Bangalore`, `Mumbai`, `Delhi`, `Hyderabad`, `Pune`, `Chennai`. Several values widen the search. |
| `startUrls` | array | Internshala search pages (with any filters applied on the site) or single internship/job pages, used in addition to the search. |
| `maxResults` | integer | Maximum listings across all searches (default 25, `0` = everything the search has). |
| `maxPages` | integer | Stop each search after this many results pages, about 40 listings each (`0` = no limit). |

#### 🎚️ Filters

Internshala applies these filters itself. Filters marked *(internships)* or *(jobs)* only apply to that listing type.

| Field | Type | What it does |
|---|---|---|
| `workFromHome` | boolean | Remote listings only. |
| `partTime` | boolean | Part-time listings only. |
| `forWomen` | boolean | *(internships)* Internshala's internships-for-women section. |
| `minStipend` | integer | *(internships)* Minimum monthly stipend in ₹. The site's steps are 2,000 / 4,000 / 6,000 / 8,000 / 10,000, and other values are rounded down to a step. |
| `maxDurationMonths` | integer | *(internships)* Maximum duration. The site's steps are 1, 2, 3, 4, 6, 12, 24 and 36 months. |
| `withJobOffer` | boolean | *(internships)* Only internships with a pre-placement job offer. |
| `fastResponse` | boolean | *(internships)* Only employers that respond quickly. |
| `earlyApplicant` | boolean | *(internships)* Only internships with few applicants so far. |
| `minSalaryLpa` | integer | *(jobs)* Minimum annual salary in lakh ₹ (1–10). |
| `experience` | enum | *(jobs)* Jobs open to a candidate with `1`, `2`, `3`, `4`, `5` or `5plus` years of experience, so roles asking for less (including fresher roles) are included. For 0 years, pick the fresher-jobs listing type. |

#### 📄 Output

| Field | Type | What it does |
|---|---|---|
| `includeDetails` | boolean | Open each listing for the description, dates, applicant count, openings, perks, who can apply, salary breakup and company profile (default on). |
| `descriptionFormat` | enum | `all`, `text`, `html` or `markdown`. |
| `descriptionMaxLength` | integer | Truncate descriptions to N characters (`0` = no limit). |
| `compact` | boolean | Core fields only. Ideal for AI agents and MCP clients. |
| `excludeEmptyFields` | boolean | Drop null and empty fields for cleaner output. |

#### ♻️ Incremental monitoring

| Field | Type | What it does |
|---|---|---|
| `incrementalMode` | boolean | Emit only what changed since the last run, tagged with a `changeType`. |
| `stateKey` | string | Stable name for the tracked search (derived automatically if left blank). |
| `emitUnchanged` | boolean | Also emit listings that haven't changed. |
| `emitExpired` | boolean | Also emit listings that have closed since the last run (needs `maxResults: 0`). |
| `skipReposts` | boolean | Drop re-posts of a listing seen in an earlier run (same title, company and place under a new ID). They cost nothing. |

#### 🔔 Notifications

Credentials are secret inputs: encrypted at rest, masked in the UI and never written to the run log.

| Field | Type | What it does |
|---|---|---|
| `telegramToken` + `telegramChatId` | string | Telegram bot token + chat or channel ID. |
| `slackWebhookUrl` / `discordWebhookUrl` | string | Incoming webhook URL. |
| `webhookUrl` + `webhookHeaders` | string / object | POST the matched listings as JSON to n8n, Make, Zapier or any endpoint. |
| `notificationLimit` | integer | Listings per notification message (1–20, default 5). |
| `notifyOnlyChanges` | boolean | In incremental mode, alert only on NEW, UPDATED and REAPPEARED listings, even when unchanged ones are emitted. |

#### 📓 Send results to Notion

| Field | Type | What it does |
|---|---|---|
| `notionApiKey` | string | Internal integration secret from notion.so/my-integrations (starts with `ntn_`). Connect the integration to your database (⋯ → Connections). Secret input. |
| `notionDatabaseId` | string | The database URL or its 32-character ID. It can start empty: the columns are created on the first run. |
| `notionCreateProperties` | boolean | Create any missing columns with the right Notion type (on by default). Off = write only into columns you made. |

#### ⚙️ Advanced

| Field | Type | What it does |
|---|---|---|
| `proxyConfiguration` | object | Optional and off by default. Runs work without it. |
| `maxConcurrency` | integer | Pages fetched in parallel (1–16, default 16). |
| `maxRequestRetries` | integer | Retries per failed request (default 3). |
| `ignoreUrlFailures` | boolean | Skip URLs that can't be read instead of failing the run (default on). |

#### More example inputs

Remote fresher jobs for a keyword:

```json
{ "listingType": "fresher-job", "query": "content writing, digital marketing", "workFromHome": true, "maxResults": 200 }
```

Jobs for candidates with 2 years of experience, at least 5 LPA, in two cities:

```json
{ "listingType": "job", "locations": ["Hyderabad", "Chennai"], "experience": "2", "minSalaryLpa": 5, "maxResults": 0 }
```

A daily alert for new paid internships with a job offer:

```json
{ "listingType": "internship", "categories": ["Python/Django"], "withJobOffer": true, "minStipend": 8000, "maxResults": 0, "incrementalMode": true, "telegramToken": "<bot token>", "telegramChatId": "@yourchannel" }
```

Specific Internshala pages:

```json
{ "startUrls": [{ "url": "https://internshala.com/fresher-jobs/" }, { "url": "https://internshala.com/internship/detail/sales-and-business-development-executive-us-sales-internship-in-bangalore-at-spryte-labs-private-limited1789980112" }] }
```

***

### Output

Each dataset item is one internship or job. Every record carries the card fields (title, company, location, stipend/salary, duration or experience, skills, posted age). **Fetch full details** (on by default) adds the description, dates, applicant count, openings, perks, salary breakup and the company's track record. Here is a real fresher-job record, trimmed:

```json
{
  "id": "3291202",
  "listingType": "job",
  "title": "Business Development Executive",
  "company": "Zucol Solutions Private Limited",
  "url": "https://internshala.com/job/detail/fresher-business-development-executive-job-in-jaipur-at-zucol-solutions-private-limited1789720402",
  "activelyHiring": true,
  "location": "Jaipur",
  "regions": ["Rajasthan"],
  "workMode": "onsite",
  "salaryText": "₹ 2,53,000 - 4,56,000 /year",
  "salaryMin": 253000,
  "salaryMax": 456000,
  "salaryCurrency": "INR",
  "salaryPeriod": "YEAR",
  "salaryBreakup": "Annual CTC: ₹ 2,53,000 - 4,56,000 /year\nAnnual CTC breakup:\n1. Fixed pay: ₹ 2,50,000 - 4,50,000 /year\n2. Variable pay: ₹ 3,000 - 6,000 /year",
  "fixedPayMin": 250000,
  "fixedPayMax": 450000,
  "variablePayMin": 3000,
  "variablePayMax": 6000,
  "experienceText": "No experience required",
  "experienceMinYears": 0.0,
  "experienceMaxYears": 0.0,
  "isFresherJob": true,
  "skills": ["Business Development", "Client Relationship", "Effective Communication", "Lead Generation", "Sales"],
  "startDate": "Immediately",
  "applyBy": "18 Oct' 26",
  "applyByDate": "2026-10-18",
  "postedAgo": "3 weeks ago",
  "postedAt": "2026-09-18",
  "validThrough": "2026-10-18T23:59:59",
  "applicantCount": 125,
  "applicantVolumeLabel": "125 applicants",
  "numberOfOpenings": 10,
  "whoCanApply": "Only those candidates can apply who:\n1. are from Jaipur only",
  "description": "Key responsibilities:\n1. Will be responsible for finding new business opportunities.\n2. Building client relationships and increase company sales.\n3. They generate leads, pitch products or services, and close deals to drive growth.",
  "employmentType": "FULL_TIME",
  "occupationalCategory": "Business Development (Sales)",
  "companyIndustry": "Computer Services",
  "companyUrl": "https://internshala.com/company/zucol-solutions-private-limited-1650688633",
  "companyHiringSince": "December 2025",
  "companyOpportunitiesPosted": 17,
  "companyCandidatesHired": 5,
  "source": "internshala.com",
  "scrapedAt": "2026-10-18T10:07:25.425135+00:00"
}
```

Descriptions also come as `descriptionHtml` and `descriptionMarkdown`. Internship records carry `duration`, `durationMonths`, `hasJobOffer` and `jobOfferText` (e.g. *"Job offer upto ₹ 4.5LPA post internship"*) instead of the experience fields. In incremental mode, each record also carries a `changeType`.

#### Data fields

- **Core**: `id`, `listingType`, `title`, `company`, `companyLogo`, `url`, `location`, `locations`, `regions`, `workMode`, `isWorkFromHome`, `inOfficeDaysPerWeek`, `isPartTime`, `salaryText`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `isUnpaid`, `duration`, `durationMonths`, `experienceText`, `experienceMinYears`, `experienceMaxYears`, `skills`, `descriptionSnippet`, `postedAgo`, `postedDaysAgo`, `activelyHiring`, `earlyApplicant`, `hasJobOffer`, `jobOfferText`, `isFresherJob`, `isCourseExclusive`, `labels`.
- **Details** (with `includeDetails`): `description`, `descriptionHtml`, `descriptionMarkdown`, `whoCanApply`, `otherRequirements`, `perks`, `numberOfOpenings`, `applicantCount`, `applicantVolumeLabel`, `startDate`, `applyBy`, `applyByDate`, `postedAt`, `validThrough`, `employmentType`, `occupationalCategory`, `salaryBreakup`, `fixedPayMin`, `fixedPayMax`, `variablePayMin`, `variablePayMax`, `probation`, `probationMonths`.
- **Company & track record** (with `includeDetails`): `aboutCompany`, `companyWebsite`, `companyUrl`, `companyIndustry`, `companyHiringSince`, `companyOpportunitiesPosted`, `companyCandidatesHired`.
- **Tracking & change feed**: `source`, `searchKeyword`, `searchUrl`, `scrapedAt`, `detailFetched`, `contentHash`, `changeType`, `firstSeenAt`, `lastSeenAt`, `previousSeenAt`, `expiredAt`, `isRepost`, `repostOfId`, `repostDetectedAt`.

In standard mode every field is present, and missing values are `null`. The Output tab has two table views: **Overview** (the essentials per listing) and **Full details** (adds start date, openings, skills, perks, who can apply and the company website).

***

### ♻️ How to monitor Internshala with incremental mode

Schedule the Actor and turn on **incremental mode**. Each run compares against the last one and emits only **NEW / UPDATED / REAPPEARED / EXPIRED** listings. Unchanged listings are recognised from the search results *before* their detail page is fetched, so you skip both the work and the cost.

| | First run (baseline) | Next run (nothing changed) |
|---|---|---|
| Listings found | all | all |
| Detail pages fetched | all | **none** |
| Records emitted & billed | all | **none** |

After the baseline, your cost depends on how much of Internshala changes, not on how much of it you watch:

| Daily churn | of 1,000 tracked | billable records | you save |
|---|---|---|---|
| 5 % | 1,000 | 50 | **95 %** |
| 15 % | 1,000 | 150 | **85 %** |
| 30 % | 1,000 | 300 | **70 %** |

Reposted listings are detected and flagged with `isRepost` and `repostOfId`, so a re-listed role doesn't look like a brand-new opening. Closed listings (`EXPIRED`) are reported only on runs that cover the whole search (`maxResults: 0`). A capped run can't tell a closed listing from one it simply didn't reach.

#### Setting up scheduled monitoring

1. Configure your listing type, categories, cities and filters.
2. Set **Max results** to `0` and turn on **Incremental mode**.
3. Run it once to seed the baseline.
4. Open the **Schedules** tab and set a recurring run (e.g. every morning).
5. Add a notification channel. From then on, each alert carries only new and changed listings.

***

### 🔔 How to set up Internshala alerts

Get pinged the moment a matching internship or job is posted. Fill in only the channels you want (Telegram, Slack, Discord or a JSON webhook for n8n / Make / Zapier; the fields are in the Notifications table under Input). To keep every listing as a row instead, send results to a Notion database.

Each message lists up to `notificationLimit` listings with title, company, city, stipend or salary and link. Every channel fires independently, so a broken channel can't stop the scrape or the other channels. With **incremental mode** on, alerts include only listings that are genuinely new or changed, with no duplicates across runs.

***

### 💡 What can you do with Internshala data?

#### Run an internship or fresher-job alert channel

Feed new listings for a category and city into a Telegram, Slack or Discord channel for your students, community or newsletter. Incremental mode makes sure each listing is announced exactly once.

#### Benchmark stipends and entry-level salaries

Numeric `salaryMin` / `salaryMax` with period, plus the fixed-vs-variable CTC breakup on jobs, let you compare pay by role, city, category and work mode. Track the averages month over month to see where entry-level pay is moving.

#### Vet employers before you apply or partner

Hiring-since, opportunities-posted and candidates-hired show whether a company is an established recruiter or posting for the first time. Placement cells and career platforms can rank or flag employers on that track record.

#### Map hiring demand across India

Count listings, openings and applicants by skill, category, city and state to see where internships and fresher jobs are growing. Applicant counts show which roles are crowded and which still have room.

#### Power a job board or career app

Keep an aggregator, campus portal or edtech product stocked with fresh, de-duplicated Internshala listings, with descriptions in text, HTML or Markdown. Scheduled incremental runs keep it current at low cost.

#### Feed AI agents and LLM pipelines

Send compact JSON straight into an LLM context, an MCP tool or a vector store, for example to match students to roles by skills. `excludeEmptyFields` and compact mode keep token costs low.

***

### 💰 How much does it cost to scrape Internshala?

This Actor uses Apify's **pay-per-event** model: a small fee when a run starts, plus a fee for each listing in the dataset. The Actor's **Pricing** tab shows the current numbers live, so this page never goes stale.

Each results page returns about 40 listings at once, with no browser and no proxy needed by default, which keeps the per-listing fee at the low end of the market. You're billed only for listings that match your filters: filtered-out rows, padding the site adds and misspelt categories or cities never reach the dataset. Incremental mode cuts the bill further, since after the baseline you pay only for what changed (see the table above). You can also cap any run with **Max results** or with Apify's per-run spending limit.

***

### 🔌 Integrations & export

Export to **JSON, CSV, Excel** or an HTML table, or pull results from the **REST API** and the **JavaScript / Python** clients. Runs work on a **schedule**, connect to **Google Sheets, Slack, Make, Zapier and n8n**, and plug into AI agents as an **MCP tool**.

Also covering India: our [Foundit Jobs Scraper](https://apify.com/corvuslab/foundit-jobs-scraper) for the wider Indian job market.

***

### 🔗 Using the API

Run this Actor from your own code. Example with the Apify Python client:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")

run_input = {
    "listingType": "internship",
    "categories": ["Data Science"],
    "locations": ["Bangalore", "Mumbai"],
    "maxResults": 50,
}

run = client.actor("corvuslab/internshala-scraper").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["company"], item["salaryText"], item["companyCandidatesHired"])
```

It also works with the JavaScript/TypeScript client, the Apify CLI and the REST API.

***

### ❓ FAQ

**Do I need an Internshala account or login?** No. The Actor reads only public listings, with no account, cookies or proxy setup.

**Why do I get fewer listings than Internshala's own count?** For city searches, Internshala's headline count also includes remote listings, which a city search doesn't return. Listings the site adds that don't match your filters are also left out, and never billed.

**Can I search several cities at once?** Yes. Internshala itself honours only one city per search, so the Actor runs one search per city, then merges and de-duplicates the results. `maxResults` is shared across all of those searches, not applied per city.

**What happens if I misspell a category or city?** When Internshala doesn't recognise a filter value, it ignores it and returns the whole site. The Actor detects this: an unrecognised value is dropped with a warning in the log, and a search where every value was unrecognised is skipped. You never pay for thousands of unrelated listings because of a typo.

**Why is `applicantCount` empty on some listings?** Internshala shows a number only once a listing has a meaningful number of applicants. Otherwise it shows *"Be an early applicant"*, which comes through in `applicantVolumeLabel` and sets `earlyApplicant: true`. Expect a numeric count on about half of listings.

**Why is `companyCandidatesHired` sometimes null?** Internshala only displays it once the company has hired at least one candidate through the site, which is the case on a little over half of listings. `companyHiringSince` and `companyOpportunitiesPosted` are present on practically every detailed record. The exact `postedAt` / `validThrough` dates appear where the listing publishes them (most listings). `postedAgo` and `postedDaysAgo` are always there.

**Does it return employer emails or phone numbers?** No. Internshala doesn't publish employer contact details, since applications go through the site. You get the company's website (on about 60% of listings), its Internshala company page, industry, about text and hiring track record.

**Which fields apply to internships and which to jobs?** Duration, stipend steps, job offer, fast response, early applicant and for women are internship-only. Experience, salary breakup, fixed/variable pay and probation are jobs-only (fixed/variable pay only where the job publishes a breakup, `probation` only where it has one). `occupationalCategory` is filled only when the site gives a real category rather than repeating the title. `inOfficeDaysPerWeek` is filled only on hybrid listings. Fields that don't apply are `null`.

**What does `isCourseExclusive` mean?** Some listings are reserved for students of Internshala's own placement course. They appear in search results, so the Actor returns their card fields and flags them `isCourseExclusive: true`, but their full details aren't public.

**How many listings can I get?** Set `maxResults` to `0` for everything a search has. The whole Internshala catalogue is reachable, not just the first pages.

***

### ⚖️ Is it legal to scrape Internshala?

This Actor collects only **publicly available** listing data: the same internships and jobs anyone can browse on Internshala without logging in. It doesn't collect candidate data or employer contact details. You're responsible for how you use the data, in particular any personal information, and for complying with Internshala's terms and applicable law, including India's Digital Personal Data Protection Act and the GDPR/LGPD where they apply. Not affiliated with, endorsed by or sponsored by Internshala.

***

**Keywords:** internshala scraper · internshala api · internshala.com scraper · scrape internshala internships · internshala jobs scraper · internshala fresher jobs · internship scraper india · fresher jobs india · stipend data · entry-level salary data · work from home internships · job alerts telegram · job monitoring · export to CSV · export to Excel · no-code scraper · MCP tool for AI agents

# Changelog

This Actor's version history is a separate document: https://apify.com/corvuslab/internshala-scraper/changelog.md

# Actor input Schema

## `listingType` (type: `string`):

Internships, jobs, or fresher jobs (0–1 year experience).

## `query` (type: `string`):

Optional. Keywords to search for, e.g. "react" or "content writing". Separate several searches with commas — each runs as its own search and results are merged and de-duplicated.

## `categories` (type: `array`):

Optional. Internshala categories, as named on the site — e.g. "Web Development", "Python/Django", "Data Science", "Marketing", "Graphic Design", "Content Writing", "Human Resources (HR)". Several values widen the search. Names Internshala does not recognise are skipped with a warning.

## `locations` (type: `array`):

Optional. Cities, e.g. "Bangalore", "Mumbai", "Delhi", "Hyderabad", "Pune", "Chennai". Several values widen the search.

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

Optional. Paste Internshala search pages (with any filters applied on the site) or single internship/job pages. Used in addition to the search above.

## `maxResults` (type: `integer`):

Maximum number of listings to return across all searches. Set 0 for everything the search has.

## `maxPages` (type: `integer`):

Stop each search after this many results pages (about 40 listings each). 0 = no limit — Max results still applies.

## `workFromHome` (type: `boolean`):

Only remote listings.

## `partTime` (type: `boolean`):

Only part-time listings.

## `forWomen` (type: `boolean`):

Only internships in Internshala's internships-for-women section. (The site's jobs-for-women page lists internships, so this filter is not used for jobs.)

## `minStipend` (type: `integer`):

Only internships paying at least this much per month. The site filters in steps of 2,000, 4,000, 6,000, 8,000 and 10,000; other values are rounded down to a step.

## `maxDurationMonths` (type: `integer`):

Only internships lasting at most this long. Site steps: 1, 2, 3, 4, 6, 12, 24, 36.

## `withJobOffer` (type: `boolean`):

Only internships that come with a pre-placement job offer.

## `fastResponse` (type: `boolean`):

Only internships from employers that respond quickly.

## `earlyApplicant` (type: `boolean`):

Only internships with few applicants so far.

## `minSalaryLpa` (type: `integer`):

Only jobs paying at least this many lakh rupees per year (1–10).

## `experience` (type: `string`):

Only jobs open to a candidate with this many years of experience. For 0 years pick the Fresher jobs listing type.

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

Open each listing for the full description, start date, apply-by date, applicant count, openings, perks, who can apply and the company profile. Turn off for the fastest runs.

## `descriptionFormat` (type: `string`):

Which representation(s) of the full description to include.

## `descriptionMaxLength` (type: `integer`):

Truncate descriptions to this many characters. 0 = no limit.

## `compact` (type: `boolean`):

Emit only the core fields. Ideal for AI agents and MCP clients.

## `excludeEmptyFields` (type: `boolean`):

Remove null, empty-string and empty-array fields from each record.

## `incrementalMode` (type: `boolean`):

Track state between runs and tag every record with a changeType (NEW / UPDATED / REAPPEARED / UNCHANGED / EXPIRED). Unchanged listings are skipped and cost nothing.

## `stateKey` (type: `string`):

Stable name for the tracked search. Leave empty to derive one automatically from your search settings.

## `emitUnchanged` (type: `boolean`):

Also emit listings that have not changed since the previous run.

## `emitExpired` (type: `boolean`):

Emit listings that were present last run but are gone now. Only reported when the run covers the whole search (Max results 0).

## `skipReposts` (type: `boolean`):

Drop listings that are re-posts of one seen in an earlier run (same title, company and location under a new ID). They're recognised before any detail page is opened, so they cost nothing. Needs incremental mode.

## `telegramToken` (type: `string`):

Bot token from @BotFather.

## `telegramChatId` (type: `string`):

Chat or channel ID, e.g. "-100123456789" or "@yourchannel".

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

Slack incoming-webhook URL.

## `discordWebhookUrl` (type: `string`):

Discord incoming-webhook URL.

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

Any HTTPS endpoint. Receives a JSON POST with the matched listings — works with n8n, Make and Zapier.

## `webhookHeaders` (type: `object`):

Extra headers for the webhook request, e.g. {"Authorization": "Bearer xyz"}.

## `notificationLimit` (type: `integer`):

How many listings to include in each notification message.

## `notifyOnlyChanges` (type: `boolean`):

In incremental mode, send only NEW, UPDATED and REAPPEARED listings to your channels (useful together with 'Include unchanged listings').

## `notionApiKey` (type: `string`):

Create an internal integration at notion.so/my-integrations, copy its Internal Integration Secret (starts with 'ntn\_'), then open the target database → ⋯ → Connections and connect that integration. Without that last step Notion returns 'object_not_found'.

## `notionDatabaseId` (type: `string`):

Paste the database's URL or its 32-character ID. Every listing becomes one page in that database. The database can start completely empty — the columns are created for you on the first run.

## `notionCreateProperties` (type: `boolean`):

Add any columns the target database is missing (with the right Notion type) on the first run. Turn this off to write only into columns you created yourself — fields with no matching column are then skipped.

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

Optional. Not needed — runs work without a proxy. Turn it on only if requests start being refused.

## `maxConcurrency` (type: `integer`):

How many pages to fetch in parallel.

## `maxRequestRetries` (type: `integer`):

How many times to retry a failed request before giving up on it.

## `ignoreUrlFailures` (type: `boolean`):

Skip URLs that cannot be interpreted instead of failing the whole run.

## Actor input object example

```json
{
  "listingType": "internship",
  "query": "react, content writing",
  "categories": [
    "Web Development",
    "Data Science"
  ],
  "locations": [
    "Bangalore",
    "Mumbai"
  ],
  "maxResults": 25,
  "maxPages": 0,
  "workFromHome": false,
  "partTime": false,
  "forWomen": false,
  "withJobOffer": false,
  "fastResponse": false,
  "earlyApplicant": false,
  "includeDetails": true,
  "descriptionFormat": "all",
  "descriptionMaxLength": 0,
  "compact": false,
  "excludeEmptyFields": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "skipReposts": false,
  "notificationLimit": 5,
  "notifyOnlyChanges": false,
  "notionCreateProperties": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxConcurrency": 16,
  "maxRequestRetries": 3,
  "ignoreUrlFailures": true
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `allItems` (type: `string`):

No description

## `details` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("corvuslab/internshala-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("corvuslab/internshala-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 '{}' |
apify call corvuslab/internshala-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,corvuslab/internshala-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/NpOobx9VRaFqs1Wjw/builds/mqbY7VFhvBvWGQleq/openapi.json
