Browse Instagram — Kittygram Skill
One path to Instagram data: Kittygram, a public, self-hostable, Nitter-style frontend. Read-only, no account, no app. Point-at-a-public-instance by default — see the self-hosting note at the bottom for when that calculus changes.
Routing
- Plain fetch (try first) — About/homepage-style pages and, on some instances, content pages too, serve cleanly with no challenge at all. Don't assume you need the solver — try the direct request first and only reach for it on a 401.
scripts/solve-pow.js(primary for content pages) — Most instances gate profile/post/search routes behind a small proof-of-work challenge. This script solves it. No browser needed for this specific challenge type — see "Why no browserless" below.- Next instance — If a given instance returns anything the solver doesn't recognize (see the
failure-mode table), don't debug it — move to the next instance in
references/instances.md. - web_search (last resort) —
web_search query="site:instagram.com <topic>". Snippets only, no full post content, but works when every instance is down.
URL Patterns
Kittygram mirrors Instagram's own URL scheme exactly — swap the domain, keep the path:
Profile instagram.com/<username> → <instance>/<username>
Post instagram.com/p/<shortcode> → <instance>/p/<shortcode>
Reel instagram.com/reel/<shortcode> → <instance>/reel/<shortcode>
Hashtag instagram.com/explore/tags/<tag> → <instance>/explore/tags/<tag>
Search (n/a) → <instance>/search?q=<query>
Fetching Content
node <skill-path>/scripts/solve-pow.js "https://kittygram.nexussfan.cz/<username>"
The script:
- Makes a plain GET.
- If it gets back HTTP 401 with an
X-Proof-Of-Work-Challengeheader (themod_pow_captchaformat), it grindsSHA256(challenge:nonce)until the hash has the required leading zeros — the same trivial computation the challenge page's own JS does, published openly by the operator, including a reference Perl one-liner for anyone without JS. This is difficulty-4 by default: tens of thousands of hash attempts, sub-second on any real CPU. - Retries with the solved cookie, returns the page body on stdout.
Exit codes: 0 success, 1 rate-limited (back off, don't switch instances for this one — see
below), 2 silent/opaque block (switch instances), 3 unrecognized response (switch instances).
Why no browserless (mostly)
Unlike Nitter's Anubis, Kittygram's mod_pow_captcha challenge is a plain hashcash-style puzzle
with no browser fingerprinting — the operator hands you the algorithm and expects scripts to
solve it. No headless Chrome required for this one. Caveat, found during testing: not every
instance uses this challenge. pussthecat.org runs go-away, a JS-based anti-bot gate (similar
spirit to Anubis) that this script can't solve — that one genuinely does need a browser. Treat
"solver returns exit code 3" as the signal to try the next instance rather than escalating to
browserless on the same one; only reach for browserless if you specifically need pussthecat.org
or another confirmed JS-gated instance and nothing scriptable is available.
Failure-mode table (what you'll actually see)
| Symptom | Meaning | Action |
|---|---|---|
HTTP 401 + X-Proof-Of-Work-Challenge header |
mod_pow_captcha gate |
Handled automatically by the script |
HTTP 200, content-length: 0, content-type: application/octet-stream |
Opaque IP-based block, no challenge offered | Switch instances |
| HTTP 503, title "Ratelimited | Kittygram" | That instance's own rate limit, independent of any PoW gate | Back off and retry that instance later; don't just hammer a different one with the same query |
HTTP 418 with a go-away cookie / JS challenge page |
JS-based anti-bot (not the PoW format above) | Needs a real browser — skip for scripted access unless you specifically need that instance |
robots.txt disallow |
Operator has asked automated clients to stay off | Respect it, switch instances |
Instance Selection
Read references/instances.md for the ranked list and what's confirmed to work. Start with
kittygram.nexussfan.cz — it's the only instance confirmed scriptable end-to-end at time of
writing. Refresh the list periodically per the procedure in that file; Kittygram instances are
volunteer-run and churn.
Important caveat on the reference table: it was built by testing from a cloud/datacenter IP, which is precisely the kind of source these anti-bot measures target. From Brandon's actual runtime (home IP via OpenClaw), behavior may well be better across more instances — re-verify before trusting the table as gospel, and update it if reality differs.
Etiquette
These are volunteer-funded instances — FSKY explicitly asks for donations to cover the VPN/proxy costs of running one. Fine for occasional lookups. If this becomes a recurring cron pulling the same accounts on a schedule, that's a materially different load pattern than what these instances are built to absorb — revisit self-hosting at that point rather than treating a shared community resource as your backend. (See prior conversation: self-hosting only helps if you also replicate the proxy/VPN rotation that keeps a public instance's rate-limit budget usable — otherwise you're just moving the same rate-limit fight onto your own IP, likely with worse results than an established instance with donor-funded proxy infrastructure.)
Known Limitations
- Only the first ~20 comments per post are fetchable.
- Stories aren't viewable on any instance yet.
- Kittygram is actively developed and explicitly labeled unstable (
v1.3.0-unstableas of this writing). Page structure and challenge formats can shift between versions — if fetches that used to work start failing everywhere at once, check codeberg.org/irelephant/kittygram for recent changes before assuming the skill itself is broken. - Instagram rate-limits server-side scraping aggressively at the source. If every instance is failing on the same query, that's more likely Instagram-side throttling upstream of Kittygram than a run of bad luck across instances — back off rather than instance-hopping indefinitely.
Last Resort: web_search
web_search query="site:instagram.com <topic>"
Snippets only, no full post content or comments, but works when everything above is down.