Arizona State University (ASU) Class Schedule Scraper
Pricing
from $3.00 / 1,000 results
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
Maintained by CommunityActor 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.
| Field | Example |
|---|---|
courseKey, title | CSE 100, Principles of Programming with C++ |
section, classNumber | 1001, 70123 |
days, daysList | M W F, ["M","W","F"] |
startTime, endTime | 12:20 PM, 1:10 PM |
buildingName, room | PSH, PSH152 |
instructors | Yoshihiro Kobayashi |
enrolled, capacity, seatsOpen | 167, 170, 3 |
waitlisted, waitlistCapacity | 0, 20 |
instructionMode, campus | OL, TEMPE |
units, unitsMax, component | 3, 3, Lecture |
startDate, endDate, enrollDeadline | 2026-08-20, 2026-12-14, 2026-08-21 |
generalStudiesGold, generalStudiesMaroon | SCIT, SQ |
gradingBasis, consent | Student Option, `` |
validFrom, observedAt | 2007-08-01, 2026-08-24T… |
syllabusUrl, sourceUrl | links 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.
| Field | Default | Notes |
|---|---|---|
term | current term | ASU term code, e.g. 2267 = Fall 2026. Past terms work too. |
terms | — | Several 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. |
subjects | all | e.g. ["CSE","MAT"]. Empty means every subject. |
campus | all + online | Tempe, West Valley, Polytechnic, Downtown Phoenix, ASU Online, or campus-only |
maxItems | 0 (no limit) | Cap for a cheap trial run |
requestDelayMs | 600 | Politeness delay between requests |
includeRaw | false | Attach 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
seatsOpento catch a section opening up. - Schedule planning tools — days, times and rooms are what a conflict-checker needs.
- Enrollment demand research —
enrolled/capacityacross 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 installnpm run smoke # exercises the live API, no Apify platform neededapify 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.