{"id":49410532,"url":"https://github.com/subzeroid/insto","last_synced_at":"2026-05-27T22:00:46.370Z","repository":{"id":354275679,"uuid":"1221979568","full_name":"subzeroid/insto","owner":"subzeroid","description":"Interactive Instagram OSINT CLI with pluggable HikerAPI and aiograpi backends","archived":false,"fork":false,"pushed_at":"2026-05-27T12:41:18.000Z","size":3115,"stargazers_count":19,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T14:24:35.675Z","etag":null,"topics":["aiograpi","analysis","cli","hikerapi","information-gathering","instagram","instagram-account","instagram-api","instagrapi","intelligence","maltego","open-source-intelligence","osint","osint-python","prompt-toolkit","python","repl","social-media"],"latest_commit_sha":null,"homepage":"https://subzeroid.github.io/insto/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/subzeroid.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-26T23:21:12.000Z","updated_at":"2026-05-27T12:40:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/subzeroid/insto","commit_stats":null,"previous_names":["subzeroid/insto"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/subzeroid/insto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subzeroid%2Finsto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subzeroid%2Finsto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subzeroid%2Finsto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subzeroid%2Finsto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/subzeroid","download_url":"https://codeload.github.com/subzeroid/insto/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subzeroid%2Finsto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33585203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aiograpi","analysis","cli","hikerapi","information-gathering","instagram","instagram-account","instagram-api","instagrapi","intelligence","maltego","open-source-intelligence","osint","osint-python","prompt-toolkit","python","repl","social-media"],"created_at":"2026-04-29T00:04:37.790Z","updated_at":"2026-05-27T22:00:46.348Z","avatar_url":"https://github.com/subzeroid.png","language":"Python","funding_links":[],"categories":["Social Media Tools"],"sub_categories":["[↑](#-table-of-contents) Instagram"],"readme":"# insto\n\nInteractive Instagram OSINT CLI on the [HikerAPI](https://hikerapi.com/p/6k1q1388) backend and [aiograpi](https://github.com/subzeroid/aiograpi) lib.\n\n![demo](docs/demo.gif)\n\n## Design choices\n\n- **HikerAPI is the default backend, not a side mode.** Quota balance is read on REPL startup and surfaced in the bottom toolbar; `with_retry` honours `RateLimited.retry_after`; every mapper raises typed `SchemaDrift(endpoint, missing_field)` when HikerAPI's documented fields move. Logged-in `aiograpi` is one extra (`pipx install 'insto[aiograpi]'`) when you actually need data behind the login wall — but kept off the default path so your account isn't in scope.\n- **Async, typed, tested.** Python ≥ 3.11, strict mypy, ~93% coverage, ruff-clean. Backends, facade, commands all `async def`.\n- **Two surfaces, one grammar.** A prompt-toolkit REPL with slash-popup completion and live `/watch` notifications, *and* a Unix-friendly one-shot mode (`insto @user -c info`). `--json -` and `--csv -` write to stdout; `/batch -` reads targets from stdin.\n- **Snapshot / watch / diff.** Persisted in `~/.insto/store.db`. Poll a target on an interval; diff against the last snapshot.\n- **Maltego CSV export** out of the box (`--maltego` on any flat-row command, plus full `/dossier`).\n\nTwo surfaces over the same command grammar:\n\n- **REPL** — `insto` drops you into a prompt-toolkit session with tab-completion,\n  a bottom toolbar (active target, backend, quota), and live `/watch`\n  notifications. Visually similar to the Claude Code welcome screen.\n- **One-shot** — `insto @user -c \u003ccommand\u003e [args]` runs a single slash-command\n  and exits. Pipe-friendly: `--json -` writes to stdout, `--csv -` does the\n  same for flat commands, `/batch -` reads targets from stdin.\n\n## Install\n\nRequires Python ≥ 3.11. Pick the install path that matches how you keep\nother CLIs:\n\n```sh\nuv tool install insto              # uv users — fastest, no venv to manage\npipx install insto                 # pip users — same effect, classic tool\nbrew install pipx \u0026\u0026 pipx install insto   # macOS, no Python yet\n```\n\nFor the optional logged-in `aiograpi` backend (private accounts, posts\nbehind Instagram's login wall) install with the extra:\n\n```sh\nuv tool install 'insto[aiograpi]'\npipx install 'insto[aiograpi]'\n```\n\n`insto setup` then offers a `hiker | aiograpi` choice and prompts for\nthe right credentials. See [`docs/backends.md`](docs/backends.md) for\nthe trade-offs and the account-ban risk on aiograpi.\n\n\u003e **Got `insto: command not found` after install?** Both `pipx` and\n\u003e `uv tool` install into `~/.local/bin`, which is not on `$PATH` by\n\u003e default on a fresh Linux box. Fix it once:\n\u003e\n\u003e ```sh\n\u003e pipx ensurepath           # or: uv tool update-shell\n\u003e exec \"$SHELL\"             # reload PATH in the current session\n\u003e insto --version\n\u003e ```\n\nOr from a checkout (development):\n\n```sh\ngit clone git@github.com:subzeroid/insto.git\ncd insto\nuv sync \u0026\u0026 uv run insto --help     # editable inside .venv\n# or:  uv tool install --editable .   to put `insto` on $PATH\n```\n\n\u003e ℹ️ **Bare `pip install insto` does not work on modern systems by default**\n\u003e (PEP 668 — Homebrew Python, Debian 12+, Ubuntu 23.04+ all reject system-wide\n\u003e pip writes). Use `pipx` or `uv tool install` — both create an isolated\n\u003e venv per CLI, no manual sourcing.\n\n## Setup\n\n```sh\ninsto setup\n```\n\nInteractive wizard. Writes `~/.insto/config.toml` (mode `0600`) with your\nHikerAPI token, output directory, sqlite store path, and optional proxy.\nThe token is read with `getpass` so it does not echo to the terminal; pass\n`-` for the proxy to clear a previously-saved value.\n\n\u003e 💸 **HikerAPI gives you 100 free requests** to try things out — no card,\n\u003e no email-verification dance, just sign up and a token is waiting:\n\u003e \u003chttps://hikerapi.com/p/6k1q1388\u003e. That's enough for a couple of full\n\u003e `/dossier` runs or many `/info` / `/where` / `/timeline` calls — pick a\n\u003e target you already know to test the surface before deciding whether to\n\u003e top up.\n\nToken precedence is **flag \u003e env (`HIKERAPI_TOKEN`) \u003e config.toml**; the same\nprecedence applies to the proxy (`--proxy`, `HIKERAPI_PROXY`,\n`[hiker].proxy`). `socks5h://` (Tor) and `http://` proxies are both\nsupported.\n\n### Environment variables\n\n| Variable          | Purpose                                                             |\n|-------------------|---------------------------------------------------------------------|\n| `HIKERAPI_TOKEN`  | API token (overrides `[hiker].token` in config.toml)                |\n| `HIKERAPI_PROXY`  | Proxy URL (overrides `[hiker].proxy`)                               |\n| `INSTO_HOME`      | Override the default `~/.insto/` config root                        |\n| `INSTO_BACKEND`   | `hiker` (default) / `aiograpi` / `fake` (e2e suite). Same as `--backend` and `[backend]` in `config.toml` |\n\n## How insto compares to other Instagram OSINT tools\n\n| | insto | [Osintgram](https://github.com/Datalux/Osintgram) | [Toutatis](https://github.com/megadose/toutatis) | [Sherlock](https://github.com/sherlock-project/sherlock) |\n|---|---|---|---|---|\n| Backends supported | [HikerAPI](https://hikerapi.com/p/6k1q1388) (default) + aiograpi | Username/password (default) + HikerAPI ([#2586](https://github.com/Datalux/Osintgram/pull/2586)) | Logged-in Instagram session | HTTP probes — multi-site |\n| Default backend | HikerAPI — no IG session in scope | Logged-in Instagram session | Logged-in Instagram session | N/A — username probing |\n| Scope | Instagram deep dive | Instagram only | Instagram (email/phone focus) | 400+ sites, username search |\n| Geo OSINT (`/where`, `/place`, `/placeposts`) | ✅ unique | ❌ | ❌ | ❌ |\n| Network ops (`/intersect`, `/mutuals`) | ✅ unique | ❌ | ❌ | ❌ |\n| Posting cadence (`/timeline`) | ✅ unique | ❌ | ❌ | ❌ |\n| Superfan ranking (`/fans`) | ✅ unique | ❌ partial | ❌ | ❌ |\n| Snapshot / watch / diff | ✅ sqlite-backed | ❌ | ❌ | ❌ |\n| Maltego CSV export | ✅ | ❌ | ❌ | ❌ |\n| Interactive REPL | ✅ prompt-toolkit, slash-popup | ✅ basic shell | ❌ one-shot | ❌ one-shot |\n| One-shot / scriptable | ✅ stdin/stdout pipes | ⚠️ shell only | ✅ | ✅ |\n| Type-safe / strict mypy | ✅ ~93% coverage | ❌ | ❌ | ❌ |\n\n**When to pick insto** — Instagram-specific OSINT where you want HikerAPI on the default path (no IG session is ever in scope), deep network/geo analytics, snapshots over time, and Maltego-ready export. Modern stack — asyncio, strict mypy, prompt-toolkit REPL with slash-popup completion.\n\n**When to pick Osintgram** — historic OSS standard, large existing community. As of PR [#2586](https://github.com/Datalux/Osintgram/pull/2586) (merged Aug 2025) it can also run through HikerAPI via `HIKERAPI_TOKEN` so you don't have to use a logged-in Instagram account. The default path is still username/password and the command surface is the original Osintgram one — no `/where`, `/intersect`, `/timeline`, or `/fans` analytics.\n\n**When to pick Toutatis** — narrow goal: extract email + phone hints from a target's `user_info`. It's smaller and single-purpose. insto's `/email` and `/phone` cover the same data through HikerAPI without an Instagram login.\n\n**When to pick Sherlock / Maigret** — you're doing username reconnaissance across many platforms (forums, image hosts, code hosts). Different tool category — pair with insto for Instagram depth after Sherlock points you at an account.\n\nRelated projects: [aiograpi](https://github.com/subzeroid/aiograpi) (the async Instagram private API library that powers insto's optional `[aiograpi]` backend), [Social-Media-OSINT-Tools-Collection](https://github.com/subzeroid/Social-Media-OSINT-Tools-Collection) (curated tools list), [awesome-osint](https://github.com/subzeroid/awesome-osint).\n\n## Examples\n\nREPL:\n\n```text\n$ insto\n                                Tips for getting started\n  ___ _   _ ____ _____ ___      /target \u003cuser\u003e  set OSINT target\n |_ _| \\ | / ___|_   _/ _ \\     /info           full profile dump\n  | ||  \\| \\___ \\ | || | | |    /help           list all commands\n  | || |\\  |___) || || |_| |\n |___|_| \\_|____/ |_| \\___/     Recent activity\n                                @nasa\n i n s t o  ⇋  o s i n t        @instagram\n instagram tool · open-source intel\n                                hiker · 14.7M requests left · $4,417 · 15 rps cap\n\ninsto @→ /\n```\n\nType `/` and the popup opens with every command (Slack / Claude Code style):\n\n```text\ninsto @→ /info\n\u003e /target ferrari\n\u003e /info\n\u003e /posts 10                   # last 10 feed posts, media saved under output/ferrari/posts/\n\u003e /posts 10 --no-download     # URLs only, no CDN write\n\u003e /followers 500 --csv followers.csv\n\u003e /diff\n\u003e /watch ferrari 600          # poll every 10 minutes (5 min floor)\n\u003e /dossier                    # collect a full target package\n\u003e /quit\n```\n\n`/info \u003cuser\u003e` is also valid as inline form — runs the lookup without\nmutating the active session target. Same for every single-target\ncommand (`/posts nasa 5`, `/dossier nasa`, ...).\n\nOne-shot:\n\n```sh\ninsto @ferrari -c info\ninsto -c info instagram                                    # inline target, no REPL state\ninsto @ferrari -c posts 10 --json -                        # 10 posts, JSON to stdout\ninsto @ferrari -c followers 500 --csv followers.csv\ninsto @ferrari -c followers 200 --maltego                  # Maltego CSV under output/ferrari/\ninsto -c search ferrari 20 --maltego                       # full SERP, no active target needed\ninsto @nasa -c fans --limit 10                             # top fans = ❤️ + 3*💬 across 10 posts\ninsto @ferrari -c recommended --maltego                    # IG's \"same category\" recommendations\ncat targets.txt | insto -c batch - info --yes              # stdin pipe + non-interactive\ninsto -c dossier instagram --maltego                       # full target package, Maltego CSVs per section\n```\n\n`-c \u003ccmd\u003e` consumes the rest of `argv` as the slash-command's arguments,\nso `-c batch targets.txt info` runs `batch targets.txt info` (one `-c`\nper invocation). `--yes` is required when `/batch` reads from stdin or\nwhen the target list exceeds the confirmation threshold.\n\n### Global flags\n\n| Flag                            | Purpose                                                  |\n|---------------------------------|----------------------------------------------------------|\n| `-c / --cmd \u003cname\u003e [args...]`   | One-shot mode: run a single slash-command and exit       |\n| `-i / --interactive`            | Force the REPL even when a target is provided            |\n| `--proxy \u003curl\u003e`                 | Override `HIKERAPI_PROXY` for this invocation            |\n| `--json [PATH or -]`            | Write the JSON envelope (default path, file, or stdout)  |\n| `--csv  [PATH or -]`            | Same for flat-row commands                               |\n| `--maltego [PATH or -]`         | Maltego entity-import CSV (alias for `--output-format maltego`) |\n| `--output-format {json,csv,maltego}` | Explicit format selector                            |\n| `--limit N` / `--no-download`   | Per-command paging cap and media opt-out                 |\n| `--backend {hiker,aiograpi}`    | Backend selector for this invocation (overrides `$INSTO_BACKEND` and `config.toml`) |\n| `--no-progress`                 | Suppress tqdm bars + spinner on long commands (`/fans`, `/wliked`, `/wcommented`, `/dossier`) |\n| `--yes / -y`                    | Skip confirmation prompts (required for `/batch -`)      |\n| `--verbose` / `--debug`         | Logging level for `~/.insto/logs/insto.log`              |\n| `--version`                     | Print the version and exit                               |\n| `--print-completion {bash,zsh}` | Emit a shell-completion script                           |\n\nPipe to `jq`:\n\n```sh\ninsto @ferrari -c info --json - | jq '.username, .followers_count'\n```\n\nShell completion (uses `argparse` via `shtab`):\n\n```sh\ninsto --print-completion zsh \u003e ~/.insto/_insto\necho 'fpath+=~/.insto \u0026\u0026 autoload -Uz compinit \u0026\u0026 compinit' \u003e\u003e ~/.zshrc\n```\n\n## Command surface\n\n🔥 marks the killer-feature commands — the ones that are uniquely OSINT-positioned and don't have obvious equivalents in other tools.\n\n| Group | Commands | What it does |\n|---|---|---|\n| **Profile** | `info` `about` `propic` `email` `phone` `export` `pinned` | profile dump, user_about slice, avatar download, contact extraction, JSON export, pinned posts |\n| **Media** | `posts` `reels` `reposts` `stories` `highlights` `tagged` `audio` `postinfo` 🔥 | feed media, reposts, stories, highlights, tagged-in, audio-asset → clips, **`postinfo` resolves any URL/code/pk to full Post DTO** |\n| **Network** | `followers` `followings` `mutuals` `intersect` 🔥 `similar` `search` 🔥 `recommended` | follower lists, self-intersection, **`intersect` = followers(@a) ∩ followers(@b)**, suggested similar, **`search` = free-text account discovery**, category recommendations |\n| **Geo** | `locations` `where` 🔥 `place` 🔥 `placeposts` 🔥 | location frequency, **`where` = geo fingerprint (anchor + centroid + radius)**, **`place` = text → IG locations**, **`placeposts` = top media at a location** |\n| **Content** | `hashtags` `mentions` `captions` `likes` `timeline` 🔥 | top hashtags / @mentions / captions, like-count stats, **`timeline` = posting-cadence histogram (hour-of-day + day-of-week)** |\n| **Interactions** | `comments` `wcommented` `wliked` `wtagged` `fans` 🔥 | per-post + aggregated comments, top commenters / likers / taggers, **`fans` = weighted superfan ranking (likes + 3×comments)** |\n| **Discovery** | `resolve` | expand `instagram.com/share/...` short-links to canonical URLs (aiograpi only) |\n| **Direct** | `direct` `direct-thread` | read-only Direct threads and messages (aiograpi only) |\n| **Saved** | `collections` `saved` | read-only saved collections and saved posts for the logged-in aiograpi account |\n| **Watch / diff** | `watch` `unwatch` `watching` `diff` `history` | poll-based snapshot diffing; cli-history |\n| **Operational** | `quota` `health` `config` `purge` | balance + p50/p95 latency + error breakdown, effective config with origins, sqlite/cache cleanup |\n| **Session** | `target` `current` `clear` | active-target plumbing for the REPL |\n| **Batch / dossier** | `batch` `dossier` 🔥 | run one command across a target list, **`dossier` = full target package (profile + media + network + analytics) with `--maltego` CSV per section** |\n\nInside the REPL each command may be invoked with or without a leading `/`.\n\nPretty much every command takes `--limit N` (paging cap) and supports `--json` / `--csv` / `--maltego` export to file or `-` for stdout. Long-running aggregations (`/fans`, `/wliked`, `/wcommented`, `/dossier`) show a tqdm progress bar; everything else gets a `⢿ \u003ccmd\u003e...` spinner during the silent setup wait.\n\n## Where things go\n\n- `~/.insto/config.toml` — settings (mode `0600`).\n- `~/.insto/store.db` — sqlite store: snapshots, watches, cli history.\n- `~/.insto/logs/insto.log` — rotating log file (mode `0600`, secrets redacted).\n- `~/.insto/aiograpi.session.json` — persisted Instagram session for the\n  aiograpi backend (mode `0600`; only created when you pick that backend).\n- `./output/\u003cuser\u003e/\u003ctype\u003e/…` — downloaded media. Override with\n  `[output_dir]` in config or `--out` on commands that accept it.\n\n## Documentation\n\nFull docs at \u003chttps://subzeroid.github.io/insto/\u003e:\n\n- [**🔥 Killer features**](https://subzeroid.github.io/insto/killer-features/) — `/dossier`, `/where`, `/intersect`, `/fans`, `/place`, `/postinfo`, `/timeline`, `/search` with real output examples.\n- [**📓 OSINT recipes**](https://subzeroid.github.io/insto/recipes/) — concrete investigative scenarios: find someone's likely city, detect sockpuppet rings, evidence-archive a post chain, audit your own footprint, etc.\n- [Installation](https://subzeroid.github.io/insto/installation/)\n- [Basic usage](https://subzeroid.github.io/insto/basic-usage/)\n- [CLI reference](https://subzeroid.github.io/insto/cli-reference/)\n- [Backends](https://subzeroid.github.io/insto/backends/)\n- [Architecture](https://subzeroid.github.io/insto/architecture/)\n- [Troubleshooting](https://subzeroid.github.io/insto/troubleshooting/)\n\nContributing: see [CONTRIBUTING.md](CONTRIBUTING.md). Security policy: [SECURITY.md](SECURITY.md).\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubzeroid%2Finsto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsubzeroid%2Finsto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubzeroid%2Finsto/lists"}