Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@ uv tool install 'insto[aiograpi]'
pipx install 'insto[aiograpi]'
```

`insto setup` then offers a `hiker | aiograpi` choice and prompts for
If `insto` is already installed through `pipx` and you later switch to
`aiograpi`, add the optional dependency to the existing tool venv:

```sh
pipx inject insto aiograpi
```

`insto setup` then offers a `hikerapi | aiograpi` choice and prompts for
the right credentials. See [`docs/backends.md`](docs/backends.md) for
the trade-offs and the account-ban risk on aiograpi.

Expand Down Expand Up @@ -90,17 +97,17 @@ The token is read with `getpass` so it does not echo to the terminal; pass

Token precedence is **flag > env (`HIKERAPI_TOKEN`) > config.toml**; the same
precedence applies to the proxy (`--proxy`, `HIKERAPI_PROXY`,
`[hiker].proxy`). `socks5h://` (Tor) and `http://` proxies are both
`[hikerapi].proxy`). `socks5h://` (Tor) and `http://` proxies are both
supported.

### Environment variables

| Variable | Purpose |
|-------------------|---------------------------------------------------------------------|
| `HIKERAPI_TOKEN` | API token (overrides `[hiker].token` in config.toml) |
| `HIKERAPI_PROXY` | Proxy URL (overrides `[hiker].proxy`) |
| `HIKERAPI_TOKEN` | API token (overrides `[hikerapi].token` in config.toml) |
| `HIKERAPI_PROXY` | Proxy URL (overrides `[hikerapi].proxy`) |
| `INSTO_HOME` | Override the default `~/.insto/` config root |
| `INSTO_BACKEND` | `hiker` (default) / `aiograpi` / `fake` (e2e suite). Same as `--backend` and `[backend]` in `config.toml` |
| `INSTO_BACKEND` | `hikerapi` (default) / `aiograpi` / `fake` (e2e suite). Same as `--backend` and `[backend]` in `config.toml`; legacy `hiker` is still accepted |

## How insto compares to other Instagram OSINT tools

Expand Down Expand Up @@ -200,7 +207,7 @@ when the target list exceeds the confirmation threshold.
| `--maltego [PATH or -]` | Maltego entity-import CSV (alias for `--output-format maltego`) |
| `--output-format {json,csv,maltego}` | Explicit format selector |
| `--limit N` / `--no-download` | Per-command paging cap and media opt-out |
| `--backend {hiker,aiograpi}` | Backend selector for this invocation (overrides `$INSTO_BACKEND` and `config.toml`) |
| `--backend {hikerapi,aiograpi}` | Backend selector for this invocation (overrides `$INSTO_BACKEND` and `config.toml`) |
| `--no-progress` | Suppress tqdm bars + spinner on long commands (`/fans`, `/wliked`, `/wcommented`, `/dossier`) |
| `--yes / -y` | Skip confirmation prompts (required for `/batch -`) |
| `--verbose` / `--debug` | Logging level for `~/.insto/logs/insto.log` |
Expand Down
18 changes: 9 additions & 9 deletions docs/backends.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

The contract lives in `insto/backends/_base.py:OSINTBackend`. Two implementations ship:

| | **hiker** (default install) | **aiograpi** (`insto[aiograpi]`) |
| | **hikerapi** (default install) | **aiograpi** (`insto[aiograpi]`) |
|---|---|---|
| Authentication | API token | Username + password (+ 2FA) |
| Cost | Pay-per-call | Free |
Expand All @@ -17,14 +17,14 @@ The contract lives in `insto/backends/_base.py:OSINTBackend`. Two implementation

## Pick a backend

Default is **hiker**. Switch to aiograpi when you need data behind Instagram's login wall — private profiles you follow or 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.
Default is **hikerapi**. Switch to aiograpi when you need data behind Instagram's login wall — private profiles you follow or posts on accounts that 403 from logged-out HTTP. For OSINT on public profiles, HikerAPI 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):

```toml
backend = "aiograpi"

[hiker]
[hikerapi]
token = "hk_live_..." # kept around in case you flip back

[aiograpi]
Expand All @@ -39,13 +39,13 @@ 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` |
| `hikerapi.token` | `--hiker-token` | `HIKERAPI_TOKEN` |
| `hikerapi.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
## hikerapi — HikerAPI

Authenticates with a [HikerAPI](https://hikerapi.com/p/6k1q1388) token. Pay-per-call, no Instagram login, no account-ban risk.

Expand All @@ -61,7 +61,7 @@ What the backend handles:
- **Retries** — `with_retry` decorator. `RateLimited` (with `retry_after`) and `Transient` retry with exponential backoff + jitter; `AuthInvalid`, `QuotaExhausted`, `SchemaDrift`, `Banned` propagate immediately.
- **Schema drift** — every mapper raises `SchemaDrift(endpoint, missing_field)` instead of `KeyError` when 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].proxy` plumbed through `httpx`. `socks5h://` (Tor) supported.
- **Proxy** — `--proxy` / `HIKERAPI_PROXY` / `[hikerapi].proxy` plumbed through `httpx`. `socks5h://` (Tor) supported.

### HikerAPI 403

Expand Down Expand Up @@ -116,12 +116,12 @@ Don't have the seed? Either re-enable 2FA in Instagram's settings to capture it,

`Profile.access` is one of:

| State | hiker | aiograpi |
| State | hikerapi | 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 carry a `requires=("followed",)` annotation. They run cleanly on aiograpi; on hiker they exit with a typed message.
Commands that strictly need a logged-in account carry a `requires=("followed",)` annotation. They run cleanly on aiograpi; on hikerapi they exit with a typed message.
2 changes: 1 addition & 1 deletion docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Every command inherits these via the global parser. Flag conflicts (e.g. `--json
| `--yes` | Skip interactive confirmations (`/batch` over 25 targets, `/purge`). |
| `--proxy URL` | Per-call proxy. Schemes: `http://`, `https://`, `socks5h://` (Tor). |
| `--hiker-token TOKEN` | Per-call HikerAPI token override. |
| `--backend {hiker,aiograpi}` | Per-invocation backend selector (overrides `$INSTO_BACKEND` and `config.toml`). |
| `--backend {hikerapi,aiograpi}` | Per-invocation backend selector (overrides `$INSTO_BACKEND` and `config.toml`). |
| `--no-progress` | Suppress tqdm bars + `⢿ <cmd>...` spinner on long-running commands. |
| `--non-interactive` | `insto setup` only — read every value from env vars without prompts. CI/automation. |
| `--verbose` / `--debug` | Bump log level (writes to `~/.insto/logs/insto.log`, rotated). |
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Two surfaces over the same command grammar:

## Pick a backend

| | **hiker** (default) | **aiograpi** (`insto[aiograpi]`) |
| | **hikerapi** (default) | **aiograpi** (`insto[aiograpi]`) |
|---|---|---|
| Auth | API token | Instagram login + 2FA |
| Cost | Pay-per-call, [100 free requests](https://hikerapi.com/p/6k1q1388) at signup (no card) | Free |
Expand Down
14 changes: 10 additions & 4 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ pipx install 'insto[aiograpi]'
pip install 'insto[aiograpi]' # in a venv only — see PEP 668 below
```

After install, `insto setup` will offer `backend (hiker | aiograpi)` and prompt for the credentials of the chosen backend. See [Backends](backends.md) for the trade-offs and the account-ban risk.
If `insto` is already installed through `pipx` and you later switch to `aiograpi`, add the optional dependency to the existing tool venv:

```sh
pipx inject insto aiograpi
```

After install, `insto setup` will offer `backend (hikerapi | aiograpi)` and prompt for the credentials of the chosen backend. See [Backends](backends.md) for the trade-offs and the account-ban risk.

### What about `pip install insto`?

Expand Down Expand Up @@ -90,8 +96,8 @@ insto setup

Interactive wizard. Writes `~/.insto/config.toml` (mode `0600`) with:

- `hiker.token` — your [HikerAPI](https://hikerapi.com/p/6k1q1388) access key. New here? Sign up via <https://hikerapi.com/p/6k1q1388> for **100 free requests** (no card required) to try the CLI.
- `hiker.proxy` (optional) — `http://`, `https://`, or `socks5h://` proxy URL.
- `hikerapi.token` — your [HikerAPI](https://hikerapi.com/tokens) access key.
- `hikerapi.proxy` (optional) — `http://`, `https://`, or `socks5h://` proxy URL.
- `output_dir` — where downloads and exports land (resolved to absolute).
- `db_path` — where the sqlite store lives (default `~/.insto/store.db`).

Expand All @@ -100,6 +106,6 @@ Token can also live in:
- `--hiker-token <value>` — per-call flag (overrides everything else).
- `HIKERAPI_TOKEN` env — overrides the toml file.

Precedence: **flag > env > toml**. Same shape for `--proxy` / `HIKERAPI_PROXY` / `[hiker].proxy`.
Precedence: **flag > env > toml**. Same shape for `--proxy` / `HIKERAPI_PROXY` / `[hikerapi].proxy`.

`~/.insto/` is created mode `0700`; `store.db` and `config.toml` are `0600`. The setup wizard refuses to write a world-readable file.
30 changes: 19 additions & 11 deletions insto/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
runtime dependency footprint) of every backend at once.

Practically: `import insto` does not import `hikerapi`. Only the
`make_backend("hiker", ...)` call does — and that import lives inside the
`make_backend("hikerapi", ...)` call does — and that import lives inside the
function body.

Setting `INSTO_BACKEND=fake` in the environment overrides the requested
Expand All @@ -21,8 +21,15 @@
from typing import Any

from insto.backends._base import OSINTBackend
from insto.config import BACKEND_AIOGRAPI, BACKEND_FAKE, BACKEND_HIKERAPI, LEGACY_BACKEND_HIKER

BACKEND_OVERRIDE_ENV = "INSTO_BACKEND"
AIOGRAPI_INSTALL_HINT = (
"aiograpi backend requested but the `aiograpi` package is not installed. "
"For an existing pipx install, run: `pipx inject insto aiograpi`. "
"Fresh installs can use: `pipx install 'insto[aiograpi]'` or "
"`uv tool install --force 'insto[aiograpi]'`."
)

__all__ = ["BACKEND_OVERRIDE_ENV", "OSINTBackend", "make_backend"]

Expand All @@ -31,7 +38,8 @@ def make_backend(name: str, **opts: Any) -> OSINTBackend:
"""Construct a backend by short name.

Known names:
"hiker" — `HikerBackend` (HikerAPI SDK). Imports `hikerapi` lazily.
"hikerapi" — `HikerBackend` (HikerAPI SDK). Imports `hikerapi` lazily.
"hiker" — legacy alias for "hikerapi".
"fake" — `FakeBackendProd`, hardcoded in-process data for E2E
tests. Selected when `INSTO_BACKEND=fake` is set even if
the caller asked for another backend.
Expand All @@ -41,25 +49,25 @@ def make_backend(name: str, **opts: Any) -> OSINTBackend:
override = os.environ.get(BACKEND_OVERRIDE_ENV)
if override:
name = override
if name == "hiker":
if name in {BACKEND_HIKERAPI, LEGACY_BACKEND_HIKER}:
from insto.backends.hiker import HikerBackend

return HikerBackend(**opts)
if name == "aiograpi":
if name == BACKEND_AIOGRAPI:
# aiograpi is an optional dependency: gate the import so the
# default install (hiker-only) does not have to ship it. If the
# user did not install `insto[aiograpi]`, give them the exact
# command to run.
try:
from insto.backends.aiograpi import AiograpiBackend

return AiograpiBackend(**opts)
except ModuleNotFoundError as exc: # pragma: no cover — environment dependent
raise RuntimeError(
"aiograpi backend requested but the `aiograpi` package is not "
"installed. Run: `pip install 'insto[aiograpi]'` "
"(or `uv tool install 'insto[aiograpi]'` / `pipx install 'insto[aiograpi]'`)."
) from exc
return AiograpiBackend(**opts)
if name == "fake":
missing = getattr(exc, "name", None)
if missing == "aiograpi" or "aiograpi" in str(exc):
raise RuntimeError(AIOGRAPI_INSTALL_HINT) from exc
raise
if name == BACKEND_FAKE:
from insto.backends._fake import FakeBackendProd

return FakeBackendProd(**opts)
Expand Down
Loading
Loading