AutomationFlowsWeb Scraping › Get Douyin Video Comments and Replies with Justoneapi

Get Douyin Video Comments and Replies with Justoneapi

Byapisub001 @apisub001 on n8n.io

Use this n8n workflow to get Douyin video comments and fetch replies for the first comment with replies using JustOneAPI.

Event trigger★★★★☆ complexity21 nodesHTTP Request
Web Scraping Trigger: Event Nodes: 21 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #15885 — we link there as the canonical source.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "D7YEcQ01Iz9rYzrG",
  "name": "Get Douyin video comment replies with JustOneAPI",
  "tags": [],
  "nodes": [
    {
      "id": "48a719d5-9648-44bc-9336-516082dd7558",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        992,
        704
      ],
      "parameters": {
        "width": 480,
        "height": 496,
        "content": "## Get Douyin video comment replies with JustOneAPI\n\n### How it works\n\n1. Trigger workflow manually\n2. Prepare API and comment parameters\n3. Fetch Douyin video comments\n4. Select first comment with replies\n5. Check if comment has ID\n6. If yes: fetch and process replies\n7. If no: build empty reply output\n8. Output final results\n\n### Setup steps\n\n- - [ ] Configure JustOneAPI credentials in HTTP Request nodes\n- - [ ] Set Douyin video ID in 'Prepare API and Comment Inputs' node\n- - [ ] Verify API endpoints in both HTTP Request nodes\n\n### Customization\n\nYou can modify the comment selection logic in 'Select First Comment With Replies' to handle different reply retrieval scenarios."
      },
      "typeVersion": 1
    },
    {
      "id": "44c2df53-28dc-4621-bf61-6ce7cded00c4",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1552,
        704
      ],
      "parameters": {
        "color": 7,
        "height": 112,
        "content": "## Workflow Trigger\n\nInitial manual trigger to start the workflow"
      },
      "typeVersion": 1
    },
    {
      "id": "e9dd128e-2852-44cb-8b0c-07ea56675383",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1872,
        704
      ],
      "parameters": {
        "color": 7,
        "height": 112,
        "content": "## Input Preparation\n\nPrepares API parameters and comment selection criteria"
      },
      "typeVersion": 1
    },
    {
      "id": "5a43d51a-e7da-4f21-8526-1a1be52c4798",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2192,
        704
      ],
      "parameters": {
        "color": 7,
        "width": 304,
        "height": 112,
        "content": "## Fetch Douyin Comments\n\nMakes API call to retrieve video comments"
      },
      "typeVersion": 1
    },
    {
      "id": "d9d6b52b-202a-4050-ab8d-a11c476554c1",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2544,
        704
      ],
      "parameters": {
        "color": 7,
        "width": 288,
        "height": 112,
        "content": "## Comment Selection\n\nIdentifies first comment with replies for further processing"
      },
      "typeVersion": 1
    },
    {
      "id": "5d812d36-1a96-4651-8c52-447e96345004",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2880,
        704
      ],
      "parameters": {
        "color": 7,
        "width": 272,
        "height": 112,
        "content": "## Comment Validation\n\nChecks if selected comment has valid ID for reply retrieval"
      },
      "typeVersion": 1
    },
    {
      "id": "7b60d774-fa86-43e7-a91d-8a2084c774d5",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3216,
        704
      ],
      "parameters": {
        "color": 7,
        "width": 816,
        "height": 112,
        "content": "## Reply Processing Path\n\nMain path for fetching and processing comment replies"
      },
      "typeVersion": 1
    },
    {
      "id": "59f9fc21-2fe7-4f11-a3a4-f1500365af51",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3216,
        1136
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 96,
        "content": "## No Reply Path\n\nAlternative path when no valid comment ID is found"
      },
      "typeVersion": 1
    },
    {
      "id": "4b5267f5-8aa0-4d9d-9bdd-a3f0ce94a508",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2544,
        1120
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 112,
        "content": "## Raw Data Outputs\n\nOptional outputs for raw API responses (debugging)"
      },
      "typeVersion": 1
    },
    {
      "id": "f951678b-ac21-49d7-9907-d98f1d3f2db7",
      "name": "Manual Execution Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        1616,
        928
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "5b863797-b634-4adf-9a23-5d6bda3692f0",
      "name": "Prepare API and Comment Data",
      "type": "n8n-nodes-base.set",
      "position": [
        1936,
        928
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"baseUrl\": \"https://api.justoneapi.com\",\n  \"token\": \"YOUR_JUSTONEAPI_TOKEN\",\n  \"awemeId\": \"YOUR_DOUYIN_AWEME_ID\",\n  \"commentPage\": 1,\n  \"replyPage\": 1\n}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "4010f7b9-a6d2-41e0-86fb-dfa04ddf07a7",
      "name": "Fetch Video Comments via API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2272,
        928
      ],
      "parameters": {
        "url": "={{$json.baseUrl + '/api/douyin/get-video-comment/v1'}}",
        "options": {
          "timeout": 60000,
          "redirect": {
            "redirect": {}
          }
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "token",
              "value": "={{$json.token}}"
            },
            {
              "name": "awemeId",
              "value": "={{$json.awemeId}}"
            },
            {
              "name": "page",
              "value": "={{$json.commentPage}}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b649b6f9-fc7f-405c-85ce-53a60b89ca51",
      "name": "Output Raw Comments Data",
      "type": "n8n-nodes-base.set",
      "position": [
        2592,
        1312
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{$json}}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "a0182f3d-5890-4cce-944b-37df40b961c9",
      "name": "Select Comment with Replies",
      "type": "n8n-nodes-base.code",
      "position": [
        2592,
        928
      ],
      "parameters": {
        "jsCode": "const cfg = $('Prepare API and Comment Data').first().json;\nconst raw = $json;\n\nfunction firstImageUrl(image) {\n  return Array.isArray(image?.url_list) ? image.url_list[0] || null : null;\n}\n\nconst root = Array.isArray(raw) ? raw[0] : raw;\nconst data = root?.data || {};\nconst comments = Array.isArray(data.comments) ? data.comments : [];\n\nfunction cleanUser(user = {}) {\n  return {\n    uid: user.uid ?? null,\n    shortId: user.short_id ?? null,\n    secUid: user.sec_uid ?? null,\n    nickname: user.nickname ?? null,\n    signature: user.signature ?? null,\n    uniqueId: user.unique_id ?? null,\n    avatarThumb: firstImageUrl(user.avatar_thumb),\n    avatarMedium: firstImageUrl(user.avatar_medium),\n    isVerified: user.is_verified ?? null,\n    followStatus: user.follow_status ?? null,\n    followerCount: user.follower_count ?? null,\n    customVerify: user.custom_verify ?? null,\n    enterpriseVerifyReason: user.enterprise_verify_reason ?? null,\n    verificationType: user.verification_type ?? null,\n    region: user.region ?? null\n  };\n}\n\nfunction cleanTopLevelComment(comment) {\n  return {\n    commentId: comment.cid ?? null,\n    text: comment.text ?? null,\n    awemeId: comment.aweme_id ?? null,\n    createTime: comment.create_time ?? null,\n    likeCount: comment.digg_count ?? null,\n    status: comment.status ?? null,\n    replyCommentTotal: comment.reply_comment_total ?? null,\n    replyId: comment.reply_id ?? null,\n    replyToReplyId: comment.reply_to_reply_id ?? null,\n    isAuthorDigged: comment.is_author_digged ?? null,\n    userDigged: comment.user_digged ?? null,\n    isHot: comment.is_hot ?? null,\n    labelText: comment.label_text ?? null,\n    labelType: comment.label_type ?? null,\n    contentType: comment.content_type ?? null,\n    imageList: comment.image_list ?? null,\n    user: cleanUser(comment.user)\n  };\n}\n\nconst cleanedComments = comments.map(cleanTopLevelComment);\nconst selectedComment = cleanedComments.find(comment => Number(comment.replyCommentTotal || 0) > 0) || null;\n\nreturn [{\n  json: {\n    baseUrl: cfg.baseUrl,\n    token: cfg.token,\n    awemeId: cfg.awemeId,\n    commentPage: cfg.commentPage,\n    replyPage: cfg.replyPage,\n    commentsMeta: {\n      statusCode: data.status_code ?? null,\n      cursor: data.cursor ?? null,\n      hasMore: data.has_more ?? null,\n      total: data.total ?? null,\n      replyStyle: data.reply_style ?? null,\n      hotsoonFilteredCount: data.hotsoon_filtered_count ?? null,\n      foldedCommentCount: data.folded_comment_count ?? null,\n      logId: data.extra?.logid ?? null,\n      imprId: data.log_pb?.impr_id ?? null\n    },\n    totalCommentsReturned: cleanedComments.length,\n    hasCommentWithReplies: Boolean(selectedComment?.commentId),\n    commentId: selectedComment?.commentId || null,\n    selectedComment,\n    comments: cleanedComments,\n    rawCommentsResponse: raw\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "7ae06198-2dc1-4eb1-95be-5c65875fa88f",
      "name": "Check for Comment ID",
      "type": "n8n-nodes-base.if",
      "position": [
        2928,
        928
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "hasCommentIdCondition",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{$json.commentId}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "82e6e947-fdd3-41c9-8121-55491a87a7f7",
      "name": "Fetch Comment Replies via API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3264,
        832
      ],
      "parameters": {
        "url": "={{$json.baseUrl + '/api/douyin/get-video-sub-comment/v1'}}",
        "options": {
          "timeout": 60000,
          "redirect": {
            "redirect": {}
          }
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "token",
              "value": "={{$json.token}}"
            },
            {
              "name": "commentId",
              "value": "={{$json.commentId}}"
            },
            {
              "name": "page",
              "value": "={{$json.replyPage}}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "d078f3a9-14bc-46a7-b213-33ebb052e087",
      "name": "Output Raw Replies Data",
      "type": "n8n-nodes-base.set",
      "position": [
        3568,
        992
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{$json}}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "d9f31eae-ea1f-4333-a663-459c700b976e",
      "name": "Build Final Reply Data",
      "type": "n8n-nodes-base.code",
      "position": [
        3568,
        832
      ],
      "parameters": {
        "jsCode": "const selectedData = $('Select Comment with Replies').first().json;\nconst rawReplies = $json;\n\nfunction firstImageUrl(image) {\n  return Array.isArray(image?.url_list) ? image.url_list[0] || null : null;\n}\n\nconst root = Array.isArray(rawReplies) ? rawReplies[0] : rawReplies;\nconst data = root?.data || {};\nconst replies = Array.isArray(data.comments) ? data.comments : [];\n\nfunction cleanUser(user = {}) {\n  return {\n    uid: user.uid ?? null,\n    shortId: user.short_id ?? null,\n    secUid: user.sec_uid ?? null,\n    nickname: user.nickname ?? null,\n    signature: user.signature ?? null,\n    uniqueId: user.unique_id ?? null,\n    avatarThumb: firstImageUrl(user.avatar_thumb),\n    avatarMedium: firstImageUrl(user.avatar_medium),\n    isVerified: user.is_verified ?? null,\n    followStatus: user.follow_status ?? null,\n    followerCount: user.follower_count ?? null,\n    customVerify: user.custom_verify ?? null,\n    enterpriseVerifyReason: user.enterprise_verify_reason ?? null,\n    verificationType: user.verification_type ?? null,\n    region: user.region ?? null\n  };\n}\n\nfunction cleanReply(reply) {\n  return {\n    replyId: reply.cid ?? null,\n    text: reply.text ?? null,\n    awemeId: reply.aweme_id ?? null,\n    rootCommentId: reply.root_comment_id ?? null,\n    parentCommentId: reply.reply_id ?? null,\n    replyToReplyId: reply.reply_to_reply_id ?? null,\n    level: reply.level ?? null,\n    createTime: reply.create_time ?? null,\n    likeCount: reply.digg_count ?? null,\n    status: reply.status ?? null,\n    commentReplyTotal: reply.comment_reply_total ?? null,\n    userDigged: reply.user_digged ?? null,\n    isAuthorDigged: reply.is_author_digged ?? null,\n    isHot: reply.is_hot ?? null,\n    labelText: reply.label_text ?? null,\n    labelType: reply.label_type ?? null,\n    contentType: reply.content_type ?? null,\n    isFolded: reply.is_folded ?? null,\n    imageList: reply.image_list ?? null,\n    user: cleanUser(reply.user)\n  };\n}\n\nconst cleanedReplies = replies.map(cleanReply);\n\nreturn [{\n  json: {\n    awemeId: selectedData.awemeId,\n    commentPage: selectedData.commentPage,\n    replyPage: selectedData.replyPage,\n    hasCommentWithReplies: selectedData.hasCommentWithReplies,\n    commentsMeta: selectedData.commentsMeta,\n    selectedComment: selectedData.selectedComment,\n    repliesMeta: {\n      statusCode: data.status_code ?? null,\n      cursor: data.cursor ?? null,\n      mergeCursor: data.merge_cursor ?? null,\n      hasMore: data.has_more ?? null,\n      total: data.total ?? null,\n      logId: data.extra?.logid ?? null,\n      imprId: data.log_pb?.impr_id ?? null\n    },\n    totalCommentsReturned: selectedData.totalCommentsReturned,\n    replyCountReturned: cleanedReplies.length,\n    comments: selectedData.comments,\n    replies: cleanedReplies,\n    rawCommentsResponse: selectedData.rawCommentsResponse,\n    rawRepliesResponse: rawReplies\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "d105af4d-63f9-43bf-9dfa-7a728cca3b92",
      "name": "Output Final Reply Data",
      "type": "n8n-nodes-base.set",
      "position": [
        3888,
        832
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{$json}}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "300640fe-57a6-4af1-8915-4dd0207cd859",
      "name": "Build No Replies Data",
      "type": "n8n-nodes-base.code",
      "position": [
        3264,
        1248
      ],
      "parameters": {
        "jsCode": "const data = $json;\n\nreturn [{\n  json: {\n    awemeId: data.awemeId,\n    commentPage: data.commentPage,\n    replyPage: data.replyPage,\n    hasCommentWithReplies: false,\n    message: 'No top-level comment with reply_comment_total greater than 0 was found in the returned comments page. Review the raw comments response or try another commentPage value.',\n    commentsMeta: data.commentsMeta,\n    totalCommentsReturned: data.totalCommentsReturned,\n    comments: data.comments,\n    rawCommentsResponse: data.rawCommentsResponse\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "c1546f43-c060-4913-a61c-0d9eaf082d65",
      "name": "Output No Replies Data",
      "type": "n8n-nodes-base.set",
      "position": [
        3568,
        1248
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{$json}}"
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "501d481b-d4fb-4a98-9081-93464366b2d0",
  "connections": {
    "Check for Comment ID": {
      "main": [
        [
          {
            "node": "Fetch Comment Replies via API",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build No Replies Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build No Replies Data": {
      "main": [
        [
          {
            "node": "Output No Replies Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Final Reply Data": {
      "main": [
        [
          {
            "node": "Output Final Reply Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Execution Trigger": {
      "main": [
        [
          {
            "node": "Prepare API and Comment Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select Comment with Replies": {
      "main": [
        [
          {
            "node": "Check for Comment ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Video Comments via API": {
      "main": [
        [
          {
            "node": "Select Comment with Replies",
            "type": "main",
            "index": 0
          },
          {
            "node": "Output Raw Comments Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare API and Comment Data": {
      "main": [
        [
          {
            "node": "Fetch Video Comments via API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Comment Replies via API": {
      "main": [
        [
          {
            "node": "Build Final Reply Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Output Raw Replies Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Use this n8n workflow to get Douyin video comments and fetch replies for the first comment with replies using JustOneAPI.

Source: https://n8n.io/workflows/15885/ — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

This workflow allows you to import any workflow from a file or another n8n instance and map the credentials easily. A multi-form setup guides you through the entire process At the beginning you have t

Execute Command, Read Write File, HTTP Request +3
Web Scraping

[n8n] Advanced URL Parsing and Shortening Workflow - Switchy.io Integration. Uses splitInBatches, stickyNote, httpRequest, html. Event-driven trigger; 56 nodes.

HTTP Request, GitHub, Stop And Error +1
Web Scraping

[](https://youtu.be/c7yCZhmMjtI)

HTTP Request, GitHub, Stop And Error +1
Web Scraping

This automation organizes your n8n workflows files into categorizes (Active, Template, Done, Archived) and uploads them directly to a categorized Google Drive folders. It is designed to help users man

Google Drive, HTTP Request, Time Saved
Web Scraping

Create Animated Stories using GPT-4o-mini, Midjourney, Kling and Creatomate API. Uses httpRequest. Event-driven trigger; 51 nodes.

HTTP Request