# Get video comments



<MethodPage method="GET" path="/v1/videos/{id}/comments" credits={1}>
  Returns a video's top-level comments, about 20 per page, top or newest first. Each comment has its author, like count, reply count and, when it has replies, a `replies_cursor` for [`/comments/replies`](#replies). **1 credit** per page.

  <Callout type="info" title="Credits">
    Each successful page deducts 1 credit. A video with comments turned off returns `404 comments_disabled` and costs nothing, and so does an empty page or an unavailable video.
  </Callout>

  <Security permission="videos:read" />

  <SchemaGroup title="Path Parameters">
    <SchemaField name="id" type="string" location="path" required>
      11-character YouTube video ID or video URL.
    </SchemaField>
  </SchemaGroup>

  <SchemaGroup title="Query Parameters">
    <SchemaField name="sort" type="string" optional location="query">
      `top` (default) or `newest`.
    </SchemaField>

    <SchemaField name="cursor" type="string" optional location="query">
      `next_cursor` from the previous page. Cursors last 2 hours.
    </SchemaField>
  </SchemaGroup>

  <div id="returns" className="mt-8">
    Response (HTTP 200) [#response-http-200]

    ```jsonc
    {
      "video_id": string,
      "sort": "top" | "newest",
      "comment_count": number,         // Video total, first page only; YouTube rounds it
      "comment_count_text": string,    // As shown, e.g. "3.3K"
      "has_more": boolean,
      "next_cursor": string | null,    // Pass as cursor for the next page
      "comments": [
        {
          "id": string,
          "text": string,
          "author": {
            "name": string,            // e.g. "@handle"
            "channel_id": string,
            "avatar_url": string,
            "is_channel_owner": boolean,
            "is_verified": boolean
          },
          "like_count": number,        // YouTube's rounded figure ("12K" is 12000)
          "like_count_text": string,
          "reply_count": number,
          "published_text": string,    // Relative, e.g. "3 years ago"
          "is_edited": boolean,
          "is_pinned": boolean,
          "is_hearted": boolean,       // Hearted by the creator
          "replies_cursor": string     // Present when the comment has replies
        }
      ]
    }
    ```

    YouTube shows only relative times and rounded like counts, so those are what the API returns.
  </div>

  <div id="replies" className="mt-8">
    Replies [#replies]

    `GET /v1/videos/{id}/comments/replies?cursor=REPLIES_CURSOR` returns a comment's replies in the same shape, without `sort` and `comment_count`. Pass a comment's `replies_cursor`, then the page's `next_cursor` for more. Same price: 1 credit per page.
  </div>

  <MethodSamples>
    <LanguageSample language="cURL">
      ```bash
      curl -X GET "https://api.ytapi.dev/v1/videos/dQw4w9WgXcQ/comments?sort=top" \
        -H "Authorization: Bearer $YT_API_KEY"

      # Replies to one comment
      curl -X GET "https://api.ytapi.dev/v1/videos/dQw4w9WgXcQ/comments/replies?cursor=REPLIES_CURSOR" \
        -H "Authorization: Bearer $YT_API_KEY"
      ```
    </LanguageSample>

    <LanguageSample language="TypeScript">
      ```ts
      const response = await fetch(
        "https://api.ytapi.dev/v1/videos/dQw4w9WgXcQ/comments?sort=top",
        {
          headers: {
            Authorization: `Bearer ${process.env.YT_API_KEY}`,
          },
        },
      );

      const page = await response.json();
      for (const c of page.comments) {
        console.log(c.like_count, c.author.name, c.text);
      }
      ```
    </LanguageSample>

    <LanguageSample language="Python">
      ```python
      import os
      import requests

      response = requests.get(
          "https://api.ytapi.dev/v1/videos/dQw4w9WgXcQ/comments",
          headers={"Authorization": f"Bearer {os.environ['YT_API_KEY']}"},
          params={"sort": "top"},
      )
      for c in response.json()["comments"]:
          print(c["like_count"], c["author"]["name"], c["text"])
      ```
    </LanguageSample>

    <LanguageSample language="Go">
      ```go
      package main

      import (
      	"fmt"
      	"net/http"
      	"os"
      )

      func main() {
      	req, _ := http.NewRequest("GET", "https://api.ytapi.dev/v1/videos/dQw4w9WgXcQ/comments?sort=top", nil)
      	req.Header.Set("Authorization", "Bearer "+os.Getenv("YT_API_KEY"))

      	resp, err := http.DefaultClient.Do(req)
      	if err != nil {
      		panic(err)
      	}
      	defer resp.Body.Close()
      	fmt.Println(resp.Status)
      }
      ```
    </LanguageSample>
  </MethodSamples>
</MethodPage>
