# Throne Scraper (`huykenny/throne-scraper`) Actor

Scrape public Throne creator profiles and wishlists. Extract products, prices, brands, categories and merchants, analyze creator interests and sponsorship fit, and monitor wishlist changes.

- **URL**: https://apify.com/huykenny/throne-scraper.md
- **Developed by:** [Kenny Ha](https://apify.com/huykenny) (community)
- **Categories:** Social media, Lead generation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 enriched creators

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

## Throne Creator, Wishlist & Brand Intelligence

Turns public [Throne](https://throne.com) creator pages into structured commerce data: profiles, complete wishlists, normalized prices and merchants, brand and category classification, brand affinity, creator niches, sponsorship fit, and wishlist change monitoring.

Built for brands and influencer agencies who need to answer *"which creators already want what we sell, and what would it cost to send it?"* — with the reasoning visible, not just a score.

### What you get

| | |
|---|---|
| **Creator profile** | Username, display name, bio, main platform, social links the creator published themselves, account age |
| **Full wishlist** | Every publicly visible item, with prices in whole currency units, merchant, product URL, image, availability, collections |
| **Normalization** | Brand and category per item with a confidence and a source; stable product keys for matching the same product across creators |
| **Statistics** | Min / median / mean / trimmed mean / p25 / p75 / p90 / stdDev / price buckets — **per currency**, never summed across currencies |
| **Intelligence** | Brand affinity (0–100, formula published below), creator niches, commercial readiness signals, duplicate-product detection, sponsorship fit with reasons and blockers |
| **Cross-creator popularity** | Which products and brands the most creators want — counted per creator, not per item |
| **Monitoring** | New items, price drops and rises, availability flips, collection moves, crowdfunding progress, removals |

### Quick start

```json
{
  "mode": "profile",
  "creatorUrls": ["https://throne.com/cirely"],
  "outputLevel": "intelligence"
}
```

Usernames work too, in any shape you happen to copy: `cirely`, `@cirely`, `throne.com/cirely`, `https://throne.com/cirely?utm_source=x`.

### Modes

| Mode | What it does | Browser |
|---|---|---|
| `profile` | One creator in full detail. The cheapest way to try the Actor. | no |
| `batch` | Many creators. One failing creator never stops the run. | no |
| `discover` | Lists creators from Throne's public directory, newest accounts first. Metadata only — feed the result into `batch`. | no |
| `search` | Same work as `batch`, but only writes items matching your filters. | no |
| `monitor` | Compares against the previous run and reports what changed. | no |

### Output levels

`basic` — profile, social links, price statistics, top brands and categories. No item list. Use it to screen hundreds of creators.

`full` — everything in `basic`, plus the complete wishlist and collections.

`intelligence` — everything in `full`, plus brand affinity, niches, commercial signals, duplicate products and sponsorship fit.

### Measured performance

Real numbers from a run over 30 creators discovered from the sitemaps:

| | |
|---|---|
| Creators | 30 |
| Wishlist items | 511 |
| HTTP requests | 61 (**2.03 per creator**) |
| Downloaded | 2.1 MB (**70 kB per creator**) |
| Runtime | 13.8 s at concurrency 3 |
| Peak memory | 197 MB |
| Browser | never launched — no mode needs one |
| Proxy | not used |

Extrapolated to 1 000 creators: roughly **2 030 requests, 70 MB, and about 8 minutes** at the default concurrency. Raise `maxConcurrency` to trade politeness for speed.

Discovery is cheaper still: **40 creators with public wishlists came back in a single request**, scanning 300 profiles.

### How the numbers are made

Everything below is deterministic. There is no language model anywhere in this Actor — the same input always produces the same output, and the cost of a run does not depend on how chatty a wishlist is.

#### Prices

Throne stores money in **minor units** — `2403` means `$24.03`. This Actor converts once, in one module, using ISO 4217 exponents, so zero-decimal currencies (JPY, KRW) and three-decimal ones (KWD, BHD) come out right too.

**Shipping, tax and fees are separate fields and are never added to the item price.** If you want what a gifter actually pays, use `totalContribution` — that value comes from Throne, it is not our sum.

The original pre-discount price is the one field Throne sends inconsistently — sometimes in cents, sometimes in whole dollars. It is only returned when one of those readings is actually plausible as a higher former price; otherwise it is `null`. A missing field beats an invented discount.

**No currency conversion happens anywhere.** Statistics are computed per currency. A wishlist mixing USD and EUR gets two statistics blocks, never one meaningless total.

#### Brands

Resolved in order: the explicit brand field from Throne → merchant domain → a brand dictionary → parsing the product title. Each result carries a `confidence` and a `source`.

Names are unified so affinity does not split in half: `Jackbox Games, Inc.` and `Jackbox Games` become one brand, `SQUISHMALLOW` becomes `Squishmallows`, `Pokemon` and `Pokémon` converge — while deliberate capitalization like `LEGO`, `NVIDIA` and `HyperX` is left alone.

Ambiguous words are only accepted as brands when the title confirms them. `Apple iPhone 16 Pro Case` is Apple; `Apple Pie Silicone Baking Mold` is not. **When in doubt the brand is `null`** — an invented brand is worse than a missing one, because brand affinity is built on top of it.

#### Brand affinity (0–100)

| Component | Weight | Measures |
|---|---|---|
| `countShare` | 40 | share of wishlist items from that brand |
| `valueShare` | 30 | share of wishlist value |
| `featured` | 15 | the creator pinned an item of that brand |
| `recency` | 15 | an item of that brand was added in the last 90 days |

The result is multiplied by `evidenceFactor = min(1, itemCount / 3)`. Affinity means *repeated* preference, and one item is one data point. Without this, a single $3 539 sword — 78 % of one real wishlist's value — outranked a brand with five items.

Shares are **absolute**, relative to the whole wishlist. On a wishlist spread across 18 brands the strongest brand scores around 7 out of 100, and that is intentional: the score is meant to be comparable **across creators**, which is what you need when screening five hundred profiles. For "does this creator fit my brand?" use the sponsorship fit output, which works with shares directly.

#### Sponsorship fit

Only the criteria you fill in are scored; the rest are excluded from the formula rather than counted as zero. `budget`, `minimum wishlist size` and `max days inactive` are **hard gates** — fail one and the creator is reported as not a match whatever the score.

Every result carries `reasons` and `blockers` in plain language, plus up to ten concrete `matchingItems` — an actual answer to "what should I send?".

#### Monitoring

One snapshot per creator lives in a **named** key-value store (default `throne-monitor-state`), so it survives between runs. Item identity never includes price or position, so a discount is reported as a price drop rather than as a new item — verified by running twice over an unchanged wishlist and getting zero changes.

**A removed item never implies a purchase.** People delete items they changed their mind about, got elsewhere, or are simply tidying up. Throne does not publish the reason, so neither does this Actor: the event is `ITEM_REMOVED` and its description says the reason is not knowable from public data.

When a run hits `maxItemsPerCreator`, removal detection is switched off for that creator and the reason is stated in the output — a missing item might just be beyond the cap.

### Limits, stated plainly

- **Wishlist caps.** Rows hit by `maxItemsPerCreator` are flagged `wishlistTruncated`. Nothing is ever silently shortened.
- **Popularity is dataset-scoped.** "Wanted by 7 creators" means 7 of the creators in *your run*. Every popularity report repeats this in a `scope` field.
- **No currency conversion.** Price ranges and cross-currency totals are deliberately absent rather than approximated.
- **`search` costs the same as `batch`.** Throne cannot be queried by brand or category — those categories are produced by this Actor's own normalization, so filtering happens after fetching.
- **`discover` cannot filter server-side.** Combining a public-wishlist filter with ordering needs a database index Throne does not have, so the filter is applied after fetching. Discovery still returns roughly 40–100 usable creators per request.
- **Category taxonomy is rule-based.** Items it cannot place land in `Other` with a low confidence. Three figures are reported so you can tell why: `uncategorizedShare`, `unnamedItemShare` (items named with a single emoji or similar, which nothing can classify) and `uncategorizedShareOfNamed` — the last is the one that actually measures taxonomy quality. On five real wishlists it currently sits between 0 % and 13 %.
- **Private and missing profiles produce an error row, not a crash** — and are not charged for.

### What this Actor does not collect

- **Nothing behind a login, and nothing private.** Only what an anonymous visitor sees. Where Throne's access rules deny anonymous access, the run reports it and moves on — no attempt is made to work around it.
- **No gifter or supporter data.** Those are third parties and are irrelevant to commerce intelligence.
- **No guessed contact details.** Only the links a creator published on their own public profile. No email guessing, no enrichment from third-party databases.
- **No sensitive profiling.** Race, ethnicity, religion, politics, sexual orientation, health and financial status are never inferred or classified. Niches describe the goods in a wishlist, never the person.
- **No payment or shipping information.**
- **No redirect following.** Throne's `robots.txt` disallows `/redirect`; those URLs are recorded and flagged but never requested.

Credentials, tokens, cookies and proxy passwords are never logged at any level, including debug.

### Outputs

- **Dataset** — one row per creator (or per change in `monitor` with `onlyChanges`), with the views **Creators & wishlists**, **Wishlist changes** and **Discovered creators**.
- **`POPULARITY_REPORT`** in the key-value store — products and brands wanted by the most creators in the run.
- **`RUN_SUMMARY`** in the key-value store — counts, requests and bytes per creator, truncated wishlists, error codes and what was charged. Written even when the run fails.

### Not affiliated with Throne

This is an independent tool. It is not built, endorsed, or supported by Throne, and it uses no official Throne API, partnership, or private access — it reads the same public pages and public data any visitor's browser receives. "Throne" is used only to say which public website the data comes from.

### Support

Found a field that is wrong, or a brand that should be unified? Open an issue on the Actor page. Include the creator username and what you expected — the normalization rules are data, and adding a rule is a one-line change.

# Actor input Schema

## `mode` (type: `string`):

What the run does. Every mode reads public data over plain HTTP with no browser, which is why runs are cheap.

## `outputLevel` (type: `string`):

How much gets computed and written. Lower levels are cheaper and produce smaller rows.

## `creatorUrls` (type: `array`):

Throne profile URLs or plain usernames. All of these work: cirely, @cirely, throne.com/cirely, https://throne.com/cirely. Required for every mode except Discover.

## `maxCreators` (type: `integer`):

Hard cap on how many creators one run processes. In Discover mode this is how many usernames to collect.

## `maxItemsPerCreator` (type: `integer`):

Cap per creator. When a wishlist hits the cap the row is flagged wishlistTruncated, and Monitor mode stops reporting removals for that creator — a missing item might just be beyond the cap.

## `includeCollections` (type: `boolean`):

Fetch the creator's collections (the groups they sort items into). Costs one extra request per creator, so turn it off for large batches.

## `onlyWithPublicWishlist` (type: `boolean`):

Discover mode only. Skips accounts whose wishlist is not public — for this Actor they are a dead end. Turn it off to list every account that has a username.

## `filterBrands` (type: `array`):

Search mode only. Case-insensitive brand names, for example Elgato or LEGO. Combined with the other filters as AND.

## `filterCategories` (type: `array`):

Case-insensitive category names from this Actor's taxonomy, for example Gaming, Streaming Equipment, Trading Cards, Beauty.

## `minPrice` (type: `integer`):

In whole currency units (dollars, not cents). Items without a known price never pass a price filter.

## `maxPrice` (type: `integer`):

In whole currency units. No currency conversion is performed anywhere in this Actor, so ranges only match items already in that currency.

## `sponsorshipBrands` (type: `array`):

Scores each creator on how strongly they already want these brands. Requires the Intelligence output level.

## `sponsorshipCategories` (type: `array`):

Category names from this Actor's taxonomy.

## `sponsorshipNiches` (type: `array`):

For example Gaming & Streaming, Anime & Collectibles, Beauty & Lifestyle. Niches describe the goods in a wishlist, never the person.

## `sponsorshipBudget` (type: `integer`):

In whole currency units. This is a hard gate: a creator with nothing in budget is reported as not a match, whatever their score.

## `sponsorshipCurrency` (type: `string`):

ISO 4217 code for the budget above. Defaults to USD.

## `sponsorshipMinItems` (type: `integer`):

Reject creators whose public wishlist has fewer items than this. Hard gate.

## `sponsorshipMaxDaysInactive` (type: `integer`):

Reject creators who have not added anything recently. Hard gate. Creators whose items carry no dates are reported as unverifiable rather than assumed active.

## `onlyChanges` (type: `boolean`):

Monitor mode only. Writes one row per change instead of a full creator row — the cheap setup for a scheduled watcher. The first run has nothing to compare against, so it stores a baseline snapshot and reports no changes.

## `snapshotStoreName` (type: `string`):

Name of the named key-value store that keeps one snapshot per creator. It must be a named store: the default store is recreated for every run, so monitoring would never see the previous state. Use different names to keep separate watch sets from overwriting each other.

## `useProxy` (type: `boolean`):

Off by default and normally unnecessary: the public endpoints this Actor reads have not rate-limited it, and residential traffic would only add cost. Turn it on if your own runs start getting blocked.

## `proxyGroups` (type: `array`):

Apify Proxy groups, for example RESIDENTIAL. Ignored when the proxy is off.

## `proxyCountryCode` (type: `string`):

Two-letter country code for the proxy, for example US. Ignored when the proxy is off.

## `maxConcurrency` (type: `integer`):

How many creators to fetch at once. The default of 3 keeps this Actor a well-behaved visitor; raising it speeds up large batches but increases the chance of being rate-limited.

## `includeRawData` (type: `boolean`):

Attach the untouched public data exactly as Throne's own website receives it. Useful when you want a field this Actor does not normalize yet; it makes rows several times larger.

## `debug` (type: `boolean`):

Verbose logs. Credentials, proxy passwords and tokens are never logged at any level.

## Actor input object example

```json
{
  "mode": "profile",
  "outputLevel": "full",
  "creatorUrls": [
    "https://throne.com/cirely"
  ],
  "maxCreators": 20,
  "maxItemsPerCreator": 500,
  "includeCollections": true,
  "onlyWithPublicWishlist": true,
  "sponsorshipCurrency": "USD",
  "onlyChanges": false,
  "snapshotStoreName": "throne-monitor-state",
  "useProxy": false,
  "maxConcurrency": 3,
  "includeRawData": false,
  "debug": false
}
```

# Actor output Schema

## `creators` (type: `string`):

One row per creator: public profile, social links, the full wishlist with normalized prices and brands, wishlist statistics and — at the intelligence output level — brand affinity, niches, commercial signals and sponsorship fit.

## `wishlistChanges` (type: `string`):

New items, price drops, price increases, availability flips, collection moves, crowdfunding progress and removals. Removal never implies a purchase — Throne does not publish that.

## `discoveredCreators` (type: `string`):

Usernames and profile URLs from Throne's public creator directory, newest first. Deliberately metadata only — feed them into a batch run to fetch details.

## `popularityReport` (type: `string`):

Products and brands wanted by the most creators in this run. Counted per creator, not per item, and explicitly scoped to this dataset — not to all of Throne.

## `runSummary` (type: `string`):

Counts, per-creator request and byte usage, truncated wishlists, error codes and what was charged. Written even when the run fails.

# 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 = {
    "creatorUrls": [
        "https://throne.com/cirely"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("huykenny/throne-scraper").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 = { "creatorUrls": ["https://throne.com/cirely"] }

# Run the Actor and wait for it to finish
run = client.actor("huykenny/throne-scraper").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 '{
  "creatorUrls": [
    "https://throne.com/cirely"
  ]
}' |
apify call huykenny/throne-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/jITVKKDc4hGdne0SD/builds/H43Tsnemd5oQu0FFA/openapi.json
