Backends¶
insto is split between command surface and backend. The backend is the only layer that touches a third-party API; everything above it consumes DTOs (Profile, Post, User, Comment, ...) and never sees a raw HikerAPI / aiograpi dict.
The contract lives in insto/backends/_base.py:OSINTBackend. Two implementations ship as of 0.2.0:
| hiker (default install) | aiograpi (insto[aiograpi]) |
|
|---|---|---|
| Authentication | API token | Username + password (+ 2FA) |
| Cost | Pay-per-call | Free |
| Account ban risk | None | Real |
| Stability | High | Brittle (Instagram churn) |
| Sees private accounts you follow | No | Yes |
| Sees DMs / saved feed | No | Yes (planned) |
| Quota visibility | Yes (/sys/balance) |
No |
| Install footprint | base | pip install 'insto[aiograpi]' |
Pick a backend¶
Default is hiker. Switch to aiograpi when you need data behind Instagram's login wall — private profiles you follow, saved feed, posts on accounts that 403 from logged-out HTTP. For OSINT on public profiles, hiker is the right choice nine times out of ten and carries no account-ban risk.
You can flip backends mid-session at any time by editing ~/.insto/config.toml (or running insto setup again):
backend = "aiograpi"
[hiker]
token = "hk_live_..." # kept around in case you flip back
[aiograpi]
username = "your.handle"
password = "..."
totp_seed = "JBSWY3DP..." # optional 2FA seed
session_path = "/Users/you/.insto/aiograpi.session.json"
Precedence is flag > env > toml > default for every key:
| Key | Flag | Env |
|---|---|---|
backend |
(no flag yet) | INSTO_BACKEND |
hiker.token |
--hiker-token |
HIKERAPI_TOKEN |
hiker.proxy |
--proxy |
HIKERAPI_PROXY |
aiograpi.username |
(no flag) | AIOGRAPI_USERNAME |
aiograpi.password |
(no flag) | AIOGRAPI_PASSWORD |
aiograpi.totp_seed |
(no flag) | AIOGRAPI_TOTP_SEED |
hiker — HikerAPI¶
Authenticates with a HikerAPI token. Pay-per-call, no Instagram login, no account-ban risk.
insto setup # token wizard
export HIKERAPI_TOKEN=hk_live_... # or env var
insto -c info instagram --hiker-token=hk_live_... # or per-call flag
What the backend handles:
- Quota & balance — read from
/sys/balanceon REPL startup and before every/quota. Surfaced in the welcome banner and the bottom toolbar. - Retries —
with_retrydecorator.RateLimited(withretry_after) andTransientretry with exponential backoff + jitter;AuthInvalid,QuotaExhausted,SchemaDrift,Bannedpropagate immediately. - Schema drift — every mapper raises
SchemaDrift(endpoint, missing_field)instead ofKeyErrorwhen HikerAPI's documented fields move. Counter shown in/health. - Cursor safety — every
iter_*method has a 1000-page hard cap so a server-side cursor loop cannot DOS the operator. - Proxy —
--proxy/HIKERAPI_PROXY/[hiker].proxyplumbed throughhttpx.socks5h://(Tor) supported.
HikerAPI 403¶
HikerAPI proxies Instagram's HTTP statuses verbatim — when a call returns 403, that's Instagram refusing the request, not HikerAPI billing or scope. You'll see this most often on:
/similar— Instagram refuses the suggested-users / chaining call for many target user_ids (locked-down accounts, country gating, anti-abuse heuristics). It works for some targets, 403s for others — the endpoint isn't dead, it's just per-target flaky.- Anything against an account that requires a logged-in session to read.
The fix is to switch to the aiograpi backend for that one command.
aiograpi — Instagram private API (logged-in)¶
Optional, install separately:
uv tool install 'insto[aiograpi]'
pipx install 'insto[aiograpi]'
pip install 'insto[aiograpi]' # in a venv only — see installation.md
Then run insto setup, pick aiograpi, paste your Instagram username + password, and (optionally) the TOTP seed for 2FA.
What works on aiograpi (≥ 0.8.0):
- Every command —
/info,/posts,/reels,/stories,/highlights,/followers,/followings,/mutuals,/comments,/captions,/likes,/wcommented,/hashtags,/mentions,/locations,/tagged,/similar,/dossier. - Reads private profiles you follow.
- Login is lazy — the constructor stores credentials, the actual
client.login()fires on the first network call. The session is then dumped to~/.insto/aiograpi.session.json(mode0600); subsequent runs reuse it without re-authenticating.
aiograpi 0.7 was missing chaining / fetch_suggestion_details (used by /similar); insto's [aiograpi] extra now requires aiograpi ≥ 0.8.0 so this is settled at install time.
Account-ban risk¶
aiograpi authenticates as a real Instagram user. Heavy use, fast scrapes, and especially /dossier runs against many targets in a row look like automation to Instagram's anti-abuse systems. Mitigations baked in:
/batchdefaults to concurrency 3 with 1s ± 25% jitter between target starts.RateLimitError,PleaseWaitFewMinutes, andClientThrottledErrortranslate toRateLimited(retry_after)and back off.AccountSuspendedandFeedbackRequiredtranslate to the typedBannederror so the CLI surfaces it cleanly instead of a stack trace.
For real OSINT work, use a dedicated burner account — never your personal Instagram. Insto's defaults are conservative, but Instagram's rules are theirs to enforce.
2FA (TOTP)¶
If your account has 2FA enabled, paste the TOTP seed (the 32-char base32 string Instagram shows when you set up an authenticator app) during insto setup. aiograpi will generate the 6-digit code on demand. Insto stores the seed in ~/.insto/config.toml (mode 0600) and registers it with the global redaction set so it never reaches error output or the rotating log file.
Don't have the seed? Either re-enable 2FA in Instagram's settings to capture it, or skip 2FA on the burner account.
Visibility states¶
Profile.access is one of:
| State | hiker | aiograpi |
|---|---|---|
public |
✓ | ✓ |
private |
✓ | ✓ |
followed |
n/a | ✓ (private profile you follow) |
blocked |
n/a | ✓ (only via aiograpi error response) |
deleted |
✓ | ✓ |
Commands that strictly need a logged-in account (DMs, saved feed, posts of a private profile you follow) carry a requires=("followed",) annotation. They run cleanly on aiograpi; on hiker they exit with a typed message.