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.
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.
-
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.
-
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 asmain, and typemainagain in the confirm box.It commits an empty history, so your first post starts clean.
-
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
- In Google Drive, create a folder and put in the photos you'd be happy to post.
- Right-click the folder → Share → General access: Anyone with the link, Viewer → Copy link. That link is the secret
DRIVE_FOLDER_MAIN. - 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
- 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. - 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. - Copy the Account ID from the R2 overview page:
R2_ACCOUNT_ID. - 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_IDandR2_SECRET_ACCESS_KEY. - If you used a folder, set
source.r2.prefixinconfig/profiles.yamlto it, for examplephotos/.
-
04INSTAGRAM
Get an Instagram token
- At developers.facebook.com, create an app and add the Instagram product.
- Under Instagram → API setup with Instagram login, add your account as a tester and accept the invite in the Instagram app.
- Click Generate token next to your account, with
instagram_business_content_publishandinstagram_business_manage_insights. That isIG_MAIN_ACCESS_TOKEN. - 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.
-
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-lunaorgemini-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 modelgemma4:31bby default and easily covers a post a day. Captions may need a little more checking in preview. -
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.
Name Value 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_PROVIDERset toopenai,geminiorollama. 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_MODELwith its name, such asqwen3-vl:235bon 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_SOURCEset tor2the same way. Without it, Google Drive is used. -
07VOICE
Describe your account
Open
config/profiles.yamlon GitHub (the pencil icon edits it in the browser). Underprofiles → 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.mdholds 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. -
08TEST
Try it by hand
Actions → Daily post → Run workflow, in these modes, in order:
- check: verifies the AI key and model, the Instagram token, the posting quota and the photo folder. No AI tokens spent.
- plan: shows which photos it would post over the next 7 days, and why.
- preview: download the
preview-mainartifact to see the exact image and caption. - 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. -
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
cronline in.github/workflows/daily-post.yml; it's in UTC.Optional: a variable set to
falseposts single photos only. -
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.
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.