# Kickstarter Projects Scraper - Funding, Backers & Rewards (`scrapyx/kickstarter-projects-scraper`) Actor

Scrapes Kickstarter's own discovery API: goal, pledged, backers, percent funded, currency, category, location, creator and dates -- optionally reward tiers and live counters. Flags filters Kickstarter silently drops, and the 2,400-row-per-query ceiling it never mentions.

- **URL**: https://apify.com/scrapyx/kickstarter-projects-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Business, E-commerce, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Kickstarter Projects Scraper — Funding, Backers & Rewards

Reads Kickstarter's **own discovery API** (`/discover/advanced?format=json`) —
the endpoint kickstarter.com itself calls. No key, no auth, no cookie.

### What you get

| `recordType` | One per | Carries |
| --- | --- | --- |
| `PROJECT` | project | goal, pledged, USD-converted pledged, percent funded, backers, currency + FX rate, state, created/launched/deadline dates, category tree, location, creator, photo — plus reward tiers and live counters if you switch them on |
| `SEARCH_SUMMARY` | query | the exact query sent, Kickstarter's own hit count, how much of it is actually reachable, and **which filters upstream honoured** |
| `ERROR` | failed input | a named reason — every input maps to at least one row |

Optional second pass:

- **Reward tiers** (`includeProjectDetails`) — title, minimum pledge, backers
  per tier, shipping, estimated delivery, add-ons, tags, update/comment counts.
- **Live counters** (`includeLiveStats`) — a 168-byte call per project for
  up-to-the-minute backers, pledged and comments. Discovery results are cached
  and can lag; both numbers are kept side by side rather than merged.

### Three things this tells you that the API does not

**1. One query can only ever reach 2,400 rows.** Page 200 works; page 201 is a
genuine HTTP 404. A query claiming 296,780 hits will hand you 2,400 of them and
say nothing about the rest. Every summary carries `totalHits`,
`estimatedReachable`, `estimatedUnreachable` and `hitPageCeiling`, so the gap is
visible instead of inferred. The way past it is to **split the query** — that is
what the `queries` list is for (by category, state, location or funding band).

**2. A wrong `categoryId` or `woeId` is not an error — it returns everything.**
`category_id=999999` comes back HTTP 200 with the full unfiltered baseline
(685,886 projects) and no field saying the filter was dropped. This actor proves
what was applied from the rows themselves, so it costs no extra request:
`categoryFilterHonoured` / `locationFilterHonoured` in the summary, and
`categoryMatchesRequested` / `locationMatchesRequested` on every row.

**3. A subcategory is a *relevance* filter, not a strict one.** Asking for
category 35 (Video Games) returns Comic Books, Product Design, Print and Public
Art alongside it — about 58% of a page actually matches. The hit count still
moves (24,585 against a 685,886 baseline), so the usual "did the count change?"
check passes on exactly the case that matters. Parent categories (Games,
Technology, Design…) *do* filter strictly. Rows carry the per-row verdict and
the summary carries `categoryMatchRateFirstPage`; filter on it for a strict set,
ignore it for Kickstarter's own notion of the category.

### Two inputs this actor refuses on purpose

- **`state=suspended`.** It looks like a sixth state and is not a filter value.
  Kickstarter answers it with 681,135 projects — the sum of all five real states
  — and returns the *same rows* as a nonsense string. Valid: `live`,
  `successful`, `failed`, `canceled`, `upcoming`.
- **An unrecognised `sort`.** Upstream does not error; it silently substitutes
  the default (`magic`), so the run would look sorted and not be. Verified by
  comparing returned id order, not counts — the count is identical for every
  sort.

`term` is honest, for contrast: a term with no matches returns zero, not the
baseline.

### Notes

- 12 projects per request.
- Cloudflare here is a TLS-fingerprint gate rather than a challenge for
  everyone; the actor uses a measured profile allowlist and rotates on failure.
- The project-detail page is intermittently unavailable over HTTP/2 even after
  retries. When that happens the row keeps all of its discovery data and carries
  `detailFetched: false` plus `detailError` — a detail failure never costs you
  the project.
- A proxy is optional and off by default. Worth switching on for long runs.

# Actor input Schema

## `queries` (type: `array`):

One or more discovery queries. Each object accepts term, state, categoryId, woeId, sort, staffPicks, raised and goal. Use several queries to get past the 2,400-row-per-query ceiling -- split by category, state or location. Leave empty to use the flat fields below.

## `term` (type: `string`):

Free-text search, used when 'Queries' is empty. Verified honest: a term with no matches returns zero results, not the unfiltered baseline.

## `state` (type: `string`):

Only these five are real filter values. 'suspended' looks like a sixth and is not one -- Kickstarter answers it with every state at once, identically to a nonsense string, so this actor refuses it.

## `categoryId` (type: `integer`):

Kickstarter category id. Parent ids (1 Art, 3 Comics, 6 Dance, 7 Design, 9 Fashion, 10 Food, 11 Film & Video, 12 Games, 13 Journalism, 14 Music, 15 Photography, 16 Technology, 17 Theater, 18 Publishing, 26 Crafts) filter strictly. A SUBcategory id is a relevance filter upstream and mixes in neighbouring categories -- rows carry categoryMatchesRequested so you can tell.

## `woeId` (type: `integer`):

Kickstarter location id, e.g. 2459115 for New York, NY. An unknown id is NOT an error upstream -- it silently returns every project. Rows carry locationMatchesRequested and the summary says whether the filter was honoured.

## `sort` (type: `string`):

An unrecognised sort is not an error upstream -- it silently becomes 'magic', so the run looks sorted and is not. Only these six are accepted here.

## `staffPicks` (type: `boolean`):

Restrict to projects Kickstarter has featured.

## `raised` (type: `integer`):

Kickstarter's own band: 0 = under 75% funded, 1 = 75-100%, 2 = over 100%.

## `goal` (type: `integer`):

Kickstarter's own goal band, 0 (under $1,000) through 6 (over $100,000).

## `maxProjectsPerQuery` (type: `integer`):

Set 0 to walk to the ceiling. That ceiling is 2,400 rows (page 200); page 201 is a genuine HTTP 404, so a broad query cannot be fully collected in one go however many hits it reports.

## `includeProjectDetails` (type: `boolean`):

Second pass over each project page for reward tiers, add-ons, tags and update/comment counts. Costs about 590 KB per project against 7 KB for a discovery row, so it is off by default.

## `includeLiveStats` (type: `boolean`):

Fetch each project's 168-byte stats endpoint for up-to-the-minute backers, pledged and comment counts. Discovery results are cached and can lag by hours; both numbers are kept side by side.

## `maxDetailsPerQuery` (type: `integer`):

Caps the second pass separately from the result count, so a large discovery run does not turn into a large download.

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

Requests in flight at once across all queries. Kickstarter drops back-to-back connections under load, so this is deliberately low.

## `minRequestInterval` (type: `integer`):

Politeness pacing shared across all workers.

## `proxyConfiguration` (type: `object`):

Optional and OFF by default. Cloudflare here is a TLS-fingerprint gate that the measured profile pool passes cold. Worth switching on for long runs.

## Actor input object example

```json
{
  "queries": [
    {
      "categoryId": 12,
      "state": "live"
    },
    {
      "categoryId": 16,
      "state": "live"
    }
  ],
  "term": "solar charger",
  "state": "",
  "sort": "magic",
  "staffPicks": false,
  "maxProjectsPerQuery": 60,
  "includeProjectDetails": false,
  "includeLiveStats": false,
  "maxDetailsPerQuery": 25,
  "maxConcurrency": 2,
  "minRequestInterval": 1,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "queries": [
        {
            "term": "board game",
            "state": "live",
            "sort": "most_funded"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/kickstarter-projects-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 = { "queries": [{
            "term": "board game",
            "state": "live",
            "sort": "most_funded",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/kickstarter-projects-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 '{
  "queries": [
    {
      "term": "board game",
      "state": "live",
      "sort": "most_funded"
    }
  ]
}' |
apify call scrapyx/kickstarter-projects-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/kickstarter-projects-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/ohNqE3bzybKYj2kxw/builds/XuviFCpuhiEDV5Dy5/openapi.json
