Sync Instagram saved event posts to calendar exports.
Project description
Instacalendar
Scenario: you're like me and save lots of gigs and events in Instagram. Then you forget about them. Life's busy and it's hard to keep track of all those fun events without aligning them with your boring, grown-up calendar. Meet Instacalendar: seamlessly sync an entire Instragram saved post collection to your Google (or other) calendar. Keep track of those events, plan better, go out and explore!
instacalendar is a command-line wizard that reads an Instagram saved posts
collection, asks OpenRouter models through LiteLLM to infer calendar events,
lets you review each candidate event, and exports approved events to .ics or
Google Calendar.
The app can be installed as a Python package or as a Windows executable bundled with PyInstaller.
TLDR
git clone https://github.com/lkoelman/instacalendar.git
cd instalendar && uv sync
# run setup
uv run instacalendar init
# run interactively (fetch Instagram collections and select one)
uv run instacalendar
# export specific collection
uv run instacalendar run --collection "Concerts" --ics-output events.ics
Installation
Install From PyPI
uv tool install instacalendar
Then run:
instacalendar init
instacalendar
Install From Source
git clone https://github.com/lkoelman/instacalendar.git
cd instacalendar
uv sync --dev
Because instagrapi tracks the undocumented Instagram API at a fast-changing pace, upgrading this dependency regularly could prevent bugs arising due to API divergence:
# upgrade out environment and uv.lock file:
uv sync --upgrade-package instagrapi
# upgrade instagrapi before running a command
uv run --upgrade-package instagrapi instacalendar <command>
Configure
Run the guided setup:
uv run instacalendar init
Or provide values non-interactively:
uv run instacalendar init \
--instagram-username your_user \
--instagram-password your_password \
--openrouter-api-key sk-or-v1-... \
--openrouter-text-model google/gemini-3-flash-preview \
--openrouter-vision-model google/gemini-3-flash-preview \
--openrouter-video-model google/gemini-3-flash-preview \
--default-export ics
If OPENROUTER_API_KEY or INSTAGRAM_PASSWORD is set in your environment, setup asks whether to use
that value before prompting you to type one.
Secrets are stored in the operating system keyring. Instagram session settings are stored under the app data directory to avoid repeated logins.
Google Calendar Export
For now, just import the .ics file in your Google Calendar. In the future, an OAuth Client ID will be created so you can directly push events to your Google calendar.
For Google Calendar export, authenticate during setup:
uv run instacalendar init --default-export google --google-auth
The command opens a Google consent link in your browser and stores the resulting OAuth token under the app data directory. Later Google Calendar exports reuse and refresh that token when possible.
Release builds can ship an Instacalendar desktop OAuth client so normal users do
not need to create Google Cloud credentials. For development, private forks, or
builds without a bundled OAuth client, set one of these environment variables
before running --google-auth:
export GOOGLE_OAUTH_CLIENT_FILE=/path/to/oauth-client.json
# or
export GOOGLE_OAUTH_CLIENT_JSON='{"installed": ... }'
The OAuth client must be a Google desktop app. The app requests the
calendar.events scope needed to read and write calendar events.
Run
Start the guided wizard:
uv run instacalendar
Export a collection directly:
uv run instacalendar run --collection "Concerts" --ics-output events.ics
Extracted event results are cached locally as each post is processed, so a failed or interrupted run can resume without sending already processed posts back to OpenRouter when the configured model set still matches. To force a fresh extraction pass, use:
uv run instacalendar run --collection "Concerts" --ignore-event-cache
By default, cache hits require the same post, same configured OpenRouter model
set, and same extraction source type (text, image, or video). You can
relax matching when needed:
uv run instacalendar run --collection "Concerts" --event-cache-key post,media
Retry extraction/export from posts already saved in the local cache:
uv run instacalendar run --from-cache --collection "Concerts" --ics-output events.ics
Limit processing to recent posts, or cap how many matching posts are reviewed:
uv run instacalendar run --collection "Concerts" --posted-since 2026-04-01 --limit 25
While extraction is running, the progress output shows runtime-only estimated LLM cost and token usage for each post and for the run so far, grouped by model. The final summary prints the same per-model token and estimated cost totals. These estimates come from LiteLLM/OpenRouter response usage metadata and are not persisted in the local cache.
Inspect cached posts and processed exports:
uv run instacalendar cache list-posts
uv run instacalendar cache calendar
uv run instacalendar cache events
uv run instacalendar cache info
Clear the local cache:
uv run instacalendar cache clear --yes
Privacy
Instagram captions, post metadata, image content, and cached local video content for posts being processed may be sent to OpenRouter for extraction. Remote Instagram video URLs are not sent when the local video download failed. Google Calendar export sends approved event details to Google. The local cache stores post metadata, downloaded image and video files, extracted event results, review decisions, and export records so reruns can resume extraction/export without contacting Instagram unnecessarily, avoid repeated OpenRouter calls for matching posts, and avoid duplicate exports. Model responses are validated against the app's Pydantic extraction schema before they are cached or reviewed.
Test And Lint
uv run pytest
uv run ruff check
Build A Windows Executable
On Windows:
uv sync --dev
uv run pyinstaller --onefile --name instacalendar src/instacalendar/cli.py
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file instacalendar-0.1.0.tar.gz.
File metadata
- Download URL: instacalendar-0.1.0.tar.gz
- Upload date:
- Size: 24.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1e120dce5053ae7675511ba96d3a4ebd338a263988c0ffc37c7fd9a8d375ad5
|
|
| MD5 |
9fad2eeacfd9be31ac573fe9dcebc9c4
|
|
| BLAKE2b-256 |
654c652f5009d0ce3186950b57f96bd4553722856116f7ac43177d45593f3cc9
|
Provenance
The following attestation bundles were made for instacalendar-0.1.0.tar.gz:
Publisher:
publish.yml on lkoelman/instacalendar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
instacalendar-0.1.0.tar.gz -
Subject digest:
b1e120dce5053ae7675511ba96d3a4ebd338a263988c0ffc37c7fd9a8d375ad5 - Sigstore transparency entry: 1396607873
- Sigstore integration time:
-
Permalink:
lkoelman/instacalendar@4b6e979c126f5c59511f08ca269de0763e4ccb5b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/lkoelman
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4b6e979c126f5c59511f08ca269de0763e4ccb5b -
Trigger Event:
push
-
Statement type:
File details
Details for the file instacalendar-0.1.0-py3-none-any.whl.
File metadata
- Download URL: instacalendar-0.1.0-py3-none-any.whl
- Upload date:
- Size: 29.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21cff468e2b551f08887503a2021af10fb8427e12f63446b86988f48ab6b0702
|
|
| MD5 |
e7b210e8d4532858a9b75b16e1597163
|
|
| BLAKE2b-256 |
f815b259902a81ea06e3fa3a1895c93f304d646ad6b11bf793dda89019316394
|
Provenance
The following attestation bundles were made for instacalendar-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on lkoelman/instacalendar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
instacalendar-0.1.0-py3-none-any.whl -
Subject digest:
21cff468e2b551f08887503a2021af10fb8427e12f63446b86988f48ab6b0702 - Sigstore transparency entry: 1396607878
- Sigstore integration time:
-
Permalink:
lkoelman/instacalendar@4b6e979c126f5c59511f08ca269de0763e4ccb5b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/lkoelman
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4b6e979c126f5c59511f08ca269de0763e4ccb5b -
Trigger Event:
push
-
Statement type: