<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Tech Experiments]]></title><description><![CDATA[Tech Experiments]]></description><link>https://techexperiments.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 30 Oct 2026 09:10:38 GMT</lastBuildDate><atom:link href="https://techexperiments.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Selecting Giveaway Winners from Instagram Post Comments with HikerAPI]]></title><description><![CDATA[This is useful for developers who run Instagram giveaways and need a reliable way to pull the full list of commenters from a public post so they can pick…]]></description><link>https://techexperiments.hashnode.dev/selecting-giveaway-winners-from-instagram-post-comments-with-hikerapi</link><guid isPermaLink="true">https://techexperiments.hashnode.dev/selecting-giveaway-winners-from-instagram-post-comments-with-hikerapi</guid><category><![CDATA[Python]]></category><category><![CDATA[instagram]]></category><category><![CDATA[ instagram growth ]]></category><category><![CDATA[marketing]]></category><dc:creator><![CDATA[Anand Chhatpar]]></dc:creator><pubDate>Wed, 14 Oct 2026 22:16:13 GMT</pubDate><content:encoded><![CDATA[<p>This is useful for developers who run Instagram giveaways and need a reliable way to pull the full list of commenters from a public post so they can pick winners programmatically. Manual scrolling or copy-paste stops being viable past a few hundred comments; the official Graph API only covers accounts you own; and long-running scraper or private-client sessions tend to get blocked.</p>
<p>HikerAPI is a REST API that returns public Instagram data (profiles, media, comments, etc.) with an API key in the <code>x-access-key</code> header. Pricing starts at $0.001 per request with 100 free requests on signup. Documentation and signup are at <a href="https://hikerapi.com/help/instagram-private-api-alternatives?utm_source=hashnode&amp;utm_medium=rewards">HikerAPI</a>.</p>
<p>A minimal request looks like this:</p>
<pre><code class="language-python">import requests
headers = {"x-access-key": "YOUR_KEY"}
resp = requests.get("https://api.hikerapi.com/v2/fbsearch/topsearch", params={"query": "indie game dev"}, headers=headers)
print(resp.json())
</code></pre>
<h2>Fetching the media id from a post shortcode</h2>
<p>Most giveaway posts are identified by shortcode (the part after <code>/p/</code> in the URL). The media info endpoint returns the numeric id required by the comments endpoint.</p>
<pre><code class="language-python">import requests

API_KEY = "YOUR_KEY"
BASE = "https://api.hikerapi.com"
headers = {"x-access-key": API_KEY}

def get_media_id(shortcode: str) -&gt; str:
    resp = requests.get(
        f"{BASE}/v2/media/info/by/code",
        params={"code": shortcode},
        headers=headers,
        timeout=30,
    )
    resp.raise_for_status()
    data = resp.json()
    # response shape varies slightly by version; adjust if the field is nested under "media" or "items"
    return str(data.get("pk") or data.get("id") or data["response"]["pk"])

media_id = get_media_id("Cxxxxxxxx")  # replace with the real shortcode
</code></pre>
<h2>Paginating comments and collecting commenters</h2>
<p>The comments endpoint returns roughly 15 comments per request. Pagination is driven by the <code>page_id</code> (or equivalent cursor) returned in the previous response. The loop below accumulates unique usernames until the end of the comment list.</p>
<pre><code class="language-python">def fetch_all_commenters(media_id: str) -&gt; list[str]:
    commenters = set()
    page_id = None

    while True:
        params = {"id": media_id}
        if page_id:
            params["page_id"] = page_id

        resp = requests.get(
            f"{BASE}/v2/media/comments",
            params=params,
            headers=headers,
            timeout=30,
        )
        resp.raise_for_status()
        payload = resp.json()

        # v2 responses often nest under "response"
        body = payload.get("response", payload)
        items = body.get("items", [])

        for item in items:
            user = item.get("user") or {}
            username = user.get("username")
            if username:
                commenters.add(username)

        paging = body.get("paging_info") or {}
        page_id = paging.get("max_id") or paging.get("next_max_id")
        more = paging.get("more_available", False)

        if not more or not page_id:
            break

    return sorted(commenters)
</code></pre>
<h2>Selecting winners</h2>
<p>Once the set of commenters is in memory, selection is ordinary Python. The example below draws without replacement and writes the result to a file so the draw can be audited later.</p>
<pre><code class="language-python">import random
from datetime import datetime

def pick_winners(commenters: list[str], n: int, seed: int | None = None) -&gt; list[str]:
    if n &gt; len(commenters):
        raise ValueError(f"only {len(commenters)} unique commenters")
    rng = random.Random(seed)
    winners = rng.sample(commenters, n)
    return winners

commenters = fetch_all_commenters(media_id)
winners = pick_winners(commenters, n=3, seed=42)

print(f"total unique commenters: {len(commenters)}")
print("winners:", winners)

with open(f"winners_{datetime.utcnow().date()}.txt", "w") as f:
    f.write("\n".join(winners))
</code></pre>
<h2>Tradeoffs versus scraping and instagrapi</h2>
<p>Direct scraping (browser automation or raw HTTP against Instagram) requires maintaining session cookies, handling rate-limit challenges, and periodically rewriting selectors when the frontend changes. It also exposes the account used for the scrape to bans. The cost is engineering time and operational risk rather than per-request fees.</p>
<p>instagrapi is a private-API client that reverse-engineers the mobile endpoints. It can do more than read-only public data (including authenticated actions), but it needs a real Instagram account, is sensitive to Instagram’s client-side changes, and can trigger checkpoints or temporary locks. For a pure read of public comments the maintenance overhead is higher than a paid REST wrapper that absorbs those changes.</p>
<p>HikerAPI trades a small per-request cost for a stable, key-based interface that does not require an Instagram login. It is limited to public data and does not support writing comments or other mutations. For a one-off giveaway with a few thousand comments the free tier is usually sufficient; larger draws simply consume additional requests at the published rate. Pagination is explicit, so you control exactly how many calls are made and can resume from a stored cursor if a run is interrupted.</p>
]]></content:encoded></item></channel></rss>