Working with Instagram data is useful for developers building analytics dashboards, influencer research tools, social media monitoring systems, and automation workflows.
For example, you might want to:
- Retrieve publicly available Instagram profile information.
- Analyze recent posts and engagement metrics.
- Monitor follower growth across multiple accounts.
- Build automated reports for marketing teams.
- Track changes in Instagram profiles over time.
Python makes processing this information relatively simple. The challenge is obtaining the data in a structured format.
Instagram provides official APIs for supported use cases, but their access requirements and available data may not fit every application.
An alternative is to use a third-party REST API.
In this tutorial, we'll use GramAPI, an Instagram data API, to build a small Python application that retrieves profile information and tracks follower counts over time.
By the end, you'll have a script that:
- Fetches Instagram profile information.
- Retrieves recent Instagram posts.
- Saves profile statistics to a CSV file.
- Compares follower counts between different dates.
- Can run automatically every day.
Let's get started.
1. Prerequisites
You'll need:
- Python 3.9 or newer.
- The
requestsPython library. - An API key.
- Basic familiarity with Python.
We'll use GramAPI for the API requests.
GramAPI provides 100 free requests for testing, so you can follow this tutorial without purchasing a package.
Install requests
Open your terminal and run:
python -m pip install requests
Get your API key
Create an account at:
Once you're logged in, open the API Keys section of your dashboard:
https://gramapi.com/cabinet/api-keys
Create an API key and save it somewhere secure.
Never hardcode API keys into public repositories.
Instead, store your key in an environment variable.
On Linux or macOS:
export GRAMAPI_KEY="your_api_key_here"
On Windows PowerShell:
$env:GRAMAPI_KEY="your_api_key_here"
Now Python can read the key without including it directly in your source code.
2. Fetch Instagram Profile Data
Let's start by retrieving information about a public Instagram account.
We'll use the nasa profile as an example.
GramAPI provides the following endpoint:
GET https://api.gramapi.com/raw/ig/user/info
The endpoint accepts a url parameter containing an Instagram username, numeric user ID, or profile URL.
Authentication is handled using the X-Api-Key HTTP header.
Python example
import os
import requests
API_KEY = os.environ["GRAMAPI_KEY"]
BASE_URL = "https://api.gramapi.com"
response = requests.get(
f"{BASE_URL}/raw/ig/user/info",
params={"url": "nasa"},
headers={
"X-Api-Key": API_KEY,
"Accept": "application/json"
},
timeout=40
)
response.raise_for_status()
data = response.json()
user = data["user"]
print("Username:", user.get("username"))
print("Full name:", user.get("full_name"))
print("Followers:", user.get("follower_count"))
print("Following:", user.get("following_count"))
print("Posts:", user.get("media_count"))
print("Verified:", user.get("is_verified"))
How it works
The script performs four actions:
1. Reads your API key
API_KEY = os.environ["GRAMAPI_KEY"]
This keeps credentials separate from application code.
2. Sends an HTTP GET request
requests.get(...)
Python sends the username as a query parameter and the API key in the request headers.
3. Parses the JSON response
data = response.json()
The API returns structured JSON data.
4. Extracts profile information
user = data["user"]
The user object contains profile details such as username, biography, follower count, and other available information.
The exact fields may vary depending on the account and data returned by Instagram.
Using .get() helps avoid errors when optional fields are missing.
What can you build with this?
Even one endpoint makes several applications possible:
- A profile statistics dashboard.
- An influencer research tool.
- A competitor monitoring system.
- An automated account reporting workflow.
But a single profile lookup only provides a snapshot.
To understand how an account changes, you need to collect data over time.
We'll implement that shortly.
3. Retrieve Recent Instagram Posts
Next, let's retrieve the latest posts from an Instagram profile.
The endpoint is:
GET https://api.gramapi.com/raw/ig/user/feed
It returns recent media items, including available engagement information.
Python example
import os
import requests
API_KEY = os.environ["GRAMAPI_KEY"]
response = requests.get(
"https://api.gramapi.com/raw/ig/user/feed",
params={"url": "nasa"},
headers={"X-Api-Key": API_KEY},
timeout=40
)
response.raise_for_status()
feed = response.json()
posts = feed.get("items", [])
for post in posts[:5]:
caption = post.get("caption") or {}
if isinstance(caption, dict):
caption_text = caption.get("text", "")
else:
caption_text = ""
likes = post.get("like_count")
comments = post.get("comment_count")
print("Likes:", likes if likes is not None else "Unknown")
print("Comments:", comments if comments is not None else "Unknown")
print("Caption:", caption_text[:100])
print("---")
Understanding the response
The endpoint returns an items array containing media objects.
Depending on the available information, these objects may include:
- Media identifiers.
- Captions.
- Like counts.
- Comment counts.
- Publication timestamps.
- Media metadata.
Some fields may be unavailable or have different values depending on the account or media type.
For example, a missing like count should be treated as unknown rather than automatically interpreted as zero.
Pagination
The feed endpoint typically returns a page of recent posts.
To retrieve additional pages, you need a pagination cursor.
The documented response schema includes next_max_id, which can be passed as the after parameter.
Example:
next_cursor = feed.get("next_max_id")
if feed.get("more_available") and next_cursor:
response = requests.get(
"https://api.gramapi.com/raw/ig/user/feed",
params={
"url": "nasa",
"after": next_cursor
},
headers={"X-Api-Key": API_KEY},
timeout=40
)
response.raise_for_status()
next_page = response.json()
Each additional page requires another API request.
Pagination is particularly useful when building applications that need historical content or larger collections of posts.
4. Track Instagram Follower Growth Over Time
Now let's build something more practical.
Instead of requesting profile information manually, we'll create a Python script that collects statistics for several Instagram accounts and saves the results to a CSV file.
This allows us to compare follower counts between different dates.
Our script will:
- Read a list of Instagram usernames.
- Retrieve their profile statistics.
- Load previously saved statistics.
- Calculate follower changes.
- Append the latest results to a CSV file.
Complete Python script
Create a file named track.py:
import csv
import os
import time
from datetime import datetime, timezone
from pathlib import Path
import requests
API_KEY = os.environ["GRAMAPI_KEY"]
BASE_URL = "https://api.gramapi.com"
ACCOUNTS = [
"nasa",
"lego",
"bellroy"
]
CSV_FILE = Path("instagram_snapshots.csv")
FIELDS = [
"checked_at",
"username",
"followers",
"following",
"posts"
]
def get_profile(username):
response = requests.get(
f"{BASE_URL}/raw/ig/user/info",
params={"url": username},
headers={"X-Api-Key": API_KEY},
timeout=40
)
response.raise_for_status()
data = response.json()
user = data.get("user")
if not isinstance(user, dict):
raise ValueError("Profile data was not returned")
return user
def load_previous_snapshots():
previous = {}
if not CSV_FILE.exists():
return previous
with CSV_FILE.open(
"r",
newline="",
encoding="utf-8"
) as file:
reader = csv.DictReader(file)
for row in reader:
previous[row["username"]] = row
return previous
def main():
previous = load_previous_snapshots()
file_exists = CSV_FILE.exists()
timestamp = datetime.now(
timezone.utc
).isoformat(timespec="seconds")
with CSV_FILE.open(
"a",
newline="",
encoding="utf-8"
) as file:
writer = csv.DictWriter(
file,
fieldnames=FIELDS
)
if not file_exists:
writer.writeheader()
for index, username in enumerate(ACCOUNTS):
# Free and Starter plans allow 1 RPS.
if index > 0:
time.sleep(1.1)
try:
user = get_profile(username)
except (requests.RequestException, ValueError) as error:
print(f"{username}: request failed: {error}")
continue
followers = user.get("follower_count")
if followers is None:
print(f"{username}: follower count unavailable")
continue
row = {
"checked_at": timestamp,
"username": user.get("username", username),
"followers": followers,
"following": user.get("following_count"),
"posts": user.get("media_count")
}
writer.writerow(row)
old = previous.get(row["username"])
if old and old.get("followers"):
change = (
int(followers)
- int(old["followers"])
)
print(
f"{row['username']}: "
f"{followers:,} followers "
f"({change:+,} since last check)"
)
else:
print(
f"{row['username']}: "
f"{followers:,} followers "
"(first snapshot)"
)
if __name__ == "__main__":
main()
Run the script
python track.py
On the first run, the script retrieves the current statistics and creates:
instagram_snapshots.csv
Example CSV structure:
checked_at,username,followers,following,posts
2026-10-15T09:00:00+00:00,nasa,100000000,80,4000
2026-10-15T09:00:00+00:00,lego,12000000,1200,6000
The values above are illustrative, not actual account statistics.
When you run the script again, it loads the previous values and calculates the difference.
For example:
nasa: 100,005,000 followers (+5,000 since last check)
lego: 12,001,200 followers (+1,200 since last check)
Now you have a basic Instagram follower growth tracker.
The data can be opened in Excel, Google Sheets, or processed with pandas.
5. Automate Daily Data Collection
Running the script manually works, but collecting data at consistent intervals is more useful for trend analysis.
On Linux and macOS, you can use cron to schedule the script.
For example, to run it every morning at 9:00:
0 9 * * * /path/to/run.sh >> /path/to/tracker.log 2>&1
Your run.sh script should load the API key from a secure location, change to the project directory, and execute track.py.
Example:
#!/bin/sh
set -a
. "$HOME/.config/gramapi.env"
set +a
cd "$HOME/instagram-tracker" || exit 1
exec "$HOME/instagram-tracker/.venv/bin/python" track.py
Keep the environment file outside your repository and restrict its permissions:
chmod 600 ~/.config/gramapi.env
The file should contain:
GRAMAPI_KEY=your_api_key_here
Update the paths to match your environment.
On Windows, you can use Task Scheduler instead.
Once scheduled, the script will gradually build a dataset containing daily snapshots.
After several weeks, you can use the CSV file to create charts or identify unusual changes in follower counts.
6. API Rate Limits and Request Costs
When building automated data collection workflows, it's important to understand rate limits and usage-based billing.
According to GramAPI's documentation, request limits depend on the selected plan.
| Plan | Requests per second |
|---|---|
| Free | 1 |
| Starter | 1 |
| Growth | 2 |
| Business | 3 |
| Pro | 5 |
| Scale | 10 |
For our example, the script pauses between requests to stay within the Free and Starter plan limits.
How many requests will the tracker use?
Suppose you're monitoring 50 Instagram accounts once per day.
That means:
50 accounts Γ 30 days = 1,500 requests/month
If every profile lookup succeeds, that's approximately 1,500 billable requests.
GramAPI currently offers a Starter package with:
- 10,000 requests.
- $12 one-time payment.
- No expiration date for purchased credits.
At 50 successful profile checks per day, 10,000 requests would last approximately six months.
Actual consumption depends on the number of accounts, additional API calls, retries, and other billable responses.
A failed request is not always free. Always review the API's billing rules before implementing automatic retries.
7. Handling API Errors
Production applications need to handle unsuccessful requests.
GramAPI returns HTTP status codes and structured error responses.
Here are some common cases:
| HTTP status | Meaning | Charged? |
|---|---|---|
| 200 | Successful request | Yes |
| 400 | Invalid request or upstream rejection | Depends on error |
| 401 | Missing or invalid API key | No |
| 402 | Insufficient request balance | No |
| 403 | Disabled key or suspended account | No |
| 404 | Resource or endpoint unavailable/not found | No |
| 429 | Rate limit exceeded | No |
| 500 | Upstream processing error | No |
| 503 | Upstream unavailable | No |
For HTTP 400, the distinction matters:
- Requests rejected by GramAPI because of missing or unparseable parameters are not charged.
- Requests that Instagram processes and rejects may be charged.
Handling rate limits
When you receive HTTP 429, check the Retry-After header.
A simple approach:
import time
if response.status_code == 429:
retry_after = float(
response.headers.get("Retry-After", "2")
)
time.sleep(max(retry_after, 1))
After waiting, your application can retry the request.
For production applications, consider implementing bounded retries, exponential backoff, and request logging.
Avoid automatically retrying every HTTP error: some errors indicate invalid input or exhausted credits and require a different response.
8. What Can You Build Next?
The follower tracker is just a starting point.
Once you have a reliable way to request and store Instagram data, you can extend the application.
Influencer Analytics
Collect profile information and available engagement metrics to help evaluate public accounts.
Competitor Monitoring
Track posting frequency, follower changes, and publicly available activity across selected accounts.
Social Media Dashboards
Build visualizations that summarize profile statistics and content performance over time.
Automated Reports
Generate periodic reports for marketing teams using Python, pandas, spreadsheets, or other reporting tools.
Custom Alerts
Notify users when monitored metrics change significantly.
For larger applications, consider replacing CSV files with PostgreSQL or another database.
You can also separate data collection, processing, and reporting into independent components.
Conclusion
In this tutorial, we built a Python workflow that:
- Retrieves Instagram profile information through a REST API.
- Fetches recent posts and available engagement metrics.
- Stores follower statistics in a CSV file.
- Calculates changes between collection dates.
- Can run automatically on a schedule.
The same approach can be extended into a more advanced analytics platform, monitoring tool, or automated reporting system.
We used GramAPI as the data provider.
You can find the API reference here:
The main takeaway is that once the data is available as structured JSON, Python makes it straightforward to build useful applications around it.
Top comments (0)