Changelog¶
All notable changes to insto. Format follows Keep a Changelog; versioning follows SemVer. Entries from 0.1.1 onward will be assembled from Conventional Commits by release-please.
0.7.3 (2026-04-29)¶
Documentation¶
- HikerAPI free-trial promo link (100 requests, no card) (a1bbaed)
0.7.2 (2026-04-29)¶
Documentation¶
- OSINT recipes page โ 7 multi-step investigative scenarios (e776d4c)
- refresh demo.gif (/info + /where + /fans) + Killer features page (df556b0)
[0.7.1] - 2026-04-29¶
Added¶
/where <user>๐ฅ โ geo-fingerprint analytic. Walks the target's recent posts, extracts GPS coordinates from every geotag, computes the anchor (most-frequent place โ proxy for "where they live or work"), the centroid (arithmetic mean of all geotag points), and the spread radius (max haversine distance from centroid). Top-N places rendered as a horizontal bar chart. On @ferrari (15/30 posts geotagged): anchor = Maranello (47%), centroid in N. Italy, max radius 9.5k km โ Maranello is HQ, the rest is racing circuits and ski trips.Post.location_lat/Post.location_lngfields. The IG payload always carried these but the mappers were dropping them. Now extracted by both backends; new_opt_floathelper handles NaN / coercion errors. Snapshot serialisation is unaffected (snapshot diff already serialised the whole Post viadataclasses.asdict).
Changed¶
- Command surface table in the README marks ๐ฅ killer-feature commands so newcomers can immediately spot the OSINT-unique primitives (
/dossier,/where,/intersect,/fans,/place,/placeposts,/postinfo,/search,/timeline) vs the trivial wrappers. /locationsmoved from "Content" group to a new "Geo" group alongside/where,/place,/placepostsโ they all answer "where" rather than "what about the captions".
[0.7.0] - 2026-04-29¶
Added โ five new OSINT commands¶
/place <query>โ search Instagram places by free text (e.g.Tbilisi,Eiffel Tower). Returns matched locations with name + GPS + IG location pk, plus a hint to/placepostsfor posts at that place. CSV / JSON / Maltego (maltego.GPS) export./placeposts <pk>โ top posts at a given Instagram location pk. Reveals who, what, when at a place โ the geo-OSINT primitive. Pairs with/placeto find the pk./postinfo <ref>โ resolve a media reference (full URL / shortcode / numeric pk) to the full Post DTO. Caption, owner, taken_at, hashtags, mentions, location, media URL. Evidence collection: paste a permalink, get metadata. No active target needed./pinned <user>โ list the target's pinned posts (Instagram caps at 3). What the account wants you to see first./reposts <user>โ posts the target has reposted (IG's repost surface). Reveals amplification network. HikerAPI only; aiograpi has no equivalent yet.
Added โ DTO¶
Placeโ newdataclassfor IG locations:pk,name,address,city,lat,lng,facebook_id. Returned bybackend.search_places, consumed bybackend.iter_place_posts.
Backend ABC¶
- Five new methods:
iter_user_pinned,iter_user_reposts,get_post_by_ref,search_places,iter_place_posts. Default implementations raiseNotImplementedErrorso third-party backends extendingOSINTBackendkeep compiling. HikerAPI implements all five; aiograpi implements four (no reposts).
[0.6.2] - 2026-04-29¶
Fixed¶
- Spinner no longer overlaps the rich Panel on commands that print straight to stdout (
/info,/about,/resolve, ...). Two changes: (1)ctx.printnow stops the spinner before writing, so any first user-facing output cleans the spinner line; (2)_stop_spinnererases the line synchronously instead of waiting for the spinner loop's next tick, so a fast follow-up panel doesn't render on top of a half-painted frame.
[0.6.1] - 2026-04-29¶
Added¶
/about <user>โ surface the raw IGuser_aboutpayload as its own command (joined date, country, former usernames, verified flag). Cheaper than/info(one fewer call) and JSON-exportable for pipelines that want only this slice./infoshows the avatar URL as an OSC-8 hyperlink ("open"); modern terminals (iTerm2, kitty, Apple Terminal) make it clickable. The full signed CDN URL is hidden behind the link so the panel stays tidy. Hint to/propicfor offline downloads./infosurfaces moreuser_aboutfields:created(account-joined date),former usernames. Were silently dropped before because the renderer was looking for the wrong keys.
[0.6.0] - 2026-04-29¶
Added¶
/intersect <a> <b>โ followers(@a) โฉ followers(@b). New OSINT primitive: shared audience between two targets reveals communities, staff, family, PR networks. Both follower fetches run concurrently (different pks so the backend serves in parallel). Default window 1000 per side;--limit Nto widen,--limit 0for unbounded. Maltego export uses{a}_{b}as a synthetic target dir so the file colocates with other artifacts./timeline <user>โ posting cadence histogram. 24-bucket hour-of-day sparkline + 7-bucket day-of-week bar chart over the last N posts. Reveals timezone (sleeping hours), human vs scheduler-driven posting, weekday vs weekend rhythm. UTC-bucketed; JSON export carries the raw bucket arrays for further analysis.- /dossier section progress bar โ 9-step tqdm bar that ticks once per section completes. Pairs with the v0.5.5 spinner: spinner runs during pre-flight, hands off to the bar once sections start.
insto setup --non-interactiveโ config wizard driven entirely by env vars + existing config without prompts. Errors loudly when a required field is missing. Pattern for CI / automation:INSTO_BACKEND=hiker HIKERAPI_TOKEN=$T insto setup --non-interactive.
Performance¶
/fans,/wliked,/wcommentedare ~5ร faster. Per-post fan-out now usesasyncio.Semaphore(5)+asyncio.as_completedinstead of a serial loop./fans @nasa --limit 5drops from ~17 s to 8.5 s on the same backend response time. Concurrency cap is conservative re: HikerAPI's 7-15 rps per-account limit and aiograpi's per-session throttle. Order-independent (Counter aggregation) soas_completedis safe.
Documentation¶
- Command surface now renders as a 10-row table (group / commands / one-line description) instead of a paragraph list. Easier to skim when you want to know what's in
/fansvs/recommendedvs/intersect. - One-shot examples in the README cover the new commands (
/search,/fans,/recommended,/intersect,/timeline). INSTO_BACKENDenv-var description backfilled (the prior text said "set tofakefor the e2e suite" โ it's been acceptinghiker/aiograpifor a year).
[0.5.5] - 2026-04-29¶
Added¶
- Spinner on stderr during command execution โ pipx-style Braille wheel that paints
โขฟ fans...while the backend call sequence runs, before the per-post tqdm bar (or instead of it, for commands like/info//resolve//recommendedthat don't have a per-iteration loop). Auto-stops whentrack()starts a tqdm bar (tqdm reuses the same line). Honours--no-progressand auto-suppresses on non-TTY. Closes the silent-pause-then-output gap that made commands feel hung even on fast networks.
Fixed¶
/theme<Tab>selecting a choice now actually inserts/theme instagraminstead of/themeinstagram. v0.5.4's leading-space approach turned out to drop the space on some prompt-toolkit code paths; v0.5.5 yields the choices as full-token replacements (text="/theme instagram",start_position=-len("/theme")) so prompt-toolkit's apply step deletes the typed/themeand inserts the complete/theme instagram. Bulletproof regardless of which apply path the menu uses.
[0.5.4] - 2026-04-29¶
Fixed¶
- v0.5.3 fixed
/theme<Tab>to show the theme choices inline, but accepting one produced/themeinstagram(no separator) โ prompt-toolkit inserted the completion at the cursor without the implicit space. Now the choices include a leading space in their completion text, so/theme<Tab>โ arrow toinstagramโ Enter produces/theme instagram.
[0.5.3] - 2026-04-29¶
Fixed¶
- Slash popup now yields argument choices for the typed-exactly command without requiring a trailing space. Before: typing
/themeand pressing Tab only re-inserted/themeitself; you had to type a space to getclaude/instagram/aiograpi. After:/theme<Tab>shows the themes inline. Same for/purge(history / snapshots / cache).
[0.5.2] - 2026-04-29¶
Added¶
- Progress bars on long-running aggregation commands (
/fans,/wliked,/wcommented). tqdm-based, writes to stderr so JSON / CSV stdout stays clean. Auto-suppresses on non-TTY (CI logs, piped invocations) without configuration; manual override via the new--no-progressglobal flag. - New dependency:
tqdm >= 4.66. Same patterninsta-dluses for download progress.
Why¶
/fans --limit 50 makes 100 backend round-trips per invocation โ easily a minute of silent waiting. The bar shows ETA + per-step rate, which is what operators actually need to decide between "wait" and "Ctrl-C, narrow the window".
[0.5.1] - 2026-04-29¶
Added¶
--backend {hiker,aiograpi}global flag โ per-invocation backend override. Sameflag > env > toml > defaultprecedence the rest of the config uses, soINSTO_BACKEND=โฆand[backend]inconfig.tomlkeep working.
Changed¶
/fansoutput now uses โค๏ธ / ๐ฌ emoji for the per-channel breakdown instead of the cryptic2L+0Cshorthand. Both the table column ((โค๏ธ3 ๐ฌ0)) and the Maltego Notes field (โค๏ธ2 ๐ฌ3). Easier to read at a glance and survives copy-paste into chat / docs.
[0.5.0] - 2026-04-29¶
Added¶
/wlikedโ top likers across the active target's recent N posts. Symmetric to the existing/wcommented(which counts commenters). One post-window pull, one likers call per post; default window 50, customisable via--limit. Flat-row CSV / JSON / Maltego export โ same shape as/wcommented. Both backends (uses the existingiter_post_likersABC)./fansโ composite ranking of likers + commenters as a single "superfans" view. Score =likes + 3*comments(a comment is ~3x more effortful than a tap-to-like). Output table shows score with the breakdown (11 (2L + 3C)); JSON envelope, CSV withrank,user,likes,comments,scorecolumns, and Maltego CSV with score-as-weight and"2L+3C"-style Notes for human-readable Maltego node labels.- New analytics primitives:
count_wliked(mirrorscount_wcommentedfor likers),count_fans(composes both into a weighted ranking),FanRowandFansResultdataclasses.
Performance / cost notes¶
/fansmakes2Nbackend calls per invocation (one likers + one comments call per post). On the default 50-post window that's 100 backend round-trips per/fansrun โ pass--limit 10for cheaper sampling. /wliked is half that cost (just likers).
[0.4.0] - 2026-04-29¶
Added¶
/resolve <url>โ expand an Instagram short-link (instagram.com/share/...) to its canonical URL via a HEAD request through the logged-in session. aiograpi only; HikerAPI raises a clear "switch backend" error./audio <track_id>โ list clips that use a given audio asset, with full Post DTOs (code, taken_at, owner). Both backends โ hiker viatrack_by_id_v2, aiograpi viatrack_info_by_id. Bypasses the preview-onlytrack_stream_*surface that returned skeleton media (nocodefield, breaks/post-style integrations)./recommendedโ IG's category-based account recommendations for the active target. aiograpi only (the surface needs a logged-in session). For@ferrarireturns 30 automotive-category accounts (Porsche creators, etc.).
All three commands route their results through the existing JSON / CSV / Maltego export pipeline โ /recommended --maltego writes recommended.maltego.csv with maltego.Person rows.
Changed¶
[aiograpi]extra now requiresaiograpi >= 0.8.5(unchanged in this release; the wave-2 endpoints all landed in the 0.8.x series).- New
OSINTBackendABC methods:resolve_short_url,iter_audio_clips,get_recommended. Default implementations raiseNotImplementedErrorso third-party backends extending the ABC don't need to implement everything to keep compiling.
[0.3.0] - 2026-04-29¶
Added¶
/search <query>โ find Instagram accounts by free-text query (username, brand, location, etc). New top-level command with--limit,--csv,--json, and--maltegoexports. Works on both backends viafbsearch_accounts_v2(HikerAPI 0.1.0+ / aiograpi 0.8.1+). Big OSINT win: insto could already drill into a known target, but couldn't discover unknown handles by name./searchcloses that gap./similarfallback chain on aiograpi โ when the primarychaining()private endpoint refuses a target ("Not eligible for chaining" / 403), insto now falls through touser_related_profiles_gql(public-graphqledge_chaining). Live test:@ferrarireturns 80 suggestions on aiograpi, where the equivalent hiker call 403s. Needs aiograpi โฅ 0.8.5.resolve_targetfallback on aiograpi โ when the publicuser_id_from_usernamepath JSON-decode-fails (HTML challenge, intermittent gating), insto retries throughuser_web_profile_info_v1(private-host route, carries the logged-in session). Same target, more reliable plumbing.
Changed¶
[aiograpi]extra now requiresaiograpi >= 0.8.5(was>= 0.8.0) โ the release that landedfbsearch_accounts_v2,user_related_profiles_gql, anduser_web_profile_info_v1. Settled at install time.- aiograpi-side
chainingandfbsearch_accounts_v2responses are now run throughaiograpi.extractors.extract_user_shortbefore the insto mapper. The SERP / chaining endpoints return raw IG dicts (pk_id/idinstead ofpk); the upstream extractor reconciles them. Without this wrap, every/similarand/searchrow crashed withSchemaDrift: missing field 'pk'.
[0.2.2] - 2026-04-29¶
Added¶
tests/live/smoke.pyโ structured live smoke against the real HikerAPI, eight REQ checks + one OPT (/similar). Skips with exit 0 whenHIKERAPI_TOKEN_TESTis unset, so it's safe in any release-prep gate. Costs ~10 calls, single-digit cents. SeeCONTRIBUTING.md./healthobservability โ extends the existing quota / drift output with per-call latency p50/p95/max, cumulative call count, and a breakdown ofBackendErrorsubtypes seen this session. Instrumented at the_callboundary in both backends; latencies are kept in a 1000-slot ring (~8 KB)./dossier --maltegoโ promised in the README since v0.1, finally implemented. Each maltego-eligible section (followers, following, mutuals, hashtags, mentions, locations, wcommented, wtagged) writes a.maltego.csvwith the standardType, Value, Weight, Notes, Propertiesshape; profile.json + posts.json keep their JSON form. Verified live on both hiker and aiograpi backends.
Fixed¶
iter_hashtag_postswas silently broken on the real HikerAPI: hashtag responses useresponse.sections[*].layout_content.medias[*].media, not the genericusers/items/commentskeys, and the cursor at the top level isnext_page_id(a base64 envelope), not the innernext_max_id(a hex string the server rejects). The live smoke caught this โ mocks always passed because the fakes mirrored the wrong shape.
[0.2.1] - 2026-04-28¶
Added¶
/taggedand/similarnow work on the aiograpi backend. The first viausertag_medias_v1(already in aiograpi 0.7 โ the previous "not exposed" stub was wrong), the second via the freshly-landedchaining+fetch_suggestion_detailsin aiograpi 0.8.0. All 14OSINTBackendmethods now land on both backends.
Changed¶
[aiograpi]extra now requiresaiograpi >= 0.8.0(was>= 0.7.2) โ the upstream release that adds the chaining endpoints.aiograpi.exceptions.InvalidTargetUser("Not eligible for chaining.") is mapped to a clearBackendError("target not eligible: ...")instead of falling through to a generic transient.
Documentation¶
docs/backends.mdmatrix simplified โ no per-backend gaps remain. The "HikerAPI 403" note now correctly describes/similaras per-target flaky (Instagram refuses chaining for some user_ids), not "endpoint retired".
[0.2.0] - 2026-04-28¶
Added¶
AiograpiBackendover aiograpi 0.7.2, gated behind the newinsto[aiograpi]optional install. Login is lazy, session persists to~/.insto/aiograpi.session.json(mode0600). 12 of the 14OSINTBackendmethods land on this backend โ only/similar(endpoint retired upstream) and/tagged(aiograpi 0.7 has nouser_tag_medias) refuse with a clear "needs hiker backend" error.Configgainedbackend,aiograpi.username,aiograpi.password,aiograpi.totp_seed,aiograpi.session_pathkeys. Sameflag > env > toml > defaultprecedence;passwordandtotp_seedregister with the global redaction set so they never reach error output or rotating logs.- Setup wizard now asks
backend (hiker | aiograpi)first and only prompts for the credentials relevant to that backend. Existinghiker.tokenandaiograpiblock are preserved when you flip backends. make_backend("aiograpi", ...)โ lazy import; if the user did not installinsto[aiograpi], returnsRuntimeErrorwith the exactpip / uv / pipx install 'insto[aiograpi]'command.- Per-command argument completion in the slash popup:
/theme<Tab>listsaiograpi / claude / instagram;/purge<Tab>listshistory / snapshots / cache. Mechanism walks the command's argparsechoices=automatically โ every future command withchoicesgets completion for free. - Slash popup keeps re-rendering across the entire first-token typing (
/,/i,/in,/info) by binding every command-name character explicitly, socomplete_while_typing's debounce window does not flicker the popup. /helpand the slash popup show positional-argument signatures (/theme [name],/posts [count],/batch <file> <cmd>).- Three named themes (
/theme):claude(Claude Code burnt orange),instagram(Instagram 2022+ conic gradient),aiograpi(purple โ blue with violet accent โ default since 0.2.0). The figlet INSTO logotype renders per-row gradient on themes that define one.
Changed¶
- Default theme is now
aiograpi. Existing users withtheme = "..."in~/.insto/config.tomlare unaffected. - HikerAPI 403 is mapped to a clearer message โ Instagram returns 403 to login-walled / region-restricted endpoints, not "your account is banned". The
Bannedexception now carries the diagnosis without the misleadingbackend account is banned:prefix. - Welcome banner reads the live backend label from the class name (
hiker/aiograpi) instead of the hard-codedhiker ยท ...literal.
Fixed¶
Ctrl+Cin the REPL cancels the current line and re-prompts (shell / IPython convention) instead of exiting.Ctrl+Don an empty line still exits./theme instagramnow actually paints the figlet rows in the brand gradient โ the previous fix used a Rich style string Rich could not parse ("bold logo.0"with a dotted theme key).
Documentation¶
docs/backends.mdrewritten to cover both backends + the install matrix.- README updated for
pip install 'insto[aiograpi]'and the new welcome screenshot.pip installPEP 668 trap explained.
[0.1.1] - 2026-04-28¶
Fixed¶
_hiker_mapnow accepts ISO-8601 strings (2026-04-17T17:45:12Z) fortaken_at/created_at/expiring_atin addition to unix integers. HikerAPI'suser_medias_chunk_v1returns the ISO shape, so/posts,/dossier,/reels,/taggedwere previously raisingSchemaDrifton every live call.- REPL welcome banner now refreshes the HikerAPI balance synchronously before render, so the bottom toolbar shows real numbers ("14.7M requests left ยท $4,417 ยท 15 rps cap") on first paint instead of "balance: pending".
- Setup wizard resolves
output_diranddb_pathto absolute paths, so behaviour no longer depends on the CWD whereinstois later invoked.
Added¶
- Inline target on every single-target slash command (
/info instagram,/posts instagram,/dossier instagram...) without mutating the active session target. - Slash popup styling: typing
/opens a Claude-Code-like popup of all commands with help-text in the right column.complete_style=COLUMN,reserve_space_for_menu=10, dedicated dark-slate Style for the menu. /info-style commands now thread an optional positionaltargetthroughwith_target/with_pkvia the newadd_target_argandcompose_argshelpers incommands/_base.py.- Setup wizard prompt for proxy now lists supported schemes inline:
proxy URL (http://, https://, socks5h://) (optional, '-' to clear).
Changed¶
- Welcome banner: replaced the chafa pixel-art wasp with a typographic INSTO logotype (figlet "standard") plus the tagline
i n s t o โ o s i n t ยท instagram tool ยท open-source intel. No image deps, identical rendering on light and dark schemes, no third-party watermark to mask. Quotamodel gainedrate,amount,currencyfields populated from/sys/balance.HikerBackend.refresh_quota()is the new entry point;/quotaalways re-fetches before rendering.
Documentation¶
- Full mkdocs Material site at https://subzeroid.github.io/insto/ โ index, installation, basic-usage, cli-reference, backends, architecture, troubleshooting, contributing, changelog.
- LICENSE (MIT), CHANGELOG.md, SECURITY.md, CONTRIBUTING.md added at the repo root.
pyproject.tomlpopulated with classifiers, keywords, project URLs, and[docs]extras.
CI¶
release.ymlโ tag-driven build + trusted-publish to PyPI + GitHub release.release-please.ymlโ Conventional Commits โ CHANGELOG automation.docs.ymlโ mkdocs deploy to GitHub Pages onmain.pr-title.ymlโ semantic PR title gate.
[0.1.0] - 2026-04-27¶
Added¶
Initial public release.
- Interactive REPL (
insto) with prompt_toolkit completer (slash popup of commands, like Claude Code), bottom toolbar (active target ยท backend ยท live HikerAPI balance + rate cap), Ctrl+T / Ctrl+L keybindings, history at~/.insto/cli_history. - One-shot CLI (
insto @user -c <cmd> [args]) with the same command grammar; works in shell pipelines via--json -/--csv -to stdout and/batch -from stdin. - Slash-command surface across seven groups:
- Target โ
/target,/current,/clear - Profile โ
/info,/propic,/email,/phone,/export - Media โ
/stories,/highlights,/posts,/reels,/tagged - Network โ
/followers,/followings,/mutuals,/similar - Content analysis โ
/locations,/hashtags,/mentions,/captions,/likes - Interactions โ
/comments,/wcommented,/wtagged - Operational โ
/quota,/health,/config,/purge,/help /dossierkiller-feature: collects info + posts + followers + following + mutuals + hashtags + mentions + locations + wcommented + wtagged into one structured directory underoutput/<user>/dossier/<datetime>/with aMANIFEST.mdsummary. Sections fan out viaasyncio.gatherand tolerate partial completion onQuotaExhausted./batchwith concurrency cap, jittered per-target sleep, stdin support, dedup, JSONL resume onoutput/.batch-<sha>.jsonl, and graceful exit onQuotaExhausted./watchin-session monitoring (max 3 active, โฅ 5 min interval, paused after 2 consecutive errors,patch_stdoutnotifications).OSINTBackendABC with lazy backend imports.HikerBackendfor v0.1; aiograpi planned for v0.2 โ requirement annotations (requires=("followed",)) already in place.- Hardened CDN streamer: host allowlist, HTTPS-only, no cross-host redirects, MIME cross-check, byte budget (per-resource and per-command), atomic write, collision suffix, disk guard, macOS xattr tagging.
- sqlite-backed history / snapshots / watches at
~/.insto/store.db(mode0600) with retention prune, schema versioning,BEGIN IMMEDIATEmigration lock. - OPSEC:
--proxy/HIKERAPI_PROXY(Tor / corp proxy),_redact_secretsstrips tokens from errors and rotating-file log (~/.insto/logs/insto.log). - Maltego CSV exporter (
--maltego/--output-format maltego). - Shell completion via
insto --print-completion {bash|zsh}(requiresinsto[completion]).
Notes¶
- Secret redaction covers stack traces, log files, and CLI error output.
- All 24 OSINT commands accept an inline target argument (
/info instagram) without mutating the active session target.