reelminner
Enables AI agents to scrape Instagram Reels and public profile data (metadata, engagement, owner info) without the official API, via tools for scraping, status checks, cookie import, stopping, and exporting results.
README
<p align="center"> <img src="assets/icon.ico" alt="Reelminner" width="96" height="96" /> </p>
<h1 align="center">π¬ Reelminner</h1> <p align="center"><b>Instagram Reel & Profile Scraper β Pro</b></p>
<p align="center"> <img alt="Python" src="https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white" /> <img alt="Playwright" src="https://img.shields.io/badge/Engine-Playwright-2EAD33?logo=playwright&logoColor=white" /> <img alt="License" src="https://img.shields.io/badge/License-MIT-green" /> <img alt="Platform" src="https://img.shields.io/badge/Platform-Windows%20%7C%20WSL%2FLinux-lightgrey" /> </p>
<p align="center"> Extract <b>reel metadata</b>, <b>owner profiles</b>, <b>follower counts</b>, <b>music</b>, <b>likes / comments / views</b> and more from any public Instagram Reel β through a desktop GUI, a oneβcommand CLI, a Python API, or an <b>MCP server</b> that AI agents can drive. </p>
π‘ Name note: This project's final public name is Reelminner. The Python engine class is
Reelminner(seescraper.py), the CLI/GUI and MCP server are brandedreelminner, and the GitHub repository isreelminner. The earlier working codename ReelSnipe has been fully retired. Other name ideas are listed in Name options.
π Table of Contents
- What is Reelminner
- β¨ Features
- π§ How it works
- ποΈ Project architecture
- π¦ Installation
- π Quick Start
- π» Usage
- π Output format
- βοΈ Configuration
- ποΈ Project structure
- π§ͺ Testing & QA
- π¦ Building a standalone EXE
- β οΈ Legal & ethical disclaimer
- π€ Contributing
- π License
- π Troubleshooting & FAQ
- π·οΈ Name
What is Reelminner
Reelminner is an openβsource toolkit that pulls structured data out of Instagram Reels
and the profiles that posted them. It is built around a single, reusable engine
(Reelminner) that is exposed four different ways:
| Interface | File | Best for |
|---|---|---|
| π₯οΈ Desktop GUI | gui.py |
Nonβtechnical users, oneβclick scraping |
| β¨οΈ CLI | scraper.py |
Power users, batch jobs, scripts |
| π€ MCP server | mcp_server.py |
AI agents / LLM workflows |
| π Python API | import scraper |
Embedding inside your own code |
Everything shares the same parsing, session, and rateβlimit logic, so results are identical no matter which frontβend you use.
β¨ Features
- Multiβsource reel parsing β Reelminner reads data from several layers (embedded JSON, GraphQL responses, and a live DOM fallback) so it keeps working even when Instagram changes one of them.
- Owner profile enrichment β for every reel it can autoβfetch the poster's
username,full_name,bio,followers,is_verified, andreels_count. - Follower count extraction β pulled via Instagram's GraphQL
UserByRestrictedView/GraphQLOwnerInfoquery, with a DOM fallback and pagination (handles capped follower figures like β1.2Mβ by scrolling the profile). - Music metadata β reel audio
music_title,music_artist, andmusic_id. - Engagement metrics β
views,likes,comments, and the directvideo_url/thumbnail. - Session & login management β interactive QR/login, cookie import from EditThisCookie exports, and a 24βhour session refresh so you don't reβlogin constantly.
- Concurrent scraping β a thread pool (
--workers, default 3) with polite interβrequest delays (--delay, default 2s) and adaptive backβoff when Instagram throwsBLOCKED/RATE_LIMITED. - Resilient status tracking β every row carries a
statuscode (OK,PARSED_PARTIAL,FAILED,NO_DATA,BLOCKED,RATE_LIMITED) so you know exactly what succeeded. - Multiple export formats β CSV (default), JSON, and Excel (
.xlsxviaopenpyxl). - MCP server β five stable tools so an AI agent (Claude, Cursor, etc.) can scrape, check status, import cookies, stop, and export.
- Desktop GUI β builtβin dark theme, pasteβURL box, live results table, rightβclick copy URL / open reel, and oneβclick export.
- Tested β pytest suite + an endβtoβend QA harness that enforces dataβquality gates.
π§ How it works
ββββββββββββββ ββββββββββββββ ββββββββββββββ ββββββββββββββ
β GUI β β CLI β β MCP srv β β Python β
β gui.py β β scraper.py β βmcp_server β β import β
βββββββ¬βββββββ βββββββ¬βββββββ βββββββ¬βββββββ βββββββ¬βββββββ
ββββββββββββββββββ΄βββββββββββββββββ΄βββββββββββββββββ
βΌ
βββββββββββββββββββββββββ
β Reelminner β β the engine (scraper.py)
β β’ session / cookies β
β β’ thread pool β
β β’ adaptive backβoff β
βββββββββββββ¬ββββββββββββ
βΌ
βββββββββββββββββββββββββ
β parsers.py β β pure extraction helpers
β parse_reel_page / jsonβ
β parse_owner / music β
β regex adapters β
βββββββββββββββββββββββββ
- Normalize the input URL (
normalize_reel_url) so/reel/X/and/reel/s/β¦/both work. - Load session β apply saved cookies (
sessionid,csrftoken,ds_user_id,ig_did,mid,rur) or log in. - Fetch & parse the reel page with a layered fallback:
parse_reel_pageβ embeddedwindow.__additionalData/sharedDataHTML JSONparse_reel_jsonβ raw GraphQLGQLresponseparse_graphql_reelβshortcodeMediaobject- DOM fallback β
_extract_text_rawqueries the live page for likes / comments / plays / followers via regex adapters.
- Enrich owner (unless
--no-profiles): fetch the profile and readfollowers,full_name,bio,is_verified,reels_count. - Respect limits: sleep
delaybetween requests; if blocked, back off and retry. - Write rows to CSV / JSON / Excel with a
statusper row.
ποΈ Project architecture
Reelminner is a singleβengine, multiβinterface design. One core engine
(Reelminner) does all the real work; the GUI, CLI, MCP server, and
Python API are thin frontβends that call into it. This keeps parsing, session
handling, and rateβlimiting identical across every entry point.
βββββββββββββββββββββββββββββββ
URL(s) in βββββββΆβ Reelminner β scraper.py
β ββ engine / orchestrator ββ β
βββββββββ¬ββββββββββββ¬βββββββββββ
run scrapes β β enrich owner
βΌ βΌ
ββββββββββββββββββ ββββββββββββββββββββ
β parsers.py β β session + graphqlβ
β pure extractors β β (followers/music)β
βββββββββ¬βββββββββ βββββββββββ¬βββββββββ
βββββββββββ¬βββββββββββββ
βΌ
ReelData row + status
βΌ
CSV / JSON / Excel writers
Module responsibilities
| File | Role | Key public symbols |
|---|---|---|
scraper.py |
Core engine + CLI. Owns the browser, session, thread pool, and writers. | Reelminner, scrape(), login(), has_session(), save_cookies_from_file(), clear_session(), write_csv, export_json, export_excel, normalize_reel_url, csv_columns, ReelData, DEFAULT_STATE_FILE |
parsers.py |
Pure extraction helpers β no browser, easy to unitβtest. | parse_reel_page, parse_reel_json, parse_graphql_reel, parse_owner_username_from_html, parse_music, parse_count, parse_caption, parse_graphql_followers, parse_profile_card |
gui.py |
Tkinter desktop app. Builds the window, menu, URL box, workers slider, results table, and export dialogs. | ReelminnerGUI, build(), scrape(), export_*, copy_url(), open_reel() |
theme.py |
GUI styling β applies the dark theme to ttk widgets. |
apply_dark_theme(root) |
mcp_server.py |
MCP server β exposes the engine as 5 tools for AI agents over stdio. | mcp (FastMCP), scrape_reels, get_status, import_cookies, stop_scrape, export_results |
build_exe.py |
Packaging β PyInstaller oneβfile build. | EXE(...), COLLECT/Analysis |
run_qa.py |
QA harness β runs the engine over a corpus and enforces dataβquality gates. | run_qa(), gate checks, qa_report.json |
Engine internals (Reelminner)
- Session layer β
_SESSION_COOKIE_NAMES(sessionid,csrftoken,ds_user_id,ig_did,mid,rur);_apply_cookies(),_refresh_if_needed()(24h),login()(interactive QR),clear_session(). - Concurrency β
scrape()spins up aThreadPoolExecutor(max_workers=workers); each URL is handled by_workerβ_scrape_url, which calls_gather_metadata(reel data) and optionally_gather_article(owner profile). A semaphore +_sleep()enforce politeness;status_code/retcodedrive an adaptive retry/backβoff loop when Instagram returnsBLOCKED/RATE_LIMITED. - Parsing pipeline (layered fallback) β inside
_gather_metadatathe engine tries, in order:parse_reel_page(embedded HTML JSON) βparse_reel_json(raw GraphQLGQL) βparse_graphql_reel(shortcodeMedia) β DOM fallback via the_extract_text_html/_extract_text_rawadapters and the_PATTERNSregex list (likes/comments/plays/followers). - Profile enrichment β
get_follower_count()uses Instagram's GraphQLUserByRestrictedView/GraphQLOwnerInfoquery, falling back to the DOM and paginating followers (_fetch_followerswithend_cursor) when counts are capped. - Output β rows are collected as
ReelDatadicts and written bywrite_csv(respectingcsv_columns),export_json, orexport_excel(needsopenpyxl).
Why this layout
- Testability β all parsing lives in
parsers.pywith no browser dependency, sotests/test_parsers.pycan assert on saved HTML/JSON fixtures. - One source of truth β every interface shares the same
Reelminner, so a fix in the engine benefits the GUI, CLI, and MCP server simultaneously. - Safe packaging β the GUI/CLI thin shells mean the PyInstaller EXE only bundles the engine + a minimal UI, keeping the binary small.
π¦ Installation
Requirements: Python 3.10+ and the Playwright browser engine.
# 1. Clone
git clone https://github.com/ilovekushgola/reelminner.git
cd reelminner
# 2. (Recommended) create a virtual environment
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # macOS / Linux
# 3. Install dependencies
pip install -r requirements.txt
# 4. Install the Chromium browser for Playwright
playwright install chromium
GUI only: the desktop app uses
tkinter, which ships with standard Python installs. No extra package needed. The GUI is most polished on Windows.
Optional dev/test tools:
pip install -r requirements-dev.txt # pytest, coverage
π‘ Before you start: Reelminner works best with a loggedβin Instagram session β some reels and all owner/follower data require authentication. Run
python scraper.py --loginonce (interactive QR), or import cookies exported from the EditThisCookie browser extension withpython scraper.py --import-cookies cookies.json. It only reads public content you're already allowed to view.
π Quick Start
# Scrape a single reel from the command line
python scraper.py "https://www.instagram.com/reel/CxXYZ123/"
# β¦or many reels from a file (one URL per line)
python scraper.py -f urls.txt -o export.csv
# Launch the desktop GUI
python gui.py
π» Usage
1. Desktop GUI
python gui.py
- Click Login (optional but recommended β improves success rate).
- Paste one reel URL per line into the box (or
Ctrl+Ato select all). - Drag the Workers slider, then click Scrape.
- Watch results appear in the table.
- Rightβclick a row to Copy URL or Open Reel.
- Export to CSV / Excel / JSON, or Open results folder.
The last results are autoβsaved to results/_last_results.json.
2. Command Line (CLI)
python scraper.py [URL ...] [options]
| Flag | Default | Description |
|---|---|---|
urls |
β | One or more reel URLs (positional). |
-f, --file |
β | Text file with one reel URL per line. |
--login |
off | Open a browser to log in interactively (QR). |
--import-cookies FILE |
β | Import an EditThisCookie JSON export. |
--clear-session |
off | Delete the saved storage_state.json. |
--headless |
off | Run the browser without a window. |
-w, --workers |
3 |
Number of concurrent scrape threads. |
--delay |
2.0 |
Seconds to wait between requests. |
--state |
storage_state.json |
Path for the saved session. |
-o, --output |
reels_results.csv |
Output CSV path. |
--no-profiles |
off | Skip autoβfetching owner follower data. |
# Headless, 5 workers, 1s delay, no profile enrichment
python scraper.py -f reels.txt -w 5 --delay 1 --headless --no-profiles -o out.csv
3. MCP Server (for AI agents)
Reelminner ships an MCP (Model Context Protocol) server so an AI client can drive it.
python mcp_server.py # stdio transport
Configure your MCP client (.mcp.json is included in the repo):
{
"mcpServers": {
"reelminner": {
"command": "python",
"args": ["mcp_server.py"],
"cwd": ".",
"env": { "RMIN_HEADLESS": "true" }
}
}
}
Tools exposed (5, stable):
| Tool | Signature | Purpose |
|---|---|---|
scrape_reels |
(urls, workers, delay, headless, with_profiles) |
Run a scrape job. |
get_status |
() |
Current progress / last result summary. |
import_cookies |
(json_path) |
Load cookies from an EditThisCookie file. |
stop_scrape |
() |
Stop the running job. |
export_results |
(path, fmt) |
Export to csv / json / xlsx. |
Environment overrides: RMIN_HEADLESS, RMIN_WORKERS, RMIN_DELAY, RMIN_WITH_PROFILES.
4. Python API
from scraper import Reelminner, write_csv
scraper = Reelminner(workers=3, delay=2.0, headless=True)
rows, report = scraper.scrape(
["https://www.instagram.com/reel/CxXYZ123/"],
with_profiles=True,
)
write_csv(rows, "out.csv")
for r in rows:
print(r["username"], r["followers"], r["likes"], r["status"])
Key members of Reelminner:
scrape(urls, with_profiles=True)β(rows, report)login()β interactive loginhas_session()/save_cookies_from_file(path)/clear_session()write_csv(rows, path),export_json(rows, path),export_excel(rows, path)normalize_reel_url(url)β public helpercsv_columnsβ the ordered list of output fieldsDEFAULT_STATE_FILEβ defaultstorage_state.json
π Output format
Each reel becomes one row. The full CSV schema (scraper.csv_columns):
| Column | Description |
|---|---|
idx |
Row index. |
username |
Reel owner handle (e.g. natgeo). |
followers |
Owner follower count (may be follower_minβfollower_max). |
full_name |
Owner display name. |
bio |
Owner biography text. |
is_verified |
True / False. |
reels_count |
Number of reels on the owner profile. |
profile_url |
Link to the owner profile. |
reel_url |
Canonical reel URL. |
reel_id |
Instagram reel shortcode / ID. |
caption |
Reel caption text. |
upload_date |
Post timestamp. |
views |
Play / view count. |
likes |
Like count. |
comments |
Comment count. |
video_url |
Direct video file URL. |
thumbnail |
Thumbnail image URL. |
music_title |
Audio track title. |
music_artist |
Audio artist. |
music_id |
Audio / music ID. |
scrape_ts |
When this row was scraped (ISO timestamp). |
status |
OK Β· PARSED_PARTIAL Β· FAILED Β· NO_DATA Β· BLOCKED Β· RATE_LIMITED. |
βοΈ Configuration
Cookies / session
- Log in with
python scraper.py --login(savesstorage_state.json). - Or export cookies from your browser via the EditThisCookie extension and run
python scraper.py --import-cookies cookies.json.
Environment variables (used by MCP server & CLI defaults)
| Variable | Effect |
|---|---|
RMIN_HEADLESS |
true/false β run browser headless. |
RMIN_WORKERS |
Default worker count. |
RMIN_DELAY |
Default delay between requests (seconds). |
RMIN_WITH_PROFILES |
true/false β autoβenrich owner profiles. |
A template is provided: copy mcp.env.example β mcp.env to override MCP defaults.
ποΈ Project structure
reelminner/
βββ scraper.py # Core engine: Reelminner + CLI
βββ gui.py # Tkinter desktop application
βββ parsers.py # Pure extraction helpers (HTML/JSON/music/regex)
βββ mcp_server.py # MCP server (5 tools for AI agents)
βββ theme.py # Darkβtheme styling for the GUI
βββ build_exe.py # PyInstaller build script
βββ Reelminner.spec # PyInstaller spec (oneβfile EXE)
βββ run_qa.py # Endβtoβend QA harness with dataβquality gates
βββ requirements.txt # Runtime dependencies
βββ requirements-dev.txt# Dev / test dependencies
βββ mcp.env.example # MCP env template
βββ .mcp.json # MCP client configuration
βββ assets/ # Icons (icon.ico)
βββ docs/ # SKILL.md, E2E test/fix plan
βββ skills/ # Agent skill definition
βββ tests/ # pytest suite + corpus.txt
βββ results/ # Scrape outputs (gitβignored)
π§ͺ Testing & QA
# Unit / integration tests
pytest -q
# Endβtoβend dataβquality run (uses your saved session)
python run_qa.py # full run over tests/corpus.txt
python run_qa.py --quick # 1 URL, headless, fast iteration
python run_qa.py --url <reel> # custom single URL
python run_qa.py --report-only # show last qa_report.json
The QA harness enforces gates such as parsedβrate, verifiedβrate, nonβemptyβrate,
blockedβrate, and max runtime, and writes results/qa/qa_report.json +
qa_results.csv.
π¦ Building a standalone EXE
On Windows, produce a portable .exe (no Python needed by end users):
pip install pyinstaller
python build_exe.py
Output: dist/Reelminner.exe (oneβfile build via Reelminner.spec).
β οΈ Legal & ethical disclaimer
Reelminner is provided for educational and authorized/personal use only.
- Scraping Instagram may violate its Terms of Service. Use it only on content you own or are permitted to access.
- Respect rate limits (
--delay, fewer--workers) and do not use it for spam, harassment, or commercial bulk extraction.- You are responsible for how you use this tool and for complying with applicable laws (incl. GDPR / privacy regulations) in your jurisdiction.
- The authors are not affiliated with Instagram/Meta and accept no liability.
π Troubleshooting & FAQ
playwright says the browser isn't installed / pages won't open
β Make sure you ran both pip install -r requirements.txt and
playwright install chromium. Without the Chromium download nothing will launch.
Most fields are empty, or I get BLOCKED / RATE_LIMITED
β Log in (python scraper.py --login) or import cookies, then slow down:
--delay 4 and fewer workers (-w 1). Instagram throttles anonymous/unauthenticated
traffic hardest, so an authenticated session is the single biggest success factor.
A reel returns NO_DATA
β The post may be private, deleted, or regionβlocked, or Instagram served a login wall.
Try again with a loggedβin session.
The GUI window won't open or fonts look wrong
β The GUI uses Python's builtβin tkinter. On Windows it's most polished. On Linux/macOS
install the Tk package if the window fails to launch (e.g. sudo apt install python3-tk).
ModuleNotFoundError when I run a script
β You're likely outside the repo or its virtual environment. cd into the project folder
and activate the venv (.venv\Scripts\activate on Windows, source .venv/bin/activate
on macOS/Linux) before running python scraper.py.
How do I scrape lots of reels at once?
β Put one URL per line in a text file and run
python scraper.py -f urls.txt -o out.csv.
Can an AI agent use this?
β Yes β run python mcp_server.py and point any MCP client (Claude Desktop, Cursor, etc.)
at the included .mcp.json. See MCP Server.
π€ Contributing
- Fork the repo and create a feature branch.
pip install -r requirements-dev.txt- Add/adjust tests in
tests/; runpytestandpython run_qa.py --quick. - Open a pull request describing the change and the QA result.
π License
Released under the MIT License β see LICENSE.
π·οΈ Name
The project's final public name is Reelminner ("Reel miner"). Earlier internal
codenames have been retired. If you fork it you can rename it to anything you like β
just update the title in gui.py and this README.
<p align="center">Made with β€οΈ for the openβsource scraping community.</p>
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
E2B
Using MCP to run code via e2b.