
Douyin Search Keyword
Search Douyin by keyword to pull ranked video results for trend and competitor content research.
Overview
Douyin Search Keyword is an agent skill for the Grow phase that runs validated Douyin keyword searches and returns up to 60 ranked results as JSON or markdown.
Install
npx skills add https://github.com/aiskillstore/marketplace --skill douyin-search-keywordWhat is this skill?
- Validates keywords (2–50 characters, blocks URLs and unsafe characters)
- Sanitizes input to Chinese, Latin, digits, and basic punctuation
- Sort modes 0, 1, and 2 plus publish-window filters 0, 1, 7, and 180 days
- Result limit 1–60 with JSON or markdown output
- Calls the guaikei.com-backed search API via HTTPS from a small Node module
- Keyword length enforced between 2 and 50 characters
- Search limit range 1–60 results per request
- Four publish-window filters: 0, 1, 7, and 180 days
Adoption & trust: 1 installs on skills.sh; 350 GitHub stars; trending (+100% hot-view momentum).
What problem does it solve?
You need Douyin search results for a topic but lack a safe, parameterized way to query the platform from your agent workflow.
Who is it for?
Solo builders and indie marketers researching Douyin trends, hooks, and competitor videos before writing scripts or scheduling posts.
Skip if: Teams that only need Western short-video platforms, cannot use third-party Douyin API gateways, or want deep analytics without search listings.
When should I use this skill?
You need Douyin search results for a sanitized keyword with optional sort, time range, limit, and JSON or markdown output.
What do I get? / Deliverables
You get a sanitized query executed with explicit sort, time window, and limit, plus machine-readable or markdown listings you can drop into content plans.
- Validated and sanitized search keyword payload
- Douyin search result set (JSON or markdown) up to the chosen limit
Recommended Skills
Journey fit
Canonical shelf is Grow because the skill’s purpose is discovering what performs on Douyin to inform content and distribution bets. Content subphase fits keyword discovery and result export (JSON or markdown) used to plan posts and hooks.
How it compares
Use instead of hand-copying Douyin UI results when you want bounded, filterable search exports inside an agent session.
Common Questions / FAQ
Who is douyin-search-keyword for?
Indie creators, growth-minded solo founders, and agents helping with Chinese short-video content strategy who need programmatic Douyin keyword search.
When should I use douyin-search-keyword?
Use it during Grow content planning when you are scouting topics, during Launch distribution prep when comparing what ranks for a keyword, or anytime you need 1–60 Douyin results with sort and date filters.
Is douyin-search-keyword safe to install?
Review the Security Audits panel on this Prism page and treat the skill as calling external HTTPS APIs; confirm you trust the gateway host and your data handling policy before production use.
SKILL.md
READMESKILL.md - Douyin Search Keyword
/** * 抖音搜索模块 */ const https = require("https"); const querystring = require("querystring"); const BASE_URL = "www.guaikei.com"; const utils = require("./utils"); /** * 检查搜索关键词是否符合要求 */ function notIdealFormat(keyword) { keyword = keyword.trim(); if (keyword.length < 2) { utils.printError(`搜索关键词长度不能小于 2 个字符`); return false; } if (keyword.length > 50) { utils.printError(`搜索关键词长度不能超过 50 个字符`); return false; } if (/[<>\"'&]/g.test(keyword)) { utils.printError(`搜索关键词包含特殊字符, 请输入普通关键词, 例如: 新媒体`); return false; } if (keyword.includes("http")) { utils.printError( `搜索关键词包含 http 链接, 请输入普通关键词, 例如: 新媒体`, ); return false; } return true; } /** * 清洗搜索关键词 */ function sanitizeKeyword(keyword) { let trimmed = keyword.trim(); return trimmed.replace(/[^\u4e00-\u9fa5a-zA-Z0-9\s.,!?# ,。!?]/g, ""); } /** * 格式化搜索选项, 并检查是否有效 */ function optionFormat(sort, time, limit, output) { sort = sort || 0; time = time || 0; limit = limit || 10; output = output || "json"; if (sort !== 0 && sort !== 1 && sort !== 2) { utils.printError(`排序依据 ${sort} 无效, 请使用 0, 1, 2。 默认值为 0`); sort = 0; } if (time !== 0 && time !== 1 && time !== 7 && time !== 180) { utils.printError(`发布时间 ${time} 无效, 请使用 0, 1, 7, 180。 默认值为 0`); time = 0; } if (limit < 1 || limit > 60) { utils.printError(`搜索数量 ${limit} 无效, 请使用 1-60。 默认值为 10`); limit = 10; } if (output !== "json" && output !== "markdown") { utils.printError( `输出格式 ${output} 无效, 请使用 json, markdown。 默认值为 json`, ); output = "json"; } return [sort, time, limit, output]; } function formatMessage(keyword, result) { let message = `**抖音综合搜索结果**: ${keyword}\n`; message += "-".repeat(35) + "\n\n"; for (let i = 0; i < result.length; i++) { const item = result[i]; message += `**${i + 1} .** ${item.desc || "[无标题]"}\n`; message += `**发布人**: ${item.author_nickname || "[未知]"}\n`; message += `**发布时间**: ${item.create_time_str || "[未知]"}\n`; message += `**链接**: ${item.url || "[未知]"}\n`; if (item.dynamic_cover && item.dynamic_cover.length > 0) { message += `**封面**: ${item.dynamic_cover[0] || ""}\n`; } if (item.play_addr) { message += `**视频**: ${item.play_addr}\n`; } if (item.images && item.images.length > 0) { message += `**图文**: ${item.images.slice(0, 3).join(", ")}...\n`; } message += `**点赞**: ${item.digg_count || 0}\t`; message += `**评论**: ${item.comment_count || 0}\t`; message += `**收藏**: ${item.collect_count || 0}\t`; message += `**分享**: ${item.share_count || 0}\n`; message += "\n"; } message += "-".repeat(35) + "\n"; message += `**共 ${result.length} 条结果**\n`; return message; } async function createWithRetry(token, keyword, sort, time, limit) { let lastError = null; const retryIntervals = [1000, 2000, 3000]; for (let attempt = 0; attempt < 3; attempt++) { try { const timeoutPromise = new Promise((_, reject) => setTimeout( () => reject(new Error(`创建任务超时 (${attempt + 1}/3)`)), 10000, ), ); const task = await Promise.race([ createSearchTask(token, keyword, sort, time, limit), timeoutPromise, ]); if (task.errcode === 0) return task; throw new Error(`创建任务失败, 错误信息: ${JSON.stringify(task.errmsg)}`); } catch (error) { lastError = error; utils.printInfo( `【创建任务重试】 ${attempt + 1}/3 次 - ${error.message}`, ); if (attempt < 2) { await new Promise((resolve) => setTimeout(resolve, retryIntervals[attempt]), ); } } } throw lastError || new Error("创建搜索任务失败, 3次重试均失败"); } /** * 创建抖音搜索任务 * @param {string} token - API令牌 * @param {string} keyword - 搜索关键词 * @param {number} sort - 排序依据, 0: 综合排序, 1: 最多点赞, 2: 最新发布 * @param {number} time - 发布时间, 0: 全部, 1: 一天内, 7: 七天内, 180: 半年内 * @param {number} limit - 搜索数量, 1-60 * @returns {Promise<Object>} 搜索任务状态 * @throws {