A .NET 10 CLI, distributed as a dotnet global tool, for exporting your data
out of ClassDojo. Commands are added incrementally under one base app, e.g.
classdojo-export export-multimedia, classdojo-export export-homepage
(future).
dotnet tool install --global ClassDojoExport(See "Releasing" below if it's not published yet — you can also build from source in the meantime, per "Building/testing locally".)
classdojo-export export-multimedia --student-id <student-id> --export-folder <export-folder>Downloads every image/video attachment from a student's ClassDojo story feed
into <export-folder>, laid out as:
index.html— an offline-viewable page recreating the story feed (text, tags, photos/videos with poster thumbnails, sender/commenter avatars, and comments) so you can browse it later without ClassDojo or an internet connection. A "Show: All / Student / School" dropdown (top-right) filters between individual/portfolio posts about your child ("Student") and general class/school-wide posts ("School"). Comments are fetched with one extra request per commented-on post — only "class"-scoped posts support comments, so school-wide announcements are skipped for that step.photos/— every downloaded image/video, referenced byindex.html.metadata/post_metadata.json— one entry per post (sender, class, body text, tags, like/comment counts, timestamps, whether it's a private/individual post about your child vs. a general class/school post, and which file inphotos/each attachment was saved as).metadata/manifest.json— maps attachment IDs to the file they were saved as, so re-running the command later only downloads new posts.metadata/log.txt— timestamped run history and full error details, since the console output itself isn't saved anywhere once the terminal closes.metadata/media/— sender/commenter avatar images referenced byindex.html(not part of the regular attachment download).metadata/video_candidates.json— only created if an attachment looks like it might be a video by some heuristic (type, contentType, file extension, or an unrecognized JSON field mentioning "video") that isn't already handled. Confirmed video attachments (type: "video") download and render normally; this file exists as a safety net for any future/unusual shape.
Finding the student ID: open https://home.classdojo.com/#/story/student/{studentId}
in a browser for the child you want to export — the ID in that URL is what
the command expects.
Date filtering: pass --start/--end (either or both) to limit which
posts are included, e.g. --start 2026-01-01 --end 2026-05-20. A bare date
(no time-of-day) is inclusive on both ends — --end 2026-05-20 includes
everything posted that day, not just up to midnight.
Resuming after a failure: on a large export, a single flaky connection
to ClassDojo's CDN is retried automatically (a few attempts with a short
backoff) before giving up on that one file. If the whole run does die
partway through, metadata/manifest.json is saved after every successful
download (not just at the end), so simply running the same command again
picks up where it left off instead of re-downloading everything.
The first time you run any command, a real Chromium window opens to
ClassDojo's login page (installing Chromium first if needed — a one-time
~150MB download). Log in normally (this handles 2FA/captcha since it's a
real browser), then switch back to the terminal and press Enter. Session
cookies are cached to %AppData%\ClassDojoExport\session.json and reused on
future runs until ClassDojo expires them, at which point you'll be prompted
to log in again automatically.
Pass --force-login to any command to ignore the cache and log in fresh.
cd src/ClassDojoExport
dotnet pack -c Release -o ./nupkg
dotnet tool install --global --add-source ./nupkg ClassDojoExportTo pick up code changes and try them immediately, use
update-and-run.cs from the repo root — a file-based
C# program (dotnet run <file>.cs, no project needed) that uninstalls,
rebuilds, and reinstalls the global tool, then runs it with whatever
arguments you pass after --:
dotnet run update-and-run.cs -- export-multimedia --student-id <student-id> --export-folder <export-folder>.github/workflows/publish-nuget.yml
publishes to nuget.org automatically, using Trusted Publishing
(OIDC) instead of a stored API key — GitHub Actions proves its identity to
nuget.org per run and gets back a 1-hour API key, so there's no long-lived
secret to leak or rotate. One-time setup:
- On nuget.org, go to your username menu → Trusted Publishing → add a
policy:
- Repository Owner:
dochoffiday - Repository:
ClassDojoExport - Workflow File:
publish-nuget.yml(just the filename, not the.github/workflows/path) - Environment: leave blank (this workflow doesn't use one)
- Repository Owner:
- In the GitHub repo, go to Settings → Secrets and variables → Actions →
New repository secret, name it
NUGET_USER, and set it to your nuget.org username (the profile name, not your email). - The policy starts in a 7-day "pending" state until the first successful publish locks it to this specific repo (prevents someone else recreating a deleted repo of the same name later and hijacking the policy). If it expires unused, just restart the 7-day window from the same page.
Not seeing "Trusted Publishing" as an option on nuget.org yet? Microsoft is
rolling it out gradually — fall back to a scoped API key (API Keys →
Create, glob ClassDojoExport*) stored as a NUGET_API_KEY secret, and
swap the workflow's push step back to --api-key ${{ secrets.NUGET_API_KEY }}.
To publish a new version, push a tag:
git tag v0.2.0
git push origin v0.2.0The workflow packs with that version (stripping the v) and pushes to
nuget.org. You can also trigger it manually from the Actions tab
(workflow_dispatch) and type the version in by hand.
- The
storyFeedJSON schema is inferred from community scripts, not official docs, so unrecognized fields are ignored rather than causing failures — but ClassDojo could change the shape of the response at any time. - Nothing here is affiliated with or endorsed by ClassDojo. Use only on accounts/students you have the right to export data for.