You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat: stealth human pacing, anti-throttling emulation, and adaptive backoff - #2707
When bulk scraping paginated endpoints (followers, followings, comments, post feeds), standard bot traffic triggers Instagram's rate limiting heuristics, resulting in HTTP 429 and feedback_required temporary action blocks.
This PR introduces an authentic human browsing emulation & anti-throttling pacing engine into Osintgram.
Key Changes
Gaussian Jitter Engine (src/human_pacing.py):
Replaces hardcoded fixed/uniform sleeps with realistic Gaussian distribution pauses bounded by natural reading intervals.
Pacing modes: normal (0.8s - 2.4s), stealth (1.6s - 4.8s + reading breaks), fast (minimal ~0.05s delay), and custom.
Periodic Reading Breaks:
In stealth mode, automatically pauses for 12–22 seconds every 20 pages to mimic natural user feed/profile inspection breaks.
Adaptive Backoff & Auto-Decay:
When encountering rate-limiting signals or action block warnings (feedback_required, 429), the engine dynamically scales delays up to 4x, protecting sessions from bans, and gradually decays back to normal on successive requests.
Service & Backend Integration:
Integrated seamlessly into OsintgramService._iter_items and OsintgramService._get_comments.
Unified pagination delays in src/instagrapi_backend.py.
Web UI & REST API:
Added GET /api/pacing/settings and POST /api/pacing/settings with origin protection.
Dynamic mode selector and active status badge in the Web UI Settings panel.
Configurable via SCRAPE_PACING / OSINTGRAM_PACING env vars or [Pacing] section in config/credentials.ini.
Tests & Docs:
Full test coverage in tests/test_human_pacing.py (12 tests) verifying distribution clipping, reading breaks, adaptive backoff, and Web UI endpoints.
Naming and docs
The module/docs describe this as "evading bot heuristics" and the mode is called stealth. What the code does is rate limiting with backoff, and that's how it should be presented. Please rename it (e.g. conservative, "adaptive rate limiting") and drop the "evade / emulate a human" wording from the docstring, UI and docs. Please also add a short note in doc/web-ui.md about the risk of an account block with instagrapi, especially in fast mode.
Behavior
Pacing is now applied to every backend in _iter_items / _get_comments, including HikerAPI, where there was no inter-page delay before; this slows every paginated scan by about 1.4s per page by default. Please apply it only to the instagrapi backend (or make it opt-in).
With instagrapi, both the service and the backend create their own HumanPacer and both call pace(), so delays add up and the break counters are separate. Please share one pacer.
The instagrapi backend never calls record_throttle_or_error() / record_success(), so the backoff isn't used where it matters most.
A new service (and pacer) is built on every request, so the throttle level is lost after a 429. Please keep the backoff state across scans (module-level, or per account).
The default normal mode (mean 1.4s) is faster than the previous 1.2–2.5s delay on instagrapi. Please keep the default at least as conservative as before.
Config
adaptive_backoff is written to credentials.ini but never read in resolve_pacing_config.
A single invalid value makes float() raise inside try/except Exception, and the rest of the [Pacing] section is silently ignored. Please parse each option separately and report invalid ones.
POST /api/pacing/settings doesn't validate the numbers (negative or inverted values, min_delay=0 in custom). Please enforce sane ranges and min <= max.
Rebased on latest development and addressed all review feedback in commit b817f7a:
Naming & docs:
Renamed mode to conservative (with stealth retained as backwards-compatible alias). Dropped human emulation / bot evasion claims throughout docstrings, UI, and documentation.
Added documentation in doc/web-ui.md explaining rate limiting behavior along with an explicit warning note regarding the risk of feedback_required action blocks when using instagrapi (especially in fast mode).
Behavior:
Pacing delays are scoped to the instagrapi backend; HikerAPI has 0 inter-page delay overhead.
Pacer is shared between InstagrapiClient and OsintgramService, with inter-page delays unified in _iter_items and _get_comments to eliminate duplicate delays.
InstagrapiClient calls record_success() and record_throttle_or_error() across API methods.
Backoff / throttle state is preserved across scans via get_shared_pacer().
Default normal pacing range set to 1.2s–2.6s (mean 1.85s), maintaining conservative timing matching baseline instagrapi behavior.
Config & validation:
adaptive_backoff is now read via sec.getboolean('adaptive_backoff') in resolve_pacing_config.
Options are parsed independently with warnings logged for invalid values so valid configuration fields are preserved.
POST /api/pacing/settings validates ranges (min_delay <= max_delay, non-negative values, and min_delay > 0 in custom mode).
All 233 unit/integration tests pass cleanly with 0 flake8 warnings.
In POST /api/pacing/settings, the numeric values (min_delay, max_delay, break_*, adaptive_backoff) are only written to credentials.ini when remember is true, and then the shared pacer reloads its config with resolve_pacing_config(), which reads the file and the environment. So with remember=false only mode is applied and the other values are silently dropped. Please apply them directly to the shared pacer's config.
_call counts every exception except "not found" as a throttle, so a login error, a private profile or a validation error also increases the backoff. Please limit it to rate-limit style errors (429, feedback_required, "please wait", challenge).
The stealth alias isn't needed since this feature hasn't been released, so there are no existing configs to keep working. Removing it also removes the last "stealth" wording from the code.
Minor: type(api_client).__name__ == "InstagrapiClient" is fragile; getattr(api_client, "pacer", None) is enough.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
When bulk scraping paginated endpoints (followers, followings, comments, post feeds), standard bot traffic triggers Instagram's rate limiting heuristics, resulting in HTTP 429 and
feedback_requiredtemporary action blocks.This PR introduces an authentic human browsing emulation & anti-throttling pacing engine into Osintgram.
Key Changes
src/human_pacing.py):normal(0.8s - 2.4s),stealth(1.6s - 4.8s + reading breaks),fast(minimal ~0.05s delay), andcustom.stealthmode, automatically pauses for 12–22 seconds every 20 pages to mimic natural user feed/profile inspection breaks.feedback_required, 429), the engine dynamically scales delays up to 4x, protecting sessions from bans, and gradually decays back to normal on successive requests.OsintgramService._iter_itemsandOsintgramService._get_comments.src/instagrapi_backend.py.GET /api/pacing/settingsandPOST /api/pacing/settingswith origin protection.SCRAPE_PACING/OSINTGRAM_PACINGenv vars or[Pacing]section inconfig/credentials.ini.tests/test_human_pacing.py(12 tests) verifying distribution clipping, reading breaks, adaptive backoff, and Web UI endpoints.doc/web-ui.mdconfiguration reference.Verification
python -m pytest -q).flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics).