Reels In.
Shorts Out.
Done.

Automatically sync your Instagram Reels to YouTube Shorts. Fork the repo, add your credentials, and let GitHub Actions handle the rest -effortlessly.

Fetch Reels

Pulls latest reels from any public Instagram profile with smart filtering.

Upload Shorts

Pushes videos to YouTube as Shorts with captions, tags, and metadata.

Auto Schedule

Runs every 6 hours on GitHub Actions. Zero maintenance after setup.

Fork & Go

Clone, configure, deploy. Built for the simplest possible onboarding.

Instagram
Download
Upload
YouTube Shorts
Quick Start

Up and running
in 6 steps.

Fork the repo, configure your credentials, and sync automatically.

1

Fork the Repository

Click the Fork button on GitHub to create your own copy of instoob.

2

Edit config.yml

Set your Instagram username and adjust YouTube upload preferences.

3

Set Up YouTube API

Create a Google Cloud project, enable YouTube Data API v3, and get OAuth credentials.

4

Get Refresh Token

Run python setup_youtube.py locally to authorize your YouTube channel.

5

Add GitHub Secrets

Add your YouTube and Instagram credentials as repository secrets.

6

Enable Actions

Go to the Actions tab and enable workflows. Trigger manually or wait for the schedule.

YouTube API

YouTube setup
walkthrough.

One-time setup to connect your YouTube channel.

1

Create Google Cloud Project

Go to Google Cloud Console, create a new project (e.g., "Instoob"), then navigate to APIs & Services > Library. Search for "YouTube Data API v3" and enable it.

2

Create OAuth Credentials

In APIs & Services > Credentials, click Create Credentials > OAuth client ID. Configure the consent screen as External, add your email as a test user. Choose "Desktop app" type, then download the JSON file as client_secrets.json.

3

Run Setup Script

Place client_secrets.json in the project root and run the setup script.

terminal
pip install -r requirements.txt
python setup_youtube.py
4

Save Your Credentials

The script opens a browser for consent, then prints your YOUTUBE_CLIENT_ID, YOUTUBE_CLIENT_SECRET, and YOUTUBE_REFRESH_TOKEN. Save these as GitHub Secrets.

Heads up: While your Google Cloud project is in "Testing" mode, refresh tokens expire every 7 days. Go to OAuth consent screen and click "Publish App" to avoid this.
Instagram

Connect your
Instagram.

No password needed. Just one cookie from your browser.

Simple

Session Cookie

No password needed. Just grab your sessionid cookie from the browser. Works with any account, including 2FA.

3 steps
# 1. Open instagram.com in your browser
# 2. DevTools (F12) > Application > Cookies
# 3. Copy the 'sessionid' value

Add the value as IG_SESSION_ID in GitHub Secrets. That's it.

Configuration

Customize
everything.

Edit config.yml to control what gets synced and how.

username Required

Instagram username to sync reels from.

max_reels_per_run Optional

Maximum reels to process per sync cycle. Default: 3.

max_duration Optional

Skip reels longer than N seconds. Set to 0 for no limit. Default: 180.

since_date Optional

Only sync reels posted after this date (YYYY-MM-DD format).

privacy_status Optional

YouTube upload visibility: public, unlisted, or private.

made_for_kids Optional

Whether uploaded Shorts are marked as made for kids. Default: false.

config.yml
instagram:
  username: "your_username"
  max_reels_per_run: 3
  max_duration: 0
  # since_date: "2025-01-01"

youtube:
  category_id: "22"
  privacy_status: "public"
  default_language: "en"
  title_prefix: ""
  title_suffix: ""
  description_suffix: "\n\n#Shorts"
  made_for_kids: false

sync:
  data_dir: "data"
  download_dir: "downloads"
Secrets

GitHub Secrets
reference.

Add these in your fork under Settings > Secrets and variables > Actions.

Secret Required Description
YOUTUBE_CLIENT_ID Yes Google OAuth client ID from setup script
YOUTUBE_CLIENT_SECRET Yes Google OAuth client secret from setup script
YOUTUBE_REFRESH_TOKEN Yes YouTube refresh token from setup script
IG_SESSION_ID Yes Instagram sessionid cookie from your browser
No Instagram password needed. Just copy the sessionid cookie from your browser's DevTools.
Local

Run it
on your machine.

Perfect for testing or one-off syncs.

terminal
# Clone and install
git clone https://github.com/YOUR_USER/instoob.git
cd instoob
pip install -r requirements.txt

# Configure
cp config.example.yml config.yml
cp .env.example .env
# Edit config.yml and .env with your details

# Run sync
python main.py sync

# Verbose output
python main.py sync --verbose
Schedule

Set your
sync frequency.

The GitHub Actions workflow runs every 6 hours by default. Customize the cron schedule in the workflow file.

.github/workflows/sync.yml
schedule:
  - cron: "0 */6 * * *"  # Every 6 hours
  # "0 */12 * * *"  Every 12 hours
  # "0 9 * * *"     Daily at 9 AM UTC
  # "0 9 * * 1"     Weekly on Monday
Quota note: YouTube API allows ~6 uploads per day (10,000 units, ~1,600 per upload). With max_reels_per_run: 3 and 4 runs/day, you may approach the limit. Adjust as needed.
Help

Common issues
and fixes.

Instagram auth is failing
Check your IG_SESSION_ID secret. Session cookies expire after a few months. To refresh, open Instagram in your browser, go to DevTools (F12) > Application > Cookies, copy the new sessionid value, and update the GitHub Secret.
YouTube upload returns an auth error
Your refresh token may have expired (this happens every 7 days in "Testing" mode). Run python setup_youtube.py again to get a new token, or publish your Google Cloud app to get permanent tokens.
Getting "Access blocked" on YouTube OAuth
Your Google Cloud project is in "Testing" mode and your email isn't listed as a test user. Go to Google Cloud Console > OAuth consent screen > Test users, and add your email address.
Quota exceeded error
YouTube API has a daily quota of 10,000 units (~6 uploads). Reduce max_reels_per_run in config.yml or change the cron schedule to run less frequently.
No reels found during sync
Check that the Instagram username in config.yml is correct and the profile has public video posts. If using since_date, ensure the date isn't set in the future.
Duplicate uploads appearing
Make sure data/synced.json is being committed back to your repo. The GitHub Actions workflow handles this automatically. If running locally, the state file is saved after each run.