Internshala Scraper - India Jobs & Internships, Salary avatar

Internshala Scraper - India Jobs & Internships, Salary

Pricing

from $1.46 / 1,000 posting returneds

Go to Apify Store
Internshala Scraper - India Jobs & Internships, Salary

Internshala Scraper - India Jobs & Internships, Salary

Every job and internship on Internshala with the fields the listing hides: pay as numbers with currency and period (annual CTC for jobs, monthly stipend for internships), experience, the deadline as a real date, skills, duration and the full description. A posting delisted mid-run is never charged.

Pricing

from $1.46 / 1,000 posting returneds

Rating

0.0

(0)

Developer

NeverEmpty

NeverEmpty

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

8 hours ago

Last modified

Share

Pull jobs and internships from Internshala with the fields the listing page does not give you: pay as two numbers with its currency and period, years of experience as a number, and the application deadline as a real date - plus skills, duration, start date, perks and the full description.

Jobs carry an annual CTC. Internships carry a monthly stipend. Both land in the same columns with salaryPeriod set to year or month, so a monthly figure is never mistaken for a yearly one.

Unofficial. This Actor is not affiliated with, endorsed by, or sponsored by Internshala. All product names are trademarks of their respective owners.

No API key. No proxy needed. Reads the same public pages a visitor sees.


Why this one is different

A delisted job is an expired row, and it is never charged

Jobs come off Internshala while a run is going. Measured on 2026-09-03: a job that was in the listing returned HTTP 404 a few minutes later.

Most scrapers parse that page anyway and hand you a row where every field is null - and charge you for it. This Actor checks the response first and splits the result three ways:

statusWhat it meansCharged?
okThe job page was readYes
expiredThe job is no longer listed (HTTP 404)No
unparsableThe page could not be read (any other status, or the job block is missing)No

You always know which of the three you got. An empty result and a broken fetch are never the same row.

Salary comes back as numbers, not as a string

The page shows ₹ 4,22,000 - 6,18,000 /year. You get:

{ "salaryMin": 422000, "salaryMax": 618000, "salaryCurrency": "INR", "salaryPeriod": "year",
"salaryRaw": "₹ 4,22,000 - 6,18,000 /year" }

Indian digit grouping (4,22,000) is parsed correctly. A monthly figure comes back as "salaryPeriod": "month" - it is never silently reported as a yearly one. When the page has no figure, you get null, not 0. The raw string is always kept so you can check the parsing yourself.

The deadline is a date you can sort on

Apply By 11 Oct' 26 becomes "applyBy": "2026-10-11". If the page writes it in a form this Actor cannot read, applyBy is null and applyByRaw still holds the original text. No date is ever guessed.

It returns this job's values, not the neighbour's

An Internshala job page carries similar jobs on the same HTML. Measured: one page had 4 different salary blocks and 4 company names in it. This Actor reads only the job's own block, so the salary you get belongs to the job in the row.

The same applies to skills: Learn MS-Excel, Learn Digital Marketing are Internshala's own course adverts sitting next to the real skill list. They are not returned as required skills.

A city Internshala does not have tells you so

Measured on 2026-09-03: /jobs/bangalore/, /bangalore-jobs/ and /jobs/in-bangalore/ all return HTTP 200 while quietly ignoring the city - all 50 results are identical to the unfiltered listing, starting with a job in Mumbai. Only /full-time-jobs-in-<city>/ actually filters.

Worse: a city that does not exist at all (atlantis, zzzznotacity) also answers HTTP 200 and returns the unfiltered list. Waiting for a 404 never tells you.

So this Actor checks the result instead of the status code: it fetches the unfiltered listing once and compares. If your filtered page comes back as the same jobs, you get one no-listing row saying the filter does not exist, and it is not charged - you are never handed all-India jobs while thinking you filtered by city.


Input

FieldTypeDefaultDescription
listingselectjobs9 listings, each checked against the live site: jobs, internships, work-from-home-jobs, remote-jobs, fresher-jobs, part-time-jobs, and the three internship equivalents
citystringJobs only. e.g. bangalore, delhi, mumbai. Takes priority over the others. Internshala publishes no working city filter for internships, so it is not offered there
categorystringJobs only. e.g. marketing, computer-science, finance. Used when city is empty
maxJobsinteger301-1000. One job = one row = one charged event
includeDescriptionbooleantrueThe responsibilities/requirements text. Same price either way
maxPagesinteger0Safety cap on listing pages. 0 = decide from maxJobs
keywordsarrayKeep only listings containing one of these words
keywordMatchstringanyany or all
excludeKeywordsarrayDrop listings containing one of these
companyNamesarrayKeep only these companies (partial match)
minSalaryinteger0A listing with no published pay is kept
requireSalarybooleanfalseDrop listings that do not state the pay
postedWithinDaysinteger0Apply-by within N days. An unreadable date is kept
monitoringModebooleanfalseReturn only listings not returned on a previous run
resetMonitoringStatebooleanfalseOne-shot: forget what was already returned

Filters are applied before you are charged

The filters narrow what was already read - nothing extra is fetched from Internshala - and a listing that does not match is never delivered and never charged. If a search returns listings but none match your filters you get one unpaid row saying exactly that (no-filter-match), so you can tell "the filter was too tight" apart from "there is nothing there".

minSalary keeps a listing whose pay is not stated rather than treating it as low. Remember that jobs carry a yearly CTC and internships carry a monthly stipend - salaryPeriod tells you which, so set the threshold with the listing type you chose in mind.

Monitoring mode turns this into a daily feed

Schedule it with monitoringMode: true and each run returns only the listings it has not returned before. Already-seen listings are skipped before their pages are opened, so a repeat run is fast as well as free.

⚠️ Measured on 2026-09-04: Internshala reorders its listing between requests - the first page is not stable. So the first few monitoring runs return listings that are new to you but not necessarily newly posted, as the shuffle brings different postings into the window you scan. It settles: four consecutive runs with maxJobs: 6 returned 6, 1, 3, then 0. Use a larger maxJobs if you want it to settle sooner.

The minimal call is an empty input: it returns 30 jobs from the full listing.


Output columns

ColumnExample
jobId1788172448
postingTypejob or internship
urlthe job page
statusok / expired / unparsable / no-listing
titleBusiness Development Manager
companySwing Saga
locationGhaziabad, Greater Noida, Delhi, Noida, Gurgaon
salaryMin / salaryMax422000 / 618000
salaryCurrency / salaryPeriodINR / year
salaryRaw₹ 4,22,000 - 6,18,000 /year
experienceYears / experienceRaw1 / 1 year(s)
duration4 Months (internships)
applyBy / applyByRaw2026-10-11 / 11 Oct' 26
startDateStarts Immediately
skills["Business Development", "Client Interaction", ...]
perks["Informal dress code", "5 days a week"]
postedRawPosted 2 days ago
descriptionthe full responsibilities text
scrapedAtISO timestamp of the fetch

Measured, not estimated

Everything above was checked against the live site on 2026-09-03, not read off documentation:

  • Listing paging: 8 pages in a row, all HTTP 200, no rate limiting, 329 job URLs, about 1 second per page.
  • The 404 case: a job present in the listing returned HTTP 404 minutes later. That is where the expired row comes from.
  • The silent-filter case: /jobs/bangalore/ returned the unfiltered listing with HTTP 200 (50 of 50 URLs identical to /jobs/). /full-time-jobs-in-bangalore/ returned 42 of 50 in Bangalore.
  • The neighbour-jobs case: one job page contained 4 salary blocks and 4 company names.

The Actor ships with 22 checks run against saved copies of real pages (a job page, an internship page, a delisted page and a listing page), and a mutation suite of 20 deliberate breakages - all 20 are caught. Breakages that the checks do not catch are listed in test/mutate.mjs with the reason, rather than quietly counted as passes.


Typical uses

  • Track which companies in India are hiring, and at what CTC band.
  • Build a salary benchmark by role, city or experience level - the numbers are already parsed.
  • Watch a category (marketing, computer-science) and alert on new postings before the deadline.
  • Feed a job board or a newsletter with fresh postings that still have an open applyBy date.
  • Compare fresher vs experienced pay for the same title.

Notes and limits

  • Internshala publishes Indian jobs. Salaries are in INR.
  • perks is returned only when the job page has a perks block; otherwise it is an empty array. Nothing is filled in to make the row look complete.
  • Fresher postings usually have no experience line at all. Those rows come back with experienceYears: null, not 0 - "no requirement stated" and "zero years required" are different answers.
  • postedRaw is Internshala's own wording (Posted 2 days ago). It is not converted to a date, because the site does not publish an exact timestamp and this Actor does not guess one.
  • The listing pages are read as a visitor sees them. https://internshala.com/robots.txt does not restrict them.

Other tools by NeverEmpty

Support

Found a row that looks wrong? Open an issue on the Actor page with the url from the row - the raw fields (salaryRaw, applyByRaw, experienceRaw) are kept precisely so a mistake can be checked against the page.