# How do I track a competitor’s follower growth on Instagram or TikTok?

Instagram. Checked September 2026.

Read the competitor’s public profile once a day with the Openhandle profile endpoint. Store `metrics.followers` and `capturedAt` each time. The growth chart is the difference between rows. The same call works for Instagram and TikTok, with the same response shape.

No API keeps follower history for an account you do not own. Instagram and TikTok publish only the current number. History starts the day you start reading.

## GET /v1/{platform}/profiles/@username?freshness=live

```bash
curl "https://api.openhandle.dev/v1/tiktok/profiles/@pixel_orchard_tt_test?freshness=live" \
  -H "Authorization: Bearer $OPENHANDLE_API_KEY"
```

```ts
import { OpenHandle } from '@openhandle/sdk';

const openhandle = new OpenHandle({ apiKey: process.env.OPENHANDLE_API_KEY! });

// Run once a day. Store id, capturedAt, and followers.
const { data, capturedAt } = await openhandle.tiktok.profile('pixel_orchard_tt_test').get({ freshness: 'live' });
await db.insert({ platform: 'tiktok', id: data.id, capturedAt, followers: data.metrics.followers });
```

200 OK:

```json
{
  "platform": "tiktok",
  "resource": "profile",
  "capturedAt": "2026-09-18T06:00:03Z",
  "source": "live",
  "data": {
    "id": "920000000001",
    "handle": "pixel_orchard_tt_test",
    "displayName": "Pixel Orchard",
    "metrics": { "followers": 75120, "following": 411, "posts": 4 }
  }
}
```

Trimmed to the fields this question needs. The Instagram profile endpoint returns the same shape with the same metric names. The example is a Test account, so you can run it on a free Test key.

## The recipe

1. **Store the ID on the first read.** Handles change. IDs do not. Look up by ID after the first call, and a rename never breaks the series.
2. **Read at the same time each day.** Use `freshness=live` so every row is a fresh read. A cache hit could repeat yesterday’s number.
3. **Keep `capturedAt`, not your cron time.** The capture time is when the platform showed the number. That is the timestamp the chart should use.
4. **Store nulls as nulls.** If a platform hides the count for a day, the row is `null`. Skip it in the chart. Never fill it with the previous value.

## What it costs

One profile read per account per day. A live read costs $0.0025. A 24-hour cache hit costs $0.0005, which is fine when several people in your team read the same account on the same day. Ten competitors read daily for a month is 300 live requests.

## Beyond the follower count

- **Posting rate.** Store `metrics.posts` in the same row. The delta is how many posts they published.
- **Engagement.** Read the profile posts endpoint with `since` set to your last run to get only new posts and their likes, comments, and views.
- **X and Reddit.** The same profile endpoint exists for X and Reddit, with `metrics.followers` and Reddit karma respectively.

## When this does not work

These answers are definitive. Store them as rows, do not retry them.

| Situation | Status | Code |
|---|---|---|
| The account went private | 403 | `PROFILE_PRIVATE` |
| The account is deleted, banned, or renamed without an ID lookup | 404 | `PROFILE_NOT_FOUND` |

```json
{
  "error": {
    "code": "PROFILE_NOT_FOUND",
    "message": "This profile was not found.",
    "requestId": "req_01j8…",
    "retryable": false
  }
}
```

A private or not-found day is data. Store the code with the date. A series that goes private and comes back tells you something too.

## Related

- [How do I get an Instagram follower count without logging in?](https://openhandle.dev/questions/how-do-i-get-an-instagram-follower-count-without-logging-in): The single read this recipe repeats.
- [Creator analytics use case](https://openhandle.dev/use-cases/creator-analytics): Growth charts and post performance built on scheduled reads.
- [Freshness and caching](https://openhandle.dev/docs/concepts/freshness-and-caching): Live, or up to 24 hours, 7 days, or 30 days old. You pick per request.
