Back to use cases

    Use case / SOCIAL DATA / Python 3 / Published

    Instagram Engagement Rate Calculator in Python

    Pull a public Instagram profile and its latest posts, then get the mean engagement rate, the median, and a split by image, carousel and video or reel.

    Card for Instagram Engagement Rate Calculator in Python

    Made by Desearch (desearch.ai).

    Instagram Engagement Rate Calculator is a small Python script for marketers. Give it one public Instagram username and it pulls the profile and the latest posts, then writes the engagement rate with the formula shown and a split by format (image, carousel, video/reel). You can add one or two peer accounts. Each account is calculated on its own.

    The problem

    A single viral post can make an account look more active than its recent feed is. Format matters too: a carousel and a video do not collect likes the same way. Copying likes, comments and follower counts out of a profile by hand is slow, and a pinned post or a post from the last day can skew the number. What helps is the formula written out, the mean next to the median, and a split by format.

    What the app does

    • Takes one public Instagram username, and optionally one or two peers.
    • Pulls the follower count and the latest posts (12 in the sample, capped at 20 in the script).
    • Computes a per-post engagement rate, then the mean and the median for the account.
    • Leaves out likely pinned posts, posts under 24 hours old, and posts with hidden likes, and counts what it skipped.
    • Splits the same formula by image, carousel and video/reel.
    • Writes a Markdown summary, three CSVs and a bar chart of engagement rate by format.

    How it works

    1. Profile. GET /desearch/instagram/profile/{username} for the follower count.
    2. Posts. GET /desearch/instagram/profile/{username}/posts with count for the latest posts. Each post can include likeCount, commentCount, mediaType and createTime.
    3. Skip. Likely pinned posts (listed first but older than the post after them), posts under 24 hours old, and posts with hidden likes stay out of the rate and are counted in the output.
    4. Rate. Per post: engagement rate % = (likes + comments) / followers x 100. The account rate is the mean of those rates. The median is shown next to it.
    5. Write. A summary, a posts CSV, a formats CSV and an SVG chart. Saves and shares are not in the data, so this is a likes plus comments rate.

    The code

    The script reads the API key only from a key file (~/.desearch_api_key by default, or --key-file PATH). It does not read environment variables. The request, copied from ig_engagement_rate.py on main (lines 49 to 63):

    PYTHON
    def call(session, path, params, label):
        at, t0 = now(), time.time()
        try:
            r = session.get(BASE + path, params=params, timeout=120)
            status, hdr = r.status_code, {k.lower(): v for k, v in r.headers.items()}
            try: body = r.json()
            except ValueError: body = {"_text": r.text[:3000]}
        except Exception as e:  # network error: keep going, record it
            status, hdr, body = None, {}, {"_error": repr(e)}
        rec = {"label": label, "path": path, "params": params, "at": at, "seconds": round(time.time() - t0, 2),
               "status": status, "cost_usd": hdr.get("x-desearch-cost-usd"), "usage_count": hdr.get("x-desearch-usage-count"),
               "headers": {k: v for k, v in hdr.items() if k.startswith("x-desearch") or k == "date"}, "body": body}
        n = len(body) if isinstance(body, list) else (1 if status == 200 else 0)
        print(f"{at} {label:28s} {status} {rec['seconds']:6.2f}s items={n} cost={rec['cost_usd']}", file=sys.stderr, flush=True)
        return rec

    The per-post rate, from the same file (lines 119 to 127):

    PYTHON
    def post_row(account, followers, p, ref_time=None):
        s = p.get("stats") or {}
        likes, com = count_or_none(s.get("likeCount")), count_or_none(s.get("commentCount"))
        views = count_or_none(s.get("viewCount")) or count_or_none(s.get("playCount"))
        t = parse_time(p.get("createTime"))
        f, raw = fmt_of(p)
        hidden = likes is None
        er = round(100 * (likes + (com or 0)) / followers, 4) if followers and not hidden else None
        epv = round(100 * (likes + (com or 0)) / views, 3) if views and not hidden else None

    The folder has ig_engagement_rate.py, requirements.txt, samples/sample-summary.md, samples/live-run-2026-10-17.md and offline tests in tests/.

    View the code

    Endpoints

    • GET /desearch/instagram/profile/{username}
    • GET /desearch/instagram/profile/{username}/posts

    Example output

    Saved sample from a run at 2026-10-17T09:27:12+04:00 (09:27 Asia/Tbilisi) on three public brand accounts, shown as brand_a, brand_b and brand_c. This page shows that stored response. It does not run a live demo.

    Formula. Per post: engagement rate % = (likes + comments) / followers x 100. Account rate = the mean of the post rates. The median is shown next to it.

    accountfollowersposts used / returnedengagement rate %median %range %best format
    brand_a2683564976 / 120.05580.04230.0014 to 0.1699carousel (0.0858 %, n=3)
    brand_b1043757668 / 120.45250.24740.0527 to 1.8016carousel (0.8143 %, n=3)
    brand_c1756696412 / 120.39430.29720.0973 to 1.0892video/reel (0.4657 %, n=8)

    From sample-summary.csv, brand_a skipped 3 likely pinned posts and 3 posts under 24 hours (0 hidden likes). brand_b skipped 3 likely pinned posts and 1 post under 24 hours (0 hidden likes). brand_c skipped none. These are rates on the recent posts Desearch returned on 2026-10-17, not benchmarks.

    By format

    accountformatpostsavg likesavg commentsavg viewsengagement rate %median %
    brand_acarousel3229951.33410.08580.0636
    brand_aimage11620076370.06060.0606
    brand_avideo/reel222661.5870.00850.0085
    brand_bcarousel38470522884.70.81430.5454
    brand_bimage429189315850.28120.2474
    brand_bvideo/reel15437359032507610.05270.0527
    brand_ccarousel229873282.50.17160.1716
    brand_cimage2575386560.33130.3313
    brand_cvideo/reel880984.68300.46570.3393

    Each posts call returned the number of posts asked for (12 of 12 for three accounts). The call log in samples/live-run-2026-10-17.md:

    callstatussecondsposts returned
    GET /desearch/instagram/profile/brand_a2009.57
    GET /desearch/instagram/profile/brand_a/posts count=1220011.8712
    GET /desearch/instagram/profile/brand_b2006.64
    GET /desearch/instagram/profile/brand_b/posts count=1220011.2512
    GET /desearch/instagram/profile/brand_c2005.81
    GET /desearch/instagram/profile/brand_c/posts count=1220011.6312

    Run it yourself

    BASH
    git clone https://github.com/Desearch-ai/desearch-py-examples && cd desearch-py-examples/instagram-engagement-rate-calculator
    pip install -r requirements.txt
    printf '%s' 'YOUR_KEY' > ~/.desearch_api_key && chmod 600 ~/.desearch_api_key   # key from console.desearch.ai
    python ig_engagement_rate.py --accounts BRAND_ONE --count 12 --out output/brand

    With two peers: python ig_engagement_rate.py --accounts BRAND_ONE PEER_ONE PEER_TWO --count 12 --out output/brands.

    Useful flags: --count (posts per account, capped at 20), --include-pinned, --include-fresh, --raw-out, --key-file. To try it with no key and no cost: python ig_engagement_rate.py --from-raw samples/sample-raw.json --out output/sample.

    What it costs

    Instagram calls are priced per returned item. The price for each call is in the X-Desearch-Cost-Usd response header, and the script prints that header per call and as a sum. The saved sample does not include those header values, so this page does not state a dollar amount. See pricing.

    Ideas to extend it

    • Add one or two peer accounts and compare the format split.
    • Re-run the same accounts next month and compare the rates.
    • Pass --include-pinned or --include-fresh when you want those posts in the rate.

    Use with AI agents

    Point an MCP client at the hosted Desearch server. Replace the placeholder with a key from the console. Do not commit the key.

    JSON
    {
      "mcpServers": {
        "desearch": {
          "url": "https://mcp.desearch.ai/mcp",
          "headers": {
            "Authorization": "Bearer <DESEARCH_API_KEY>"
          }
        }
      }
    }

    Prompt you can paste for this example:

    Use Desearch GET /desearch/instagram/profile/{username} and GET /desearch/instagram/profile/{username}/posts for the public accounts I name. Compute engagement rate percent as (likes + comments) / followers x 100 per post, then the mean and the median of those rates, and split image, carousel and video/reel. Leave out likely pinned posts, posts under 24 hours old and posts with hidden likes. Label accounts the way the sample does. Do not invent likes, comments, views or follower counts.

    Build your own example.

    Give your agents access to web and social search. Get an API key to start building, or talk to us about your integration.

    Read docs