# YouTube Comments API

Beta

Returns the public top-level comments of a YouTube video, short or live replay, a page at a time: text, author handle and channel, posting time, likes, reply count, and whether the comment is pinned, hearted, edited or written by the creator. Sort newest first (the default, which also supports since and until) or by YouTube's Top ranking, and follow page.next_cursor for more. Accepts every YouTube URL form or a bare 11-character video ID.

[Get 100 free credits](https://staging-fly.socialtap.dev/signup/?next=%2Fplayground%2F%3Fendpoint%3Dyoutube.comments) · [API reference](https://staging-fly.socialtap.dev/docs/reference/youtube/comments/index.md) · [Try it](https://staging-fly.socialtap.dev/playground/?endpoint=youtube.comments)

- **Price**: From **1 credit** per page$0.75–$1.45 per 1,000 pages
- **Request**: `GET /v1/youtube/comments`One API key, one JSON schema
- **Input**: `url`e.g. `https://www.youtube.com/watch?v=jNQXAC9IVRw`
- **Page size**: Up to 20 comments

Use cases

## What teams build with it. From one request.

- Track audience sentiment on your videos and competitors'
- Monitor new comments since a date
- Find questions and feedback to answer
- Build datasets of public comments for research

What you get

## Comments in one schema. The same on every platform.

- **`platform`string**: Platform ID (tiktok, youtube, …).
- **`id`string**: Platform-native comment ID (string; Reddit without t1_).
- **`post_id`string**: ID of the post commented on (equals post.id).
- **`parent_id`string**: ID of the comment this replies to; null for top-level comments.
- **`url`string**: Permalink, when the platform has one.
- **`text`string**: Comment body as plain text.
- **`author`object**: The commenting account.
- **`published_at`string**: When the comment was posted, RFC 3339 UTC. Where the platform shows only a relative time ("3 weeks ago"), the latest time that label allows (the fetch time minus the stated amount), listed in approximate_fields.

Every field, its type and when it is `null`: [the response reference](https://staging-fly.socialtap.dev/docs/reference/youtube/comments/index.md#response) and the [comment schema](https://staging-fly.socialtap.dev/resources/comment/index.md).

## Example request

cURL:

```shell
curl -G 'https://staging-fly.socialtap.dev/v1/youtube/comments' \
  --data-urlencode 'sort=newest' \
  --data-urlencode 'url=jNQXAC9IVRw' \
  -H "x-api-key: $SOCIALTAP_API_KEY"
```

Node.js:

```javascript
const params = new URLSearchParams({
  sort: "newest",
  url: "jNQXAC9IVRw",
});
const res = await fetch(`https://staging-fly.socialtap.dev/v1/youtube/comments?${params}`, {
  headers: { "x-api-key": process.env.SOCIALTAP_API_KEY ?? "" },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const { data, page, meta } = body;
console.log(data, meta.credits_charged);
```

Python:

```python
import os

import requests

res = requests.get(
    "https://staging-fly.socialtap.dev/v1/youtube/comments",
    params={"sort": "newest", "url": "jNQXAC9IVRw"},
    headers={"x-api-key": os.environ["SOCIALTAP_API_KEY"]},
)
body = res.json()
if not res.ok:
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
data, page, meta = body["data"], body["page"], body["meta"]
print(data, meta["credits_charged"])
```

Go:

```go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
)

func main() {
	q := url.Values{}
	q.Set("sort", "newest")
	q.Set("url", "jNQXAC9IVRw")
	req, err := http.NewRequest("GET", "https://staging-fly.socialtap.dev/v1/youtube/comments?"+q.Encode(), nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("x-api-key", os.Getenv("SOCIALTAP_API_KEY"))
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	var body struct {
		Data  json.RawMessage `json:"data"`
		Page  json.RawMessage `json:"page"`
		Meta  map[string]any  `json:"meta"`
		Error *struct {
			Code    string `json:"code"`
			Message string `json:"message"`
		} `json:"error"`
	}
	if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
		log.Fatal(err)
	}
	if body.Error != nil {
		log.Fatalf("%s: %s", body.Error.Code, body.Error.Message)
	}
	fmt.Println(string(body.Data), body.Meta["credits_charged"])
}
```

200 OK:

```json
{
  "data": [
    {
      "approximate_fields": [
        "published_at",
        "metrics.like_count",
        "metrics.reply_count"
      ],
      "author": {
        "avatar_url": "https://yt3.ggpht.com/i8RqA9tYqbbnOi4mlnYEY7IR3kXAoDqQbM_5Sfzw7OjTubiGsOaTdlrIZmj-I0q0Vup68eqs=s88-c-k-c0x00ffffff-no-rj",
        "display_name": null,
        "id": "UCC5NfQ6Mf0dq_eEwv4P_hWA",
        "is_verified": true,
        "url": "https://www.youtube.com/channel/UCC5NfQ6Mf0dq_eEwv4P_hWA",
        "username": "SanDiegoZoo"
      },
      "edited_at": null,
      "id": "UgzuC3zzpRZkjc5Qzsd4AaABAg",
      "is_by_post_author": false,
      "is_edited": false,
      "is_liked_by_author": true,
      "is_pinned": true,
      "metrics": {
        "like_count": 4800000,
        "reply_count": 1000
      },
      "parent_id": null,
      "platform": "youtube",
      "platform_specific": {},
      "post_id": "jNQXAC9IVRw",
      "published_at": "2020-10-26T18:59:19Z",
      "text": "We're so honored that the first ever YouTube video was filmed here!",
      "unknown_fields": [],
      "url": "https://www.youtube.com/watch?v=jNQXAC9IVRw&lc=UgzuC3zzpRZkjc5Qzsd4AaABAg"
    },
    {
      "approximate_fields": [
        "published_at"
      ],
      "author": {
        "avatar_url": "https://yt3.ggpht.com/U9zdJRwdpo6WwsenxMf6AyMyRMBTWoKsyAWCnJXdbPbNKh-YNEWP3AQRgFto91lckyGCBYENnaw=s88-c-k-c0x00ffffff-no-rj",
        "display_name": null,
        "id": "UCjoZE_5A9tO470CK3G6U7dg",
        "is_verified": false,
        "url": "https://www.youtube.com/channel/UCjoZE_5A9tO470CK3G6U7dg",
        "username": "CTwGary"
      },
      "edited_at": null,
      "id": "UgxHbErLhWMUy5GlFnp4AaABAg",
      "is_by_post_author": false,
      "is_edited": false,
      "is_liked_by_author": false,
      "is_pinned": false,
      "metrics": {
        "like_count": 0,
        "reply_count": 0
      },
      "parent_id": null,
      "platform": "youtube",
      "platform_specific": {},
      "post_id": "jNQXAC9IVRw",
      "published_at": "2026-10-26T18:58:19Z",
      "text": "I can’t believe it, but it’s 21 years old now",
      "unknown_fields": [],
      "url": "https://www.youtube.com/watch?v=jNQXAC9IVRw&lc=UgxHbErLhWMUy5GlFnp4AaABAg"
    },
    {
      "approximate_fields": [
        "published_at"
      ],
      "author": {
        "avatar_url": "https://yt3.ggpht.com/Ar50xvd1O4GCXVttK6DgX0Y0cuhBl2b_HUFQjh-gajKbmS-qjuNAHOT5fw_RX_DS5gzfphkcKAI=s88-c-k-c0x00ffffff-no-rj",
        "display_name": null,
        "id": "UCFgjcRO4y8XFQL7E8_TcLlg",
        "is_verified": false,
        "url": "https://www.youtube.com/channel/UCFgjcRO4y8XFQL7E8_TcLlg",
        "username": "Nihal-poke"
      },
      "edited_at": null,
      "id": "UgzLOxwwIAUe0jUI4RR4AaABAg",
      "is_by_post_author": false,
      "is_edited": false,
      "is_liked_by_author": false,
      "is_pinned": false,
      "metrics": {
        "like_count": 0,
        "reply_count": 0
      },
      "parent_id": null,
      "platform": "youtube",
      "platform_specific": {},
      "post_id": "jNQXAC9IVRw",
      "published_at": "2026-10-26T18:58:19Z",
      "text": "I watch this video many times 😭",
      "unknown_fields": [],
      "url": "https://www.youtube.com/watch?v=jNQXAC9IVRw&lc=UgzLOxwwIAUe0jUI4RR4AaABAg"
    }
  ],
  "page": {
    "has_more": true,
    "next_cursor": "c1.EXAMPLE_CURSOR",
    "next_cursor_expires_at": "2026-10-26T12:00:00Z",
    "end_reason": null
  },
  "meta": {
    "request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
    "platform": "youtube",
    "source": "api",
    "is_cached": false,
    "credits_charged": 1,
    "latency_ms": 0,
    "fetched_at": "2026-10-25T12:00:00Z",
    "input": {
      "kind": "video",
      "id": "jNQXAC9IVRw",
      "url": "https://www.youtube.com/watch?v=jNQXAC9IVRw"
    },
    "credits_remaining": 9999,
    "client_request_id": null,
    "warnings": [],
    "mode": "live"
  }
}
```

Long arrays and strings are shortened for display; real responses are complete.

> [!NOTE]
>
> **Good to know**
>
> - YouTube shows comment times as relative labels ("3 weeks ago"): published_at is the latest time the label allows and is listed in approximate_fields, so since and until are approximate to the label's unit.
> - Like and reply counts above a thousand are rounded by YouTube ("4.8K") and listed in approximate_fields.
> - Comments show the author's @handle; author.display_name is null.
> - The newest order includes comments YouTube's Top ranking holds back as potential spam.
> - Videos with comments turned off and private videos return private_or_unavailable; deleted videos return not_found.
> - Replies are not included; metrics.reply_count says how many a comment has.

Pricing

## Pay per page. Only when it succeeds.

| Source | Price per successful page | Per 1,000 pages |
| --- | --- | --- |
| Platform API `api` | 1 credit | $0.75–$1.45 |

- Failed requests are free: errors cost 0 credits.
- Cache hits are free: responses served from the cache cost 0 credits.
- Credits never expire.
- One credit balance for every endpoint and platform.

[Credit packs](https://staging-fly.socialtap.dev/pricing/index.md) · [How this endpoint is priced](https://staging-fly.socialtap.dev/docs/reference/youtube/comments/index.md#pricing) · [How credits work](https://staging-fly.socialtap.dev/docs/credits/index.md)

FAQ

## Questions, answered.

**How much does the YouTube Comments API cost?**

1 credit for platform api results (meta.source = api) per page of up to 20 items, charged for every successful page, empty pages included. SocialTap credits cost $0.75–$1.45 per 1,000 depending on the pack.

**How do I get the next page?**

Repeat the same request with cursor set to page.next_cursor from the previous response, keeping the other parameters. When page.has_more is false there are no more items. Cursors expire after 1 hour.

**Am I charged for failed requests?**

No. Requests that return an error cost 0 credits. Responses served from the cache are free too.

Same schema, other platforms

## Comments everywhere. One parser.

[Rumble Comments APIBetaComment`GET /v1/rumble/comments`1 credit / page](https://staging-fly.socialtap.dev/apis/rumble/comments/index.md) · [TikTok Comments APIBetaComment`GET /v1/tiktok/comments`1 credit / page](https://staging-fly.socialtap.dev/apis/tiktok/comments/index.md)

More YouTube

## YouTube API. 5 endpoints, one key.

[YouTube Video APIBetaPost`GET /v1/youtube/post`1 credit](https://staging-fly.socialtap.dev/apis/youtube/post/index.md) · [YouTube Channel Videos APIBetaPost`GET /v1/youtube/posts`1 credit / page](https://staging-fly.socialtap.dev/apis/youtube/posts/index.md) · [YouTube Channel APIBetaProfile`GET /v1/youtube/profile`1 credit](https://staging-fly.socialtap.dev/apis/youtube/profile/index.md) · [YouTube Transcript APIBetaTranscript`GET /v1/youtube/transcript`From 1 credit](https://staging-fly.socialtap.dev/apis/youtube/transcript/index.md)

## Start with 100 free credits. No card required.

Test keys answer every endpoint from recorded responses, free, so you can build before you spend. Failed requests are always free.

[Get your API key](https://staging-fly.socialtap.dev/signup/?next=%2Fplayground%2F%3Fendpoint%3Dyoutube.comments) · [Read the API reference](https://staging-fly.socialtap.dev/docs/reference/youtube/comments/index.md)

---

[HTML version](https://staging-fly.socialtap.dev/apis/youtube/comments/) · [Docs index for AI agents](https://staging-fly.socialtap.dev/llms.txt) · [All docs in one file](https://staging-fly.socialtap.dev/llms-full.txt)
