# Creator comment distribution and length features (`remarkable_whipscorpion/creator-comment-features`) Actor

Deterministic Unicode comment length and distribution features from authorized JSON. No scraping or authenticity judgments.

- **URL**: https://apify.com/remarkable_whipscorpion/creator-comment-features.md
- **Developed by:** [Kagerou AP](https://apify.com/remarkable_whipscorpion) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 creator snapshot processeds

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Creator comment distribution and length features

Turn your authorized comment JSON into consistent per-creator length and distribution features in one batch. Intended for agency analysts who have comment data but no reusable statistics module. No scraping, upstream API, model, authenticity score, or audience estimate. Existing notebooks can perform the same job; setup savings and willingness to buy this Actor remain unmeasured. MARLEY's adjacent commercial feature workflow is not evidence that MARLEY will buy this product.

### Fixed metric contract (v1)

Runtime: Node 24.18.0, ICU 78.3, Unicode 17.0. A differing runtime fails before processing or custom charging. `Intl.Segmenter('en', {granularity:'grapheme'})` counts extended grapheme clusters. Do not normalize or trim nonempty text. Whitespace-only comments (JavaScript `trim`) are empty, counted in `emptyN`, excluded from `sampleN` and every length denominator. Unpaired UTF-16 surrogates invalidate the entire row. Length limit also applies to empty comments before exclusion.

Sorted lengths use linear interpolation at index `(n-1)*p` (R type 7) for median, Q1, Q3 and p90. Mean and population standard deviation divide by `sampleN`. Outliers are strictly below `Q1-1.5*IQR` or above `Q3+1.5*IQR`; equality is not an outlier. Shares divide by nonempty `sampleN`. No rounding is applied. `sampleN=0` returns null metrics with reason `empty_sample`, custom fee zero. Single-sample standard deviation is zero.

Emoji classification is **unsupported** in v1: `emojiOnlyShare:null`, `emojiStatus:'unsupported'`, `emojiReason:'classifier_not_supplied'`. Do not interpret null as zero or use these features to infer fraud, bots, authenticity, sentiment or predictive quality.

### Input and output

Input is `{ "creators": [ ... ] }`. Each snapshot requires nonempty strings `rowId` and `creatorKey` (maximum 256 UTF-16 units), `sourceAt` (RFC3339 subset with uppercase T/Z or numeric zone, 0–3 fraction digits and seconds 00–59; leap seconds unsupported), and `comments` (array of strings). Optional `denominator` is a caller-supplied integer total comment count, at least the row's comment count. It is never inferred from audience or followers. Missing/unknown fields at row level are ignored; no field causes fetching. Root fields other than `creators` are ignored but count toward the byte cap. Extra text is never returned. Caller is responsible for authorization.

Hard run limits: 100 input snapshot rows, 100 comments per row, 10,000 comments in all arrays, 8,388,608 UTF-8 bytes of serialized input, 500 graphemes per comment. Root byte/row/total-count violations fail the run before custom fees; row-specific violations yield `invalid` and fee zero. IDs and sourceAt are retained when they meet their type/length contract; other malformed values become null. `inputIndex` always preserves the reference, even repeated rowIds or creatorKeys. No raw comments or descriptions are output or routinely logged.

Snapshot identity is SHA256 of the JSON tuple `[metricVersion,creatorKey,sourceAt,comments]`, preserving comment order and exact text. Only valid nonempty identical snapshots within one run are evaluated and charged once. Every row reference/order is retained, with per-row coverage and denominator. Different timestamps, creator keys, comment order or text create distinct snapshots. Different rowId or denominator does not. This is run-local deduplication, not a promise of deduplication across runs/restarts.

Output rows contain references, `status` (`processed`, `empty`, `invalid`, `budget_exhausted`), reason, snapshotId, counts, length metrics, outlier count/share, emoji fields, caller denominator/coverage, warnings, metricVersion and `billing`. All null metrics have a reason. `coverage` is supplied comments / caller denominator (0 denominator gives null); missing denominator warns `caller_denominator_not_supplied`. No population representativeness is claimed.

Example input:

```json
{"creators":[{"rowId":"r1","creatorKey":"creator-a","sourceAt":"2026-10-10T00:00:00Z","comments":["a","ab","abc","abcd"],"denominator":8}]}
```

Example feature values: `sampleN:4`, `emptyN:0`, mean/median 2.5, p90 3.7, populationStdDev 1.118033988749895, Q1 1.75, Q3 3.25, outlier count/share 0, coverage 0.5, emojiOnlyShare null. Exact runnable input/output live in `sample/`.

### Price and PPE publication configuration

Price hypothesis: **$0.005 per distinct valid nonempty creator snapshot**, event `creator_snapshot_processed`. Empty, invalid and unprocessed rows: custom $0. Duplicate references: custom $0 additional. Native automatic `apify-actor-start`: **$0.00005 additional per run**, assuming the native event retains that price and the deployed RAM limit is applied. The Actor metadata specifies default/minimum **256MiB**, maximum **512MiB**, and Standby disabled (`usesStandbyMode:false`). Both allowed RAM sizes are below the native 1GB threshold for one start event; this Actor never manually charges start. Publisher must remove `apify-default-dataset-item` so the result is not charged again when saved. Plain `Actor.pushData` has no custom event argument; custom charging is once through `Actor.charge`. The wrapper refuses PPE runs with missing/wrong custom price, unexpected paid events, or paid default-dataset event.

The checked-in `.actor/ppe.json` is a publisher checklist, not a platform-recognized monetization setting. Before publication set PPE (without usage transfer), the native start event and the sole custom event in Console, remove dataset event, select custom as primary, and verify actual Store prices. `maxTotalChargeUsd` / `ACTOR_MAX_TOTAL_CHARGE_USD` governs SDK budget. The wrapper preserves an explicitly configured zero as zero custom capacity (SDK 3.7.2 internally maps 0 to Infinity). Before computing a new snapshot, both SDK capacity and strict money capacity must allow a full unit. Caller/native limits are interpreted as their Number decimal strings and floored to integer microUSD; the lower limit applies. Current SDK charged counts consume exact fixed prices of 5000 microUSD/custom and 50 microUSD/native start. This conservative check also rejects tiny below-unit limits that SDK rounding admits. Units are saved successfully and made accessible before a single count1 charge. The final paid unit is already saved when `eventChargeLimitReached` is true; cached references and free rows remain visible, while subsequent new snapshots return `budget_exhausted`. Local test PPE prices differ from Store prices and prove no real sale. Non-PPE local runs process features with custom chargedUnits zero.

Paid candidate dataset rows contain `billing.chargedUnits:null` and `billing.chargeStatus:'pending_native_ledger'`: saving happens before the charge response, so these rows do not claim a settled fee. Consult the native run's `chargedEventCounts`/event ledger for actual charges. The wrapper's return-only acknowledgement sets chargedUnits to accepted count0/1 and chargeStatus to `not_charged`/`accepted`; it never rewrites or mutates the saved row. Free and duplicate rows retain chargedUnits0. A charge rejection with count0 leaves that processed result accessible and stops new snapshots; duplicate references remain free.

Output-storage failure or stop before successful save yields no custom charge. Charge/API failure after save stops without automatic retry and retains the accessible result with pending metadata; reconcile native run/event state before any retry of ambiguous acceptance. Abrupt platform abort/migration and cross-run retry are not transactionally recovered, and repeating a run can charge again. No database or hidden retry service is provided.

Paid/free plans and eligible creator revenue differ. For eligible paid events, nominal creator share is 80% before platform usage and other costs; free runs are not evidence of creator revenue. At 100 distinct valid snapshots custom retail is $0.50 plus automatic start, nominal eligible share $0.40 before usage. Compute/storage are creator costs for this PPE-only proposal; upstream cost is zero. Actual runtime margin, sales, conversion and buyer time savings are unknown.

### Run and publish

Use Node 24.18.0. `npm ci`, `npm test`, `npm run sample` (deterministic offline core, no fees). `npm start` uses the Apify SDK and default INPUT/KVS/dataset. SDK dependency is pinned at 3.7.2 and locked; core uses only Node built-ins. Apify SDK is Apache-2.0; dependencies/license inventory is in the implementation report. No proprietary model is copied. Raw input remains in platform INPUT under its normal storage/retention settings; do not submit data without permission.

Separate publisher, after independent QA and management approval, uploads/builds using existing Console Web IDE or authenticated official CLI, runs the small sample privately under a cost cap, checks actual output and event counts, applies `.actor/ppe.json`, verifies the native start/dataset policy, and publishes the listing. Do not equate upload, cloud build, local tests or SDK test logs with public pricing, eligible sales or E5 evidence. Account authentication, payment/KYC and any real consent are handled by the publisher/owner in official UI; no secrets belong in chat. API/MCP use the native authenticated Apify interfaces, with no new server. Stop before publishing if this runtime's Unicode version differs.

Before publication, verify the built Actor's recognized `defaultMemoryMbytes:256`, `minMemoryMbytes:256`, `maxMemoryMbytes:512` and `usesStandbyMode:false`, and that the deployed run enforces the maximum. Retain the existing 60-second default timeout and 100-row input cap; `defaultRunOptions.timeoutSecs:60` remains in the local file, but it is not listed in the current actor.json reference, so the publisher must set/verify the actual default timeout in Console. The checked-in metadata and PPE checklist are locally checked only; cloud memory enforcement, Standby state, sample resource sufficiency and the native one-start $0.00005 charge remain unverified. Do not publish if these checks fail.

This is a 30-day bounded market experiment: stop if 100 qualified views (or 20 non-owner completed runs) produce zero eligible external paid buyers. Insufficient exposure is inconclusive; stop maintenance within the cap anyway. Owner work estimate 0.45–1 hour/month, stop at 2 hours/month; initial external cash cap $10 with at most $5 post-listing loss reserve inside that cap. No monitor/automatic follow-up is installed. Improve only after verified external eligible purchase.

Official references checked 2026-10-10: [SDK charging](https://docs.apify.com/sdk/js/reference/class/ChargingManager), [charge result](https://docs.apify.com/sdk/js/reference/interface/ChargeResult), [PPE](https://docs.apify.com/actors/publishing/monetize/pay-per-event), [pricing and costs](https://docs.apify.com/actors/publishing/monetize/pricing-and-costs), [publishing](https://docs.apify.com/actors/publishing/publish), [Actor metadata](https://docs.apify.com/actors/development/actor-definition/actor-json), [allowed memory allocations](https://docs.apify.com/actors/running/usage-and-resources).

# Actor input Schema

## `creators` (type: `array`):

Up to 100 rows: rowId, creatorKey, sourceAt RFC3339, comments (up to 100 strings, each <=500 graphemes), optional caller total denominator. Authorized data only.

## Actor input object example

```json
{
  "creators": [
    {
      "rowId": "r1",
      "creatorKey": "creator-a",
      "sourceAt": "2026-10-10T00:00:00Z",
      "comments": [
        "a",
        "ab",
        "abc",
        "abcd"
      ],
      "denominator": 8
    }
  ]
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "creators": [
        {
            "rowId": "r1",
            "creatorKey": "creator-a",
            "sourceAt": "2026-10-10T00:00:00Z",
            "comments": [
                "a",
                "ab",
                "abc",
                "abcd"
            ],
            "denominator": 8
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("remarkable_whipscorpion/creator-comment-features").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 = { "creators": [{
            "rowId": "r1",
            "creatorKey": "creator-a",
            "sourceAt": "2026-10-10T00:00:00Z",
            "comments": [
                "a",
                "ab",
                "abc",
                "abcd",
            ],
            "denominator": 8,
        }] }

# Run the Actor and wait for it to finish
run = client.actor("remarkable_whipscorpion/creator-comment-features").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 '{
  "creators": [
    {
      "rowId": "r1",
      "creatorKey": "creator-a",
      "sourceAt": "2026-10-10T00:00:00Z",
      "comments": [
        "a",
        "ab",
        "abc",
        "abcd"
      ],
      "denominator": 8
    }
  ]
}' |
apify call remarkable_whipscorpion/creator-comment-features --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,remarkable_whipscorpion/creator-comment-features"
        }
    }
}
```

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/tvoOTnQegISjid1PY/builds/nS2XBl0EYuO7XcULJ/openapi.json
