instaPostsForge
Use it yourself · about 45 minutes, once

Your own daily poster, on your own account.

Copy the repo, add your keys as GitHub secrets, describe your account, and run it once by hand. After that it posts every day on its own. Nothing runs on your computer, and your keys never leave GitHub.

What you need

A GitHub account

Free. Your copy must be a public repo: Instagram downloads each photo from a public link to it, and Actions minutes are free for public repos.

An Instagram Professional account

Creator or Business, switched in the Instagram app under Account type and tools. Free.

A Meta developer app

At developers.facebook.com, to create the access token. It stays in development mode; no app review.

A place for your photos

A Google Drive folder with a free Google Cloud API key to read it (the default), or a private Cloudflare R2 bucket with a read-only token.

An AI API key

Claude by default, from the Claude Console with about $5 of credit; that lasts a long time. An OpenAI, Gemini or free Ollama Cloud key works too.

Typical cost: under a cent a post on Claude Haiku 5.5, a little more on OpenAI or GeminiInstagram API, Drive API or R2, GitHub Actions: free
  1. 01COPY

    Copy the repo

    Open instaPostsForge on GitHub and click Use this template → Create a new repository (or Fork). Keep it Public.

    Then in your copy, open Settings → Actions → General, allow all actions, and set Workflow permissions to Read and write. On a fork, also open the Actions tab once and enable workflows.

  2. 02CLEAN

    Start fresh

    Your copy came with the original account's posting history and photo notes in state/main/. Clear them: Actions → Start fresh → Run workflow, leave the profile as main, and type main again in the confirm box.

    It commits an empty history, so your first post starts clean.

  3. 03PHOTOS

    Make the photo folder

    Pick one place for your photos: Google Drive (the default) or a Cloudflare R2 bucket. Everything in it is fair game, so handpick. Each place keeps its own photos, so switching later is a fresh start.

    Google Drive

    1. In Google Drive, create a folder and put in the photos you'd be happy to post.
    2. Right-click the folder → Share → General access: Anyone with the link, Viewer → Copy link. That link is the secret DRIVE_FOLDER_MAIN.
    3. In the Google Cloud console: create a project → APIs and services → enable Google Drive API → Credentials → Create credentials → API key, restricted to the Drive API. That is GOOGLE_DRIVE_API_KEY.

    Or Cloudflare R2

    1. In the Cloudflare dashboard, open R2 Object Storage (it asks for a payment method once; the free tier covers this). Create bucket, no public access. Its name is R2_BUCKET_MAIN.
    2. Drag your photos onto the bucket page, ideally into a folder such as photos/. For many files, an S3 app like Cyberduck or rclone works too.
    3. Copy the Account ID from the R2 overview page: R2_ACCOUNT_ID.
    4. Manage API tokens → Create API token with Object Read only, for that bucket. Copy the Access Key ID and Secret Access Key right away (the secret is shown once): R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY.
    5. If you used a folder, set source.r2.prefix in config/profiles.yaml to it, for example photos/.
  4. 04INSTAGRAM

    Get an Instagram token

    1. At developers.facebook.com, create an app and add the Instagram product.
    2. Under Instagram → API setup with Instagram login, add your account as a tester and accept the invite in the Instagram app.
    3. Click Generate token next to your account, with instagram_business_content_publish and instagram_business_manage_insights. That is IG_MAIN_ACCESS_TOKEN.
    4. The number next to your account on the same page is IG_MAIN_USER_ID.

    It never needs your Instagram password, and you can revoke the token at any time.

  5. 05AI KEY

    Get an AI API key

    Claude is the default. In the Claude Console: API keys → Create key, and add about $5 of credit under Billing. That is ANTHROPIC_API_KEY.

    Prefer another provider? Make a key at the OpenAI platform (OPENAI_API_KEY) or in Google AI Studio (GEMINI_API_KEY), with billing set up. You only need the one you use; step 06 says how to pick it. Each uses its own cheap model that can read photos (gpt-5.6-luna or gemini-3.1-flash-lite), still cents a month.

    Want it free? Sign in at ollama.com → Settings → Keys and add an API key (OLLAMA_API_KEY). Ollama Cloud's free plan runs the open model gemma4:31b by default and easily covers a post a day. Captions may need a little more checking in preview.

  6. 06SECRETS

    Add the secrets

    In your copy: Settings → Secrets and variables → Actions → New repository secret, once per row. Nobody can read a secret back after it's saved.

    NameValue
    Claude API key (step 05). Or, instead, or : only the provider you use.
    Instagram token (step 04)
    Instagram user ID (step 04)
    Drive folder link (step 03)
    R2 instead of Drive. Bucket name, plus , and (step 03). Then the Drive rows aren't needed.
    Google API key (step 03)
    Optional. A fine-grained GitHub token for this repo only, with Secrets: Read and write, so the token renews itself every month.

    Using OpenAI, Gemini or Ollama? Also open the Variables tab next to Secrets and add a repository variable AI_PROVIDER set to openai, gemini or ollama. Without it, Claude is used. A run whose provider has no key stops straight away and says which secret is missing.

    Want a different model? Add a repository variable AI_MODEL with its name, such as qwen3-vl:235b on Ollama. It is used for every step; without it each provider uses its default. A manual run can also take a model in the model box on Run workflow.

    Photos in R2? Add a repository variable PHOTO_SOURCE set to r2 the same way. Without it, Google Drive is used.

  7. 07VOICE

    Describe your account

    Open config/profiles.yaml on GitHub (the pencil icon edits it in the browser). Under profiles → main → ai, the blocks marked ✏️ YOURS TO EDIT still describe the original account. Replace them, because captions follow them closely:

    account:
      niche: "street and travel photography in Lisbon"
      audience: "people who love slow travel"
      location: "Lisbon, Portugal"
      voice: "warm, observant, a little dry humour"
      avoid: "the word 'wanderlust'"
      ending_style: "a question about the reader's own city"

    Delete extra_instructions (it's about the original author's camera watermark), or write notes about your own photos there.

    config/ai-instructions.md holds the voice rules for every step. Its "Deities, temples and festivals" section writes reverent captions for Hindu festivals; keep it, adapt it to your own traditions, or delete it.

  8. 08TEST

    Try it by hand

    Actions → Daily post → Run workflow, in these modes, in order:

    1. check: verifies the AI key and model, the Instagram token, the posting quota and the photo folder. No AI tokens spent.
    2. plan: shows which photos it would post over the next 7 days, and why.
    3. preview: download the preview-main artifact to see the exact image and caption.
    4. post: posts once. Check your feed.

    Each run's page has a summary and a token-audit-… artifact showing what it cost. If something fails, the troubleshooting guide explains each error.

  9. 09DAILY

    Switch on daily posting

    Settings → Secrets and variables → Actions → Variables tab → New repository variable: name , value true. It must be a variable, not a secret.

    It posts at 13:30 UTC (7:00 pm in India). To change the time, edit the cron line in .github/workflows/daily-post.yml; it's in UTC.

    Optional: a variable set to false posts single photos only.

  10. 10EXTRA
    Optional

    Your own project page

    To publish this site for your copy, set Settings → Pages → Source to GitHub Actions. It republishes after every merge to main. The pages live in site/.

    To run it on your computer instead, or add a second account, see Running it locally and Adding another account.

That's it

Keep adding photos to the folder.

Each new photo is looked at once, and none is ever posted twice. When the folder runs out, the run says "add more photos" and posts nothing.