# Kick All-in-One API (`romy/kick-all-in-one-api`) Actor

Unofficial always-on REST API for live Kick.com data: home feed, live channel listings, search, channel profiles, real-time viewer counts, clips, VODs, playback URLs, and a Server-Sent Events endpoint for near-real-time chat. No account needed.

- **URL**: https://apify.com/romy/kick-all-in-one-api.md
- **Developed by:** [Romy](https://apify.com/romy) (community)
- **Categories:** Social media, Videos
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $11.70 / 1,000 live channel listings

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

### What does Kick All-in-One API do?

**Kick All-in-One API** is a REST endpoint for [Kick](https://kick.com/)'s live streaming data — home feed, browsable live-channel listings with real filters, full-text search, channel profiles, real-time (batched) viewer counts, clips, VODs, signed playback URLs, and chat. All from a single always-on API powered by [Apify Standby](https://docs.apify.com/platform/actors/development/programming-interface/standby).

It talks directly to the same internal APIs the official Kick Android app uses, reverse-engineered by capturing and analyzing live traffic from the real app. No Kick account, no API key — call the endpoint, get JSON back.

The standout endpoint is `GET /channels/{id}/chat/stream` — near-real-time chat delivered as **Server-Sent Events**, built on top of Kick's own REST-pollable chat history endpoint. No competing Kick scraper on Apify offers live chat at all.

### Why use Kick All-in-One API?

- **Live chat as Server-Sent Events** — no WebSocket client needed on your end, no polling logic to write; connect once and receive new chat messages as they're posted
- **Real, working filters everywhere they exist** — confirmed live: `language` and `category_id` genuinely filter `/livestreams`, and clips' `sort`/`time` genuinely change results. `/home`, `/livestreams`, `/clips`, and `/categories` all have real, confirmed-live pagination — `/search` and `/channels/{id}/videos` don't (see Data notes), and this README says so rather than papering over it
- **Batched real-time viewer counts** — look up several channels' live viewer numbers in a single call
- **Real, signed playback URLs** — live, DVR, and VOD `.m3u8` HLS manifests that actually play, not placeholder links
- **Always-on** — Standby mode means no cold start, responds in milliseconds
- **No account needed** — every endpoint works fully anonymously
- **Use cases:** live-chat sentiment/moderation tooling, stream discovery bots, viewer-count/analytics dashboards, clip aggregation, esports/creator monitoring

### Endpoints

| Method | Path                              | Description                                              |
| ------ | ---------------------------------- | ---------------------------------------------------------- |
| `GET`  | `/home`                            | Featured live channels, real-time viewer counts, paginated  |
| `GET`  | `/search`                          | Full-text search: channels + categories + livestreams       |
| `GET`  | `/livestreams`                     | Browsable live-channel listing, filterable & paginated      |
| `GET`  | `/categories`                      | Every game/category, with live watcher counts, paginated     |
| `GET`  | `/viewers`                         | Batched real-time viewer counts for multiple channels        |
| `GET`  | `/channels/{slug}`                 | Merged channel profile (info + links + recent categories)    |
| `GET`  | `/channels/{slug}/leaderboard`     | Top gifters for a channel                                     |
| `GET`  | `/channels/{slug}/emotes`          | A channel's custom emote set                                  |
| `GET`  | `/channels/{id}/videos`            | A channel's saved VODs                                        |
| `GET`  | `/channels/{id}/videos/{videoId}`  | Full detail for one VOD                                       |
| `GET`  | `/clips`                           | Popular/recent clips, site-wide or per-channel                |
| `GET`  | `/stream/{id}/playback`            | Real, signed HLS playback URLs (live/DVR/VOD)                 |
| `GET`  | `/channels/{id}/chat/settings`     | Chat mode (slow mode, followers-only, etc.)                   |
| `GET`  | `/channels/{id}/chat/history`      | Chat message history via plain REST polling                   |
| `GET`  | `/channels/{id}/chat/stream`       | **Near-real-time chat as Server-Sent Events**                 |

### How to use Kick All-in-One API

1. Open this Actor's Standby API URL (shown on the Actor's page, under the API tab).
2. Call any endpoint — for example:
   ```bash
   curl "https://romy--kick-all-in-one-api.apify.actor/home"
   curl "https://romy--kick-all-in-one-api.apify.actor/search?q=gaming"
   curl "https://romy--kick-all-in-one-api.apify.actor/livestreams?language=en&limit=10"
   curl "https://romy--kick-all-in-one-api.apify.actor/categories"
   curl "https://romy--kick-all-in-one-api.apify.actor/channels/kaneljoseph"
   curl "https://romy--kick-all-in-one-api.apify.actor/viewers?ids=123746987,124000001"
   curl "https://romy--kick-all-in-one-api.apify.actor/clips?sort=views&time=week"
   curl "https://romy--kick-all-in-one-api.apify.actor/channels/18750821/chat/history"
   # Server-Sent Events — stays open, streams new chat messages as they arrive:
   curl -N "https://romy--kick-all-in-one-api.apify.actor/channels/18750821/chat/stream"
   ```
   Every call needs your Apify API token, either as `Authorization: Bearer <token>` or `?token=<token>` — the Actor's page API tab has a ready-to-copy version with your token filled in.
3. Read the JSON response (or, for `/chat/stream`, the SSE `data:` event stream) — no setup required.

### Parameters

**`GET /home`** — no required parameters. `page` optional (int, default 1) — real pagination, confirmed live: 14 channels per page, distinct pages return distinct, non-overlapping channels.

**`GET /categories`** — no required parameters. `limit` (int, default 32) and `page` (int, default 1) optional — real pagination, confirmed live: distinct pages return distinct category ids.

**`GET /search`** — `q` required.

**`GET /livestreams`**

| Param         | Type                   | Example      | Meaning                                                       |
| ------------- | ---------------------- | ------------ | ---------------------------------------------------------------- |
| `sort`        | enum, default `viewer_count_desc` | `viewer_count_desc` | `viewer_count_desc` | `featured`                     |
| `language`    | string                 | `en`         | ISO 639-1 — confirmed live to filter results                     |
| `category_id` | integer                | `15`         | From `GET /categories`                                            |
| `limit`       | int, default 24        | `24`         |                                                                    |
| `cursor`      | string                 |              | From the previous response's `results.data.pagination.next_cursor` |

**`GET /viewers`** — `ids` required (comma-separated livestream ids, from `GET /livestreams` or `GET /home`).

**`GET /channels/{slug}`** — path param `slug` required (e.g. `kaneljoseph`). Response includes the channel's numeric `id`, required by every endpoint below.

**`GET /channels/{id}/videos`** — path param `id` required (**numeric channel id**, not slug). No parameters — confirmed live this endpoint has no pagination of any kind (see Data notes) and always returns the same up-to-30 most recent VODs.

**`GET /clips`**

| Param        | Type                    | Example | Meaning                                                    |
| ------------ | ----------------------- | ------- | ------------------------------------------------------------- |
| `sort`       | enum, default `views`   | `views` | `views` | `date`                                              |
| `time`       | enum, default `week`    | `week`  | `day` | `week` | `month` | `all`                            |
| `channel_id` | integer                 | `18750821` | Omit for site-wide clips, from `GET /channels/{slug}`       |
| `cursor`     | string                  |         | From the previous response's `results.data.cursor`             |

**`GET /stream/{id}/playback`** — path param `id` required (a livestream or VOD id, from `GET /livestreams`, `GET /home`, or `GET /channels/{id}/videos`).

**`GET /channels/{id}/chat/history`** — path param `id` required (numeric channel id). `start_time` optional (ISO 8601, defaults to now).

**`GET /channels/{id}/chat/stream`** — path param `id` required (numeric channel id).

| Param         | Type                       | Example | Meaning                                    |
| ------------- | -------------------------- | ------- | -------------------------------------------- |
| `start_time`  | string (date-time)         |         | ISO 8601 — defaults to now                    |
| `interval_ms` | int, default 3000, min 1000 | `3000`  | How often this Actor polls Kick internally    |

### Output

Every non-SSE response is returned directly over HTTP — this Actor does not write to an Apify dataset. Real responses (trimmed for readability):

`GET /channels/kaneljoseph`:

```json
{
    "success": true,
    "channel": {
        "id": 18750821,
        "slug": "kaneljoseph",
        "chatroomId": 18490228,
        "info": { "verified": true, "followers_count": 89833, "livestream": null },
        "links": [],
        "recentCategories": [{ "name": "IRL", "viewers": 202259 }]
    }
}
```

`GET /viewers?ids=123746987`:

```json
{ "success": true, "results": [{ "livestream_id": 123746987, "viewers": 39318, "show_view_count": true }] }
```

`GET /clips?sort=views&time=week` (trimmed to one clip):

```json
{
    "success": true,
    "results": {
        "data": {
            "clips": [
                {
                    "id": "clip_01M060TASC2P5DEWRA1V3HNTZ2",
                    "title": "...",
                    "channel": { "slug": "maherco", "username": "Maherco", "is_verified": true },
                    "views_count": 58900,
                    "playback_url": "https://clips.kick.com/clips/87/clip_01M060TASC2P5DEWRA1V3HNTZ2/playlist.m3u8"
                }
            ]
        }
    }
}
```

`GET /channels/18750821/chat/stream` (Server-Sent Events, one `data:` line per new message batch):

```
data: [{"id":"c62e3b2d-...","chat_id":4351775,"content":"...","sender":{"username":"3sam55","identity":{"badges":[{"type":"subscriber"}]}},"created_at":"2026-08-23T22:48:30Z"}]

data: [{"id":"98d5b55e-...","chat_id":4351775,"content":"[emote:37226:KEKW]","sender":{"username":"arwa22110"},"created_at":"2026-08-23T22:48:34Z"}]
```

### Data notes

- **No signature or token required anywhere**, confirmed live across all four API hosts this Actor calls (`kick.com`, `mobile.kick.com`, `search.kick.com`, plus the `.m3u8` playback hosts) — every request needs nothing but a plain, static identity header set. Independently re-confirmed by calling every endpoint directly from a plain server, no device involved.
- **The official viewer app wasn't surfaced by an in-app Play Store search on the research device** (a device-compatibility filter, not a real absence) — the APK (`com.kick.mobile`) was sideloaded directly for this research. Kick's *other* Play Store app, "KICK - Go Live" (`com.kick.streaming`), is a separate broadcaster tool for going live from a phone camera, not a viewer app, and wraps none of the data this Actor exposes.
- **Two id systems are used inconsistently by Kick's own app, and this Actor stays faithful to that.** `kick.com`-hosted endpoints (`/channels/{slug}`, `/channels/{slug}/leaderboard`, `/channels/{slug}/emotes`, `/current-viewers`) take a channel's `slug`. `mobile.kick.com`-hosted endpoints (videos, clips-per-channel, chat) take its numeric `id` instead — confirmed live, passing a slug there fails. `GET /channels/{slug}` returns both so callers can chain without guessing.
- **`/stream/{id}/playback` needs a request body, confirmed live.** The real app sends a large payload of player/session/ad-SDK telemetry; a bare POST gets rejected with `400 Bad Request`. This Actor sends a trimmed version with only the fields confirmed necessary (player name/version, connection type, a placeholder device/session id) — confirmed live this still returns real, playable signed URLs.
- **`/clips` and `/livestreams` both use real cursor-based pagination, not page numbers** — confirmed live through this Actor's own routes: paging with the previous response's cursor returned a second batch with zero id overlap against the first, for both endpoints. The cursor lives in a different spot in each response shape (`results.data.cursor` for clips, `results.data.pagination.next_cursor` for livestreams) — this Actor exposes both as-is rather than normalizing them, so pass whichever one straight through as this endpoint's `cursor` param, don't attempt to decode or construct it yourself.
- **`/livestreams`' `language` and `category_id` filters were confirmed live by testing values directly against the API**, not just observed in the app UI — a request with `language=fr` returned livestreams with `"language":"fr"` in every result, and unrecognized param names were silently ignored (confirming these exact names, not near-misses, are what the backend actually reads).
- **`/livestreams`' `sort` is a strictly-validated required enum, unlike most other params here** — confirmed live: an empty, missing, or nonsense `sort` value gets a real `400 Invalid request` from Kick's own backend, not a silent fallback. This Actor always sends a valid value (`viewer_count_desc` by default), so callers never need to worry about this.
- **`/home` is genuinely paginated, confirmed live** — 14 channels per page, `page=2` and `page=3` each returned a fully distinct set of channel ids with zero overlap against page 1.
- **`/channels/{id}/videos` has no pagination at all, confirmed live** by testing every plausible param name (`page`, `cursor`, `after`, `offset`, and `limit`) directly against the API — every one was silently ignored, always returning the identical up-to-30 most recent VODs. This is a real backend limitation, not a gap in this Actor.
- **`/search` is capped at 3 results per category (channels/categories/livestreams) with no pagination**, confirmed live the same way — `limit`, `page`, and `offset` were all tried directly against the API with zero effect on result count. Treat it as quick suggestions, not an exhaustive search; for a full channel/category listing use `/livestreams` or `/categories` instead.
- **`/channels/{id}/chat/stream` is this Actor's own construction, not a single upstream endpoint.** It polls `GET /channels/{id}/chat/history` on an interval (default 3s) and forwards each new, non-empty batch as one Server-Sent Event, de-duplicating by message id across polls. Confirmed live against a channel with active chat: two polls 3 seconds apart delivered two batches with zero overlapping message ids. Billing reflects this — you're charged per delivered message batch, not per second connected, so holding the connection open on a quiet or offline channel costs nothing.
- **A real WebSocket endpoint (`websockets.kick.com/viewer/v1/token`) also exists** for true push-based chat, confirmed live in the app's own traffic, but is not used here — the REST-polling approach above needs no token exchange or persistent socket management on either side, at the cost of up to `interval_ms` of latency versus true push.

### Pricing

Pay-per-event, billed on each successful call (or, for `/channels/{id}/chat/stream`, on each delivered message batch). See the Actor's Pricing tab for current rates.

### Known limitations

- **No booking/checkout-equivalent endpoints** — there is no purchase flow on Kick to wrap, but for the same reason as every other actor in this family: this Actor only wraps guest-accessible, read-only endpoints. No login flow (sending chat messages, following, gifting, subscribing) is implemented or planned, by design.
- **`/channels/{id}/chat/stream` latency is bounded by `interval_ms`** (default 3s, minimum 1s) — this is REST-polling dressed as a stream, not the app's own WebSocket push channel, so expect up to that much delay versus watching chat live in the app itself.
- This is an unofficial, reverse-engineered integration, not affiliated with or endorsed by Kick Streaming, Inc. Behavior may change if Kick changes its API.

Found a bug or have a feature request? Use the Issues tab on this Actor's page.

# Actor input Schema

## Actor input object example

```json
{}
```

# Actor output Schema

## `api` (type: `string`):

This Actor doesn't write to a dataset — every response is returned directly over HTTP by its Standby web server. See the README / web server OpenAPI schema (webServerSchema) for the full endpoint list and response shapes (GET /home).

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("romy/kick-all-in-one-api").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("romy/kick-all-in-one-api").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 '{}' |
apify call romy/kick-all-in-one-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,romy/kick-all-in-one-api"
        }
    }
}

```

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/euBZKLevL8tFuOYRS/builds/U6S9aN6WuUhziEDVT/openapi.json
