Arizona State University (ASU) Class Schedule Scraper avatar

Arizona State University (ASU) Class Schedule Scraper

Pricing

from $3.00 / 1,000 results

Go to Apify Store
Arizona State University (ASU) Class Schedule Scraper

Arizona State University (ASU) Class Schedule Scraper

Scrapes every class section at Arizona State University (ASU): meeting days and times, instructor, building and room, instruction mode, and live enrollment vs capacity. All ASU campuses plus ASU Online, current and past terms.

Pricing

from $3.00 / 1,000 results

Rating

0.0

(0)

Developer

Brian Webster

Brian Webster

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

11 days ago

Last modified

Categories

Share

Scrapes every class section at Arizona State University — meeting days and times, instructor, building and room, instruction mode, and live enrollment against capacity — from the public class-search service behind catalog.apps.asu.edu.

Arizona State University publishes no bulk download and no documented API for its class schedule. The data exists only inside a single-page app at catalog.apps.asu.edu, one subject at a time.

Covers all Arizona State University campuses — Tempe, West Valley, Polytechnic and Downtown Phoenix — plus ASU Online, across every subject, for the current term and past ones.

What you get

One row per section, not per course — so a lecture and its six recitations are six rows, each with its own time, room, instructor and seat count.

FieldExample
courseKey, titleCSE 100, Principles of Programming with C++
section, classNumber1001, 70123
days, daysListM W F, ["M","W","F"]
startTime, endTime12:20 PM, 1:10 PM
buildingName, roomPSH, PSH152
instructorsYoshihiro Kobayashi
enrolled, capacity, seatsOpen167, 170, 3
waitlisted, waitlistCapacity0, 20
instructionMode, campusOL, TEMPE
units, unitsMax, component3, 3, Lecture
startDate, endDate, enrollDeadline2026-08-20, 2026-12-14, 2026-08-21
generalStudiesGold, generalStudiesMaroonSCIT, SQ
gradingBasis, consentStudent Option, ``
validFrom, observedAt2007-08-01, 2026-08-24T…
syllabusUrl, sourceUrllinks back to ASU

Set Include raw API record to attach the full ~145-field upstream object under raw if you need something this misses.

General studies: Gold and Maroon are two different curricula

ASU runs two general-studies programmes side by side, and which one governs a student depends on their catalog year — Gold from 2024 onward, Maroon before it. They are not two spellings of one value and their code sets do not overlap: ENG 130 is HUAD under Gold and L under Maroon; CSE 180 is QTRS and CS. Across ASU's full catalogue, 1,192 courses carry both designations and every one of them differs.

So filter on generalStudiesGold or generalStudiesMaroon, not on the legacy joined generalStudies string, which cannot tell you which curriculum a designation belongs to.

These come from ASU's course catalogue rather than the class record — a section carries 145 fields and not one of them is a designation — so the actor fetches them per subject and joins them on. If that lookup fails the sections are still returned; the designation is enrichment, not payload.

Dates: when it was true, and when we looked

validFrom is the term's start date; observedAt is when the row was scraped. Keeping them apart matters as soon as you pull more than one term: a run covering twenty years stamps every row with today's scrape time, so filtering on that would treat a 2007 section as 2026 information. validFrom is derived from the term code, which is exact — never estimated.

Input

Everything is optional. Run it with no input and you get the whole current term.

FieldDefaultNotes
termcurrent termASU term code, e.g. 2267 = Fall 2026. Past terms work too.
termsSeveral at once, e.g. ["2267","2261","2257"]. ASU publishes 62 terms back to Fall 2007, so this is how you pull a series and see what changed.
subjectsalle.g. ["CSE","MAT"]. Empty means every subject.
campusall + onlineTempe, West Valley, Polytechnic, Downtown Phoenix, ASU Online, or campus-only
maxItems0 (no limit)Cap for a cheap trial run
requestDelayMs600Politeness delay between requests
includeRawfalseAttach the upstream record

An invalid term fails immediately with a list of valid codes, rather than quietly returning nothing.

{
"term": "2267",
"subjects": ["CSE", "MAT"],
"campus": "TEMPE",
"maxItems": 500
}

What people use this Arizona State University data for

  • Seat-availability monitoring — schedule a run and diff seatsOpen to catch a section opening up.
  • Schedule planning tools — days, times and rooms are what a conflict-checker needs.
  • Enrollment demand researchenrolled/capacity across Arizona State University terms shows which subjects are growing.
  • Space utilisation — building and room on every meeting.
  • Instructor course loads — sections per instructor per term.

Notes on access and etiquette

The actor sends exactly what a logged-out browser sends. There is no account, no credential, and no login.

Arizona State University's class search is public, and the API behind it accepts anonymous requests in a slightly surprising way that's worth stating plainly: every endpoint returns 401 when a request carries no Authorization header, but the single-page app — which never obtains a token for anonymous visitors — builds the header unconditionally as "Bearer " + sessionStorage.getItem(...). With nothing stored that is null, so every anonymous visitor's browser sends the literal string Bearer null, and the gateway accepts it. It checks that the header is present, not that it is valid. This actor sends the same string.

/robots.txt on the API host returns the SPA shell, so there are no published crawl rules to honour. The actor therefore self-throttles (600 ms between requests by default) and identifies itself in the User-Agent. Please leave both alone unless you have a reason.

Only public catalog data is collected. No student data of any kind is exposed by this endpoint.

Reliability

term, subjects and classes are separate calls, and the actor fails fast on a bad term rather than returning an empty dataset. Individual subjects that error are logged as warnings and skipped so one bad subject cannot lose a run. 429 and 5xx get bounded exponential backoff. Sections are de-duplicated on term:classNumber, because the API's scroll cursor can repeat records across pages.

A run summary is written to the key-value store under RUN_SUMMARY with the term, subject counts, failures and total sections.

If ASU changes the access pattern the actor throws a specific error naming the SPA bundle to re-read, rather than silently producing nothing.

Why it walks subject by subject

It looks wasteful. ASU's course endpoint accepts a term with no subject filter and answers in a single request, which would replace hundreds of calls with one.

Measured on term 2267, that shortcut returns 9,363 records across 215 of 343 subjects, where the per-subject walk returns 14,833 across all 343. It is a server-side result cap, and it does not error — it returns HTTP 200 with a third of the catalogue missing. Failing by quietly returning less is the failure mode that gets believed, so the actor pays the requests.

Please do not "optimise" this away without re-measuring both totals.

Scale

A full-term run covers every subject and takes a while at the default delay. Use subjects or maxItems to trial it first.

Local development

npm install
npm run smoke # exercises the live API, no Apify platform needed
apify run # requires: npm install -g apify-cli

src/asu.js has no Apify dependency, so the client and the normaliser can be reused or tested outside the platform.


Not affiliated with or endorsed by Arizona State University. All data is public information published by Arizona State University at catalog.apps.asu.edu.