# Influencer Campaign Tracker — GRIN Alternative (`khadinakbar/grin-alternative`) Actor

Track public Instagram, TikTok, and YouTube campaign posts from supplied URLs. Export views, likes, comments, caption matches, sponsorship cues, and optional fee-based metrics for deliverable review.

- **URL**: https://apify.com/khadinakbar/grin-alternative.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Social media, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 campaign post reports

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Influencer Campaign Tracker — GRIN Alternative

Track public Instagram, TikTok, and YouTube campaign posts from supplied URLs. Export views, likes, comments, caption matches, sponsorship cues, and optional fee-based metrics for deliverable review. For campaign analysts, each dataset row represents one checked creator post with its public metrics and requested campaign checks.

### Workflow: put the results to work

Use the deliverable URLs from your campaign brief as the starting list. Add the campaign terms and any agreed fee, then review caption matches alongside public engagement. Earlier snapshots let you compare the same posts without treating public counters as proof of sales attribution.

### Best fit and how this compares with GRIN

Use this Actor to audit known campaign deliverables, check caption hashtags or mentions, compare public counters with an earlier snapshot, or calculate cost per thousand public views from a fee you supply.

| Decision | This Actor | GRIN |
|---|---|---|
| Campaign reporting | Source-linked reports for supplied public post URLs | Connected creator programs with campaign reporting |
| Creator discovery | Start with known post URLs | Creator discovery and recruitment workflows |
| Relationships and payments | Export reports into your own workflow | Relationship management, activation, product seeding, and creator payments |
| Revenue | Public counts and caller-supplied fee calculations | Program reporting and revenue-oriented creator operations |
| Automation | Bounded API runs, Apify schedules, and dataset exports | An integrated creator-management workspace |
| Price comparison | Per-report charges plus platform usage | Confirm the current GRIN offer for your program |

Choose GRIN when you need the connected creator relationship, outreach, product, payment, or attributed-revenue workflow. Choose this Actor when your job starts with known public post URLs and ends with a structured campaign-content report. Cost and operator efficiency comparisons require an equivalent workload benchmark. GRIN-side costs and elapsed time remain unverified, so choose on workflow fit.

GRIN is a trademark of its owner. This independent Actor is not affiliated with, associated with, or endorsed by GRIN. Instagram, TikTok, and YouTube are trademarks of their respective owners. This Actor is independent of those platforms.

### Workflow: from deliverable URLs to campaign review

An agency receives creator post links from its campaign coordinator. The analyst supplies those URLs and the expected campaign phrase, then checks `campaignMatch`, `matchedTerms`, and the public counters in the output. A missing caption match sends the post to manual review: a logo in the video, spoken disclosure, or edited caption may explain the difference.

For the next review, retain the earlier `sourceUrl`, `collectedAt`, and counters and supply them as `previousSnapshots`. The report shows the changes. A negative change remains negative because platforms can revise counters. Each snapshot is independent; the Actor does not maintain a shared history or send messages.

### Quick start

1. Collect the public permalinks for your campaign deliverables.
2. Add the campaign terms you want to check and set a batch limit.
3. Start the Actor and inspect its outcome before exporting reports.

This public demonstration checks the title of a known YouTube video. It is a functional example, not a claimed sponsorship:

```json
{
  "postUrls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"],
  "campaignName": "Zoo content review",
  "campaignTerms": ["zoo"],
  "maxPosts": 20
}
```

### Input reference

| Field | Default and behavior |
|---|---|
| `postUrls` | 1–100 full public permalinks; duplicate post identities are checked once |
| `campaignName` | `Campaign`; a label copied to each report |
| `campaignTerms` | `[]`; up to 20 case-insensitive keywords, phrases, hashtags, or mentions |
| `matchMode` | `any`; use `all` to require every term |
| `onlyMatches` | `false`; enable to export only matching posts when terms are present |
| `maxPosts` | `20`; 1–20 unique posts checked per run |
| `providerOrder` | `scrapecreators-first`; `sociavault-first` reverses the tested provider order |
| `feePerPostUsd` | `0`; a positive known fee, applied equally to each post, enables cost metrics |
| `previousSnapshots` | `[]`; one earlier record per post with `sourceUrl`, past ISO `collectedAt`, and available counters |

Use full TikTok `/@handle/video/id` links. Instagram `/p/` and `/reel/` links work; YouTube watch, shorts, live, and youtu.be permalinks normalize to a video identity. Short redirect links and private posts require a different workflow. URL tracking parameters are discarded.

To compare snapshots, add this structure to your input with your actual earlier counters:

```json
{
  "postUrls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"],
  "previousSnapshots": [
    {
      "sourceUrl": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
      "collectedAt": "2026-01-01T00:00:00Z",
      "views": 100000000,
      "likes": 1000000
    }
  ]
}
```

The baseline numbers above illustrate the format; they are not historical measurements.

### What data you receive

Download the dataset as JSON, CSV, or Excel using Apify's export controls. The `overview` view shows the main campaign columns; JSON preserves the full record.

| Fields | Meaning |
|---|---|
| `sourceUrl`, `postId`, `platform` | Verified post identity and canonical source |
| `creatorHandle`, `title`, `caption` | Available public creator and content text |
| `views`, `likes`, `comments`, `shares` | Available public counters; unknown values remain `null` |
| `campaignMatch`, `matchedTerms` | Caption/title term matching; `null` when no terms were requested |
| `disclosureTerms`, `platformPaidPromotion` | Visible text cues and a platform flag where available |
| `engagements`, `engagementRateByViewsPct` | Likes plus comments, and that sum divided by public views |
| `viewsChange`, `likesChange`, `commentsChange`, `sharesChange` | Current counters minus the supplied baseline |
| `feePerPostUsd`, `costPerThousandViewsUsd` | Caller-provided fee and fee multiplied by one thousand, divided by public views |
| `collectedAt`, `publishedAt`, `provider` | Collection time, available publication time, and data provider |

A shortened output example from the public video workflow:

```json
{
  "platform": "youtube",
  "postId": "jNQXAC9IVRw",
  "sourceUrl": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
  "title": "Me at the zoo",
  "campaignMatch": true,
  "matchedTerms": ["zoo"],
  "shares": null,
  "provider": "scrapecreators"
}
```

Public views are not unique reach, impressions, conversions, or authenticated analytics. Instagram views cover the exposed Instagram count. Engagement calculations require both likes and comments. Sponsorship cues are text observations, not a judgment about a creator's compliance or relationship with a brand. TikTok paid-promotion flags are left unknown where their interpretation is not verified.

### API and scheduled reporting

Start a run with your Apify token in the Authorization header:

```bash
curl --request POST \
  'https://api.apify.com/v2/acts/khadinakbar~grin-alternative/runs?waitForFinish=60&maxTotalChargeUsd=1' \
  --header "Authorization: Bearer $APIFY_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"postUrls":["https://www.youtube.com/watch?v=jNQXAC9IVRw"],"campaignTerms":["zoo"]}'
```

Read the returned run status. Once terminal, use its `defaultDatasetId` to retrieve `/v2/datasets/{defaultDatasetId}/items`; use `defaultKeyValueStoreId` to read `OUTPUT` and `RUN_SUMMARY`. Paginate dataset reads with `offset` and `limit`. Each input batch is independent, and there is no upstream cursor to resume.

Save your campaign input as an Apify task and attach an Apify schedule for repeat checks. Export each run's snapshot to your own history and provide the previous values explicitly when you want changes. Webhooks can notify your own pipeline when execution completes.

### AI agent prompt card

> Check these supplied public campaign post URLs, at most 20. Match the campaign terms in captions and titles. Return source URLs, public counters, matches, missing fields, and the terminal outcome. Keep the run within my Apify spending cap. Use caller-supplied baselines only when available, and never infer sales or audience demographics.

Why choose this tool: a known post URL maps to one report with explicit provenance and unknown fields. Before calling, an agent should verify the post URLs, campaign terms, batch size, and fee assumptions. After calling, inspect `OUTPUT` and `RUN_SUMMARY`, then read the dataset. Handle provider outages as unavailable data.

For MCP client configuration, use the [current Apify MCP setup](https://mcp.apify.com). This release's verification uses the REST API; individual MCP clients and Apify AI discovery are separate checks, not implied by the prompt example.

### Outcomes and recovery

| Outcome | What to do |
|---|---|
| `COMPLETE` | Use the saved reports |
| `VALID_EMPTY` | All checked posts were filtered out; review campaign terms |
| `PARTIAL` | Use saved reports and review omitted or unavailable URLs |
| `INVALID_INPUT` | Correct the input diagnostic and rerun |
| `UPSTREAM_FAILED` | All required lookups were unavailable; retry later or check source availability |
| `CONFIG_ERROR` | Report the owner configuration or runtime issue through the Issues tab |

### Best results

Batch related deliverables and use narrow campaign phrases. Keep raw snapshots so missing and revised counters remain understandable. Confirm caption misses manually, especially when a campaign mention is spoken or displayed visually. The internal four-minute deadline preserves completed results before a longer platform timeout.

### Builder's note

In my testing, the same post arrived inside different nested response envelopes. The parser now verifies the requested post identity and requires public counter evidence before saving or charging. That protects the report from a successful HTTP response containing a hollow or unrelated object. Missing counts remain unknown rather than being converted to zero.

### Responsible use and support

Use public posts you are authorized to research and follow applicable platform terms, data rights, and retention requirements. The Actor stores reports in the run's Apify dataset and diagnostic records in its key-value store; manage their retention in your Apify account. It does not send outreach, edit posts, download media, process creator payments, or access private GRIN data. Use the [Issues tab](https://apify.com/khadinakbar/grin-alternative/issues) for reproducible problems, including the affected run ID and a public example when appropriate.

### Pricing and run costs

This Actor uses **Pay per event plus Apify platform usage**. The [Pricing tab](https://apify.com/khadinakbar/grin-alternative/pricing) lists the current event rates and billing terms.

| Event | Billing unit | When it applies |
|---|---|---|
| `apify-actor-start` | Actor Start | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). |
| `campaign-post-report` | Campaign post report | One validated post report persisted with public metrics and requested campaign checks. |

Run cost combines the charged events and Apify platform usage. Review the run charge limit and requested result count before starting.

# Actor input Schema

## `postUrls` (type: `array`):

Provide public Instagram post/reel, TikTok video, or YouTube video URLs. Use full permalinks. Duplicate posts are checked once. Each run checks up to maxPosts unique URLs.

## `campaignName` (type: `string`):

Label the reports for your campaign. This label does not search for posts. Use a short project name. It is copied to every report.

## `campaignTerms` (type: `array`):

Match up to 20 keywords, phrases, hashtags, or mentions in public captions and titles. Matching is case-insensitive with word boundaries. Empty terms disable campaign matching. Visual and spoken mentions are outside this check.

## `matchMode` (type: `string`):

Choose any to accept at least one term. Choose all to require every term. Matching uses public caption and title text. Missing matches do not prove a partnership was absent.

## `onlyMatches` (type: `boolean`):

Export only posts matching the supplied campaign terms. All supplied URLs are still checked within the cap. Unmatched posts do not incur a report event. Leave off to audit both matching and nonmatching deliverables.

## `maxPosts` (type: `integer`):

Limit each run to 1–20 unique posts. Excess URLs are left for another batch. The summary identifies an applied cap. Duplicates do not consume the limit.

## `providerOrder` (type: `string`):

Use ScrapeCreators first by default. SociaVault provides fallback when a lookup fails or lacks required evidence. Reverse the order for an independent provider check. Keys are configured by the Actor owner.

## `feePerPostUsd` (type: `number`):

Supply the same known creator fee for each post in this batch. A positive fee enables cost-per-thousand-public-views calculations. Zero leaves cost metrics unknown. This does not estimate revenue, reach, or attributed sales.

## `previousSnapshots` (type: `array`):

Supply earlier sourceUrl, collectedAt, views, likes, comments, and shares records. Use one past ISO timestamp per post. Available counters are subtracted from current counters. Negative changes are preserved.

## Actor input object example

```json
{
  "postUrls": [
    "https://www.youtube.com/watch?v=jNQXAC9IVRw"
  ],
  "campaignName": "Campaign",
  "campaignTerms": [
    "zoo"
  ],
  "matchMode": "any",
  "onlyMatches": false,
  "maxPosts": 20,
  "providerOrder": "scrapecreators-first",
  "feePerPostUsd": 0,
  "previousSnapshots": [
    {
      "sourceUrl": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
      "collectedAt": "2026-01-01T00:00:00Z",
      "views": 100
    }
  ]
}
```

# Actor output Schema

## `reports` (type: `string`):

Read source-linked public post reports with caption matches, public counters and snapshot changes.

## `output` (type: `string`):

Read the terminal outcome, report counts, filtered counts and billing summary.

## `summary` (type: `string`):

Read provider attempts, charge reconciliation, source failures and run identifiers.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "postUrls": [
        "https://www.youtube.com/watch?v=jNQXAC9IVRw"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/grin-alternative").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "postUrls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"] }

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/grin-alternative").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "postUrls": [
    "https://www.youtube.com/watch?v=jNQXAC9IVRw"
  ]
}' |
apify call khadinakbar/grin-alternative --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/grin-alternative"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/qAlpuH6xCmEQqLxjy/builds/UqaEptYHn4jOPx0CA/openapi.json
