Extract media recommendations (music, videos, books, articles) from Instagram Reels. Use this skill when the user asks to extract, identify, or find media recommendations from an Instagram Reel. This includes requests like "what song is in this reel", "extract recommendations from this reel", "what media is shown in this Instagram post", or any task involving analyzing Instagram Reel content for embedded media references.
Extract media recommendations (music, videos, books, articles) from Instagram Reels.
git clone https://github.com/hedonhermdev/instarec.git
cd instarec
| Requirement | How to verify | How to install |
|---|---|---|
uv package manager | uv --version | curl -LsSf https://astral.sh/uv/install.sh | sh |
ffmpeg | ffmpeg -version | brew install ffmpeg (macOS) or apt install ffmpeg (Linux) |
Python 3.12+ is managed automatically by uv -- do NOT install it separately.
uv sync
This will download the correct Python version (if needed) and install all project dependencies.
The tool uses Google Gemini for visual frame analysis. You need a Gemini API key.
.env file in the project root:echo 'GEMINI_API_KEY=your-api-key-here' > .env
NEVER commit the .env file to version control.
Instagram requires authentication to download Reels. You need to export your session cookies in Netscape format.
cookies.txt in the project root.NEVER commit cookies.txt to version control. Cookies expire periodically -- if you get HTTP 401/403 errors, re-export fresh cookies.
Run the following to confirm everything is configured:
| Check | Command |
|---|---|
| uv installed | uv --version |
| ffmpeg installed | ffmpeg -version |
| Dependencies installed | uv sync (should complete without errors) |
| API key configured | grep GEMINI_API_KEY .env (should show your key) |
| Cookies present | ls cookies.txt (should exist) |
uv run main.py <instagram_reel_url>
uv run main.py <url> [--cookies <path>] [--model <model>] [--scene-threshold <float>] [--keep-files]
| Argument | Type | Default | Description |
|---|---|---|---|
url | positional, required | -- | Instagram Reel URL (e.g. https://www.instagram.com/reel/ABC123/) |
--cookies | string | cookies.txt | Path to yt-dlp Netscape-format cookies file for Instagram authentication |
--model | string | gemini-2.5-flash-lite | Google Gemini model to use for frame analysis |
--scene-threshold | float | 0.05 | FFmpeg scene-change sensitivity (0-1). Lower = more frames extracted. Raise to 0.2-0.4 if too many duplicate frames are returned |
--keep-files | flag | off | Retain downloaded video and extracted frames in data/<reel_id>/ instead of cleaning up |
All commands MUST be run from the project root (the cloned instarec directory).
The CLI writes structured JSON to stdout and status/progress messages to stderr.
{
"url": "https://www.instagram.com/reel/...",
"caption": "Original reel caption text",
"media": [
{
"media": {
"type": "music | video | article | book",
"platform": "spotify | youtube | apple_music | ...",
"title": "Song or media title",
"creator": "Artist, author, or channel name",
"confidence": 0.95
}
}
]
}
| Field | Type | Description |
|---|---|---|
url | string | The input Instagram Reel URL |
caption | string | The reel's caption/description text (may be empty) |
media | array | List of detected media items. Empty array [] if nothing found |
media[].media.type | string | One of: music, video, article, book |
media[].media.platform | string or null | Platform identifier (e.g. spotify, youtube, apple_music) |
media[].media.title | string or null | Title of the media |
media[].media.creator | string or null | Artist, author, or channel name |
media[].media.confidence | number or null | Model confidence score from 0 to 1 |
Since JSON goes to stdout and status messages go to stderr, capture the JSON like this:
# Save JSON to file
uv run main.py <url> > output.json
# Parse with jq
uv run main.py <url> 2>/dev/null | jq '.media'
# Store in a variable
result=$(uv run main.py <url> 2>/dev/null)
The CLI runs a three-stage pipeline:
yt-dlp (requires valid cookies.txt for authentication). Output: MP4 video file.ffmpeg scene-change detection to extract visually distinct keyframes. Output: JPEG frames.uv run main.py "https://www.instagram.com/reel/DUacLRYktcd/"
uv run main.py "https://www.instagram.com/reel/DUacLRYktcd/" --keep-files
# Video saved to: data/DUacLRYktcd/video.mp4
# Frames saved to: data/DUacLRYktcd/frames/
uv run main.py "https://www.instagram.com/reel/DUacLRYktcd/" --model gemini-2.5-flash-preview-05-20
uv run main.py "https://www.instagram.com/reel/DUacLRYktcd/" --scene-threshold 0.3
for url in \
"https://www.instagram.com/reel/ABC123/" \
"https://www.instagram.com/reel/DEF456/"; do
uv run main.py "$url" 2>/dev/null
done
| Symptom | Likely cause | Fix |
|---|---|---|
RuntimeError: GEMINI_API_KEY not set | Missing API key | Add GEMINI_API_KEY=... to .env |
RuntimeError: yt-dlp returned no info | Invalid URL or expired cookies | Verify URL is a valid Instagram Reel; re-export cookies.txt |
ffmpeg errors / no frames extracted | ffmpeg not installed or corrupt video | Install ffmpeg; try a different reel |
Empty media array | No embedded media detected in reel | Reel may not contain media cards; try lowering --scene-threshold or using a stronger --model |
| HTTP 401/403 from Instagram | Expired or invalid cookies | Re-export cookies from a logged-in browser session |
cookies.txt) for downloadingconfidence score is the model's self-reported confidence, not a calibrated probability