I Needed Daily Content for My Turkish Speaking Club, So I Built a Bot
How I automated daily Instagram posts using Python, Unsplash, Cloudinary and the Instagram Graph API.
I run a Turkish speaking club in Dublin for people who want to practise Turkish.
To keep the community active between our events, I wanted to share one Turkish word every day on Instagram. Since I didn’t have enough time to manage the account manually, I decided to build a bot that would do everything for me.
Storing the Content
The project needed a collection of Turkish words.
I could have used a database, but I wanted to keep everything as simple as possible. A JSON file was more than enough.
Each data contains the Turkish word, its English translation and an example sentence.
{
"word": "Hayal",
"translation": "Dream",
"level": "B1",
"example": "Hayaller bazen gerçeğe dönüşür."
}
Selecting a random word is only a few lines of code.
import json
import random
with open("data/words.json", encoding="utf-8") as file:
words = json.load(file)
word = random.choice(words)
I preferred random selection instead of publishing the words in order.
I don’t think repeated words are a problem when learning a language. In fact, they can be helpful. Every time the same word appears, it will probably be combined with a different image, making the content feel new while reinforcing the vocabulary.
Finding Images
To make each post more interesting, I wanted to include a background image.
I already knew that Unsplash provides an API for developers, so it became the obvious choice.
For most concrete nouns, the English translation was enough as the search query.
For example:
Sun
Forest
Coffee
Dog
The first results were usually exactly what I needed.
Then I ran into my first real problem.
Abstract concepts didn’t work very well.
Searching for words like Dream, Freedom or Hope often returned beautiful images, but they didn’t represent the meaning of the word.
To solve this, I added an optional field called image_query.
{
"word": "Hayal",
"translation": "Dream",
"level": "B1",
"example": "Hayaller bazen gerçeğe dönüşür.",
"image_query": "person dreaming"
}
The code simply checks whether image_query exists.
image_query = word.get(
"image_query",
word["translation"]
)
If the field exists, it is used.
Otherwise, the English translation becomes the search query automatically.
This small change significantly improved the quality of the generated posts.
Generating the Image
After downloading a suitable image, Pillow generates the final Instagram post.
The image contains:
- the Turkish word,
- the English translation,
- and an example sentence.
The implementation is larger than the other modules, but the idea is straightforward.
Background Image
+
Word
+
Translation
+
Example Sentence
↓
Instagram Post
Publishing to Instagram
Once the image was ready, the next step was publishing it.
I created an Instagram Business account and connected it to Meta Developer.
Publishing through the Instagram Graph API turned out to be easier than I expected, but I encountered one limitation.
Instagram does not accept local image files.
Instead, it expects a publicly accessible image URL.
Because of that, I added Cloudinary to the pipeline.
The generated image is uploaded to Cloudinary first.
result = cloudinary.uploader.upload(image_path)
image_url = result["secure_url"]
Cloudinary returns a public URL, which is then passed to the Instagram Graph API.
Creating and publishing a post happens in two steps.
First, create the media container.
payload = {
"image_url": image_url,
"caption": caption,
"access_token": ACCESS_TOKEN
}
response = requests.post(
create_container_url,
data=payload
)
Then publish it.
payload = {
"creation_id": creation_id,
"access_token": ACCESS_TOKEN
}
requests.post(
publish_url,
data=payload
)
One thing I learned here is that the media container is not always ready immediately. Waiting a few seconds before calling media_publish solved the problem.
Running It Every Day
The final step was automation.
The project runs every day using GitHub Actions.
The workflow simply installs the dependencies and executes the application.
name: Daily Instagram Post
on:
schedule:
- cron: "0 9 * * *"
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- run: pip install -r requirements.txt
- run: python app.py
GitHub Secrets store all API keys, so there is no need to commit a .env file.
Final Thoughts
The original goal was simply to save a few minutes every day.
Instead, I ended up with a fully automated pipeline that selects a word, finds an image, generates an Instagram post and publishes it automatically.
The source code is available on GitHub:
https://github.com/hanificetinkaya/social-content-botOur instagram page:
https://www.instagram.com/learnturkishdublin