Install
openclaw skills install @chrischall/artsonia-apiAccess Artsonia (artsonia.com) student-art portfolios, comments, fans, teacher feedback, and downloads from a shell with curl instead of running the artsonia-mcp server — log in with a username/password form POST to get a session cookie, then curl the server-rendered member pages. Use when you want Artsonia data without the MCP, in a script, or on a machine where the MCP isn't installed.
openclaw skills install @chrischall/artsonia-apiArtsonia is a classic server-rendered .asp site — no public API, no JSON
store, no bot wall. All the data (students, portfolios, comments, fans,
feedback, awards, profile) lives in server-rendered HTML, and auth is a real
username + password form POST that hands back an HttpOnly session
cookie. No browser, no Transporter extension, no fpx bridge is needed —
curl with a cookie jar reaches everything a signed-in parent account can.
(The MCP keeps @fetchproxy/server as an optional fallback transport for
some future walled endpoint, but nothing documented here needs it.)
This is the same data the artsonia_* MCP tools return, reached with curl
instead of a running server.
export ARTSONIA_USERNAME=you@example.com
export ARTSONIA_PASSWORD='your-password' # or: op read "op://Private/Artsonia/password"
JAR=~/.cache/artsonia-cookies.txt
mkdir -p ~/.cache # ensure the jar's directory exists on a fresh box
: > "$JAR" # fresh jar
Read the password from stdin (Password@-) instead of putting it on the
command line — --data-urlencode name=value puts value in curl's argv,
which any local user can read via ps//proc while the process runs. This
mirrors how the MCP itself sends the password: only in the POST body, never
on a command line.
printf '%s' "$ARTSONIA_PASSWORD" | curl -s -c "$JAR" -b "$JAR" -L \
--data-urlencode "Username=$ARTSONIA_USERNAME" \
--data-urlencode "Password@-" \
--data-urlencode "TargetUrl=/members/" \
--data-urlencode "Action=login" \
-o /tmp/artsonia-login.html -w '%{http_code} %{url_effective}\n' \
https://www.artsonia.com/members/login.asp
A successful login redirects away from login.asp (final URL ends in
.../members/) and leaves cookies in $JAR. If url_effective still ends
in login.asp, or /tmp/artsonia-login.html matches You need to log in|Parent \(or Fan\) Login, the credentials are wrong — Artsonia has no
CSRF/__VIEWSTATE token, so a bad login is the only reason this fails.
Magic-link-only accounts can't use this (there's no password to POST).
Re-run this exact command any time a later request looks logged-out (see
"Session expiry" below) — curl -c overwrites the jar with a fresh session.
Every read is a GET through the jar; every write is a form-urlencoded
POST through the jar. Fetch to a file, then extract:
curl -s -b "$JAR" -c "$JAR" 'https://www.artsonia.com/members/' -o /tmp/dash.html
For the numeric ids every other endpoint needs (artist_id, artwork_id),
a plain regex on the href is enough and needs no extra tooling:
grep -oP '(?<=portfolio\.asp\?id=)\d+' /tmp/dash.html | sort -u
For the full structured fields (name, school, stats, notifications, awards,
…) don't re-derive selectors by hand — this repo already ships a
live-verified node-html-parser scraper (src/parse.ts → built
dist/parse.js) with one function per page. Build it once, then import it
in a one-liner and pipe the JSON to jq:
cd ~/git/artsonia-mcp && npm install && npm run build # once, if dist/ is missing
node --input-type=module -e "
import { readFileSync } from 'node:fs';
import { parseStudents } from '$(pwd)/dist/parse.js';
console.log(JSON.stringify(parseStudents(readFileSync('/tmp/dash.html', 'utf8'))));
" | jq '.'
references/endpoints.md has the ready-to-run curl command, dist/parse.js
import, and jq projection for every read and write tool, keyed to the same
paths and selectors the MCP uses.
Every per-student/per-artwork endpoint needs a numeric id you can only get from a parent call — never guess one:
GET /members/ → .artist-card → artist_id (from each card's
portfolio.asp?id= link).GET /artists/portfolio.asp?id=<artist_id> → .grid-item that contains
an art.asp link → artwork_id.Artsonia expires a session by redirecting/rendering back to the login page, not a 401. After any GET/POST, check the response body:
grep -qE 'login\.asp|You need to log in|Parent \(or Fan\) Login' /tmp/out.html \
&& echo "EXPIRED — re-run the login step"
GET the page you just changed
and confirm the field actually flipped before trusting a write.value=Y, never on. Sending Field=on is
silently ignored by the server (still 302s, saves nothing)./members/profile/
(#TheForm) bundles name/email/password/opt-ins in one form — re-POST
every current field verbatim (blank the password fields, keep
DidChangePassword=N), flipping only the one you're changing.OldPassword/NewPassword/
NewPassword2 blank/omitted.See references/endpoints.md for the exact body of every write, and how to
re-read and verify each one.
Full-resolution images live on a public CDN — no cookie required, even for private pieces:
curl -s -o "$artwork_id.jpg" "https://images.artsonia.com/art/full/$artwork_id.jpg"
curl -sI "https://images.artsonia.com/art/full/$artwork_id.jpg" | grep -i last-modified # per-artwork upload date
Resolutions (small→large): small medium large xlarge full.
www.artsonia.com);
nothing here needs the fetchproxy/browser-bridge path the MCP keeps as
an optional fallback./museum/art.asp is unverified upstream (both
captured accounts had 0 comments) — references/endpoints.md flags it.