不依赖任何第三方网站实现在线批量TikTok/抖音解析下载无水印视频/图集,并将结果显示在网页上。同时支持API调用,可配合iOS快捷指令APP实现应用内下载。免费,开源,无广告,长期维护。
100K+
🚀 A self-hosted data API for Douyin and TikTok. One docker compose up, an identity pool that maintains itself, and a REST API, MCP server and web console on top.
These sponsors paid to be here, and Douyin_TikTok_Download_API stays free and open because of it. To sponsor the project, see my GitHub Sponsors page.
Your Ultimate Social Media Data & API Marketplace
Professional data solutions for Douyin, Xiaohongshu, TikTok, Instagram, YouTube,
Twitter, and more.
Real-time Data | Flexible APIs | Seamless Integration | Competitive Pricing with Discounts
Buy and sell custom APIs, services, and social media solutions on the
TikHub.io Marketplace, alongside developers, businesses and content creators.
Trusted by leading global influencer marketing and social media intelligence platforms
One real call: paste a link, send it, get the normalised result back. The identity pool, the scheduler and the API reference it passed through on the way are all in the same console. The interface follows the browser's language, and both are written by hand rather than machine-translated. 中文界面
v5 is a rewrite. It started from an empty branch and inherits no v4 code.
v4's real problem was never a shortage of features — it was that the API would die quietly and nobody would know. A cookie expires, a signature algorithm changes, an endpoint gets rate-limited, and you find out when someone files an issue. v5 puts "you can see it" and "it heals itself" ahead of features.
| v4 | v5 | |
|---|---|---|
| Where identities come from | You copy cookies out of a browser into config.yaml | A headless browser mints guest identities, and the pool tops itself up when usable ones run low |
| How requests go out | Straight out, as they arrive | Health tiers, quantised LRU rotation, one in-flight lock per identity, a token bucket per (identity, endpoint), a circuit breaker per endpoint |
| When something breaks | You wait for a bug report | One structured record per request, live health for every identity and endpoint, visible in the console |
| Call style | Synchronous — send and wait | Asynchronous by default (202 + task_id); add ?wait= to go back to synchronous |
| What is kept | Nothing; parsed and discarded | PostgreSQL + Redis. Everything parsed is archived, so a post deleted upstream is still here |
| Access control | None; anyone can call it | API keys with scopes and roles, managed in the console |
| Interface | A single PyWebIO page | A React console: identity pool, scheduler, library, downloads, logs, diagnostics |
| Ways in | REST | REST, MCP and a CLI, all over the same service layer |
| Signing | X-Bogus, A_Bogus | a_bogus, X-Bogus, X-Gnarly, X-Dynosaur in pure Python, with a browser fallback |
| Deployment | pip install -r requirements.txt + python start.py | docker compose up, three images |
| Platforms | Douyin, TikTok, Bilibili | Douyin, TikTok |
Bilibili is the one thing that went backwards: v5 does not have it yet. It shares neither the signing nor the identity machinery with Douyin and TikTok, so the rewrite left it out for now.
v4's code stays on the v4 branch,
and the image is still there — pull it by version:
docker pull evil0ctal/douyin_tiktok_download_api:V4.1.2
main is v5 now, and latest follows main. To stay on v4, pin the version tag
rather than using latest.
| Capability | Douyin | TikTok |
|---|---|---|
| One post (video or image album) | ✅ | ✅ |
| Author profile | ✅ | ✅ |
| An author's posts | ✅ | ✅ |
| An author's liked posts | ✅ | ✅ |
| Mixes / playlists | ✅ | ✅ |
| Comments | ✅ | ✅ |
| Comment replies | ✅ | ✅ |
| Followers | ❌ | ✅ |
| Following | ❌ | ✅ |
Douyin serves its follower and following lists only to a signed-in session, so those two endpoints are not registered at all: an endpoint that always returns an empty page is worth nothing. Importing your own logged-in cookies widens what the rest can see, too.
Media downloads, the content archive, counter snapshots, collections and a watchlist are built in; none of them needs another service.
Paste whatever you have — a short link, a post URL, or the whole caption a platform app puts on your clipboard:
https://v.douyin.com/L4NpDJ6/
https://www.douyin.com/video/7126745726494821640
https://www.douyin.com/jingxuan?modal_id=7660875690212492466
https://www.tiktok.com/@evil0ctal/video/7156033831819037994
https://www.tiktok.com/t/ZTR9nkkmL/
2.84 nqe:/ <caption> https://v.douyin.com/L4FJNR3/ <sentence telling you to open the app>
Short links are followed and a link buried in a caption is extracted. A post id is also checked against the platform's own encoding first, so an id that cannot exist is refused here rather than costing an upstream request.
| Service | Python 3.12 · FastAPI · SQLAlchemy 2.0 (async) · Alembic · Typer · structlog |
| Transport | wreq (browser TLS fingerprint emulation) · httpx |
| Data | PostgreSQL + TimescaleDB · Redis |
| Console | React 19 · TypeScript · Vite · TanStack Query · wouter · i18next |
| Signing | a_bogus, X-Bogus, X-Gnarly and X-Dynosaur in pure Python |
| Identity minting | CloakBrowser, headless, in a container of its own, called over HTTP |
| Downloader | Go 1.23, standard library only, statically linked into a scratch image |
| Auth | argon2id password hashing · API keys with scopes |
| Protocols | REST (OpenAPI) · MCP (streamable-http) · CLI |
| Tooling | uv · ruff · mypy · pytest · Docker Compose |
Nothing beyond Postgres and Redis is required. No Kafka, no Elasticsearch, no object store, no Kubernetes.
CloakBrowser is pinned to a specific commit. That pin is a security control — see docker/Dockerfile.browser.
Douyin_TikTok_Download_API/
├── src/dtk/ the service; all of it lives here
│ ├── api/ FastAPI routes, auth, OpenAPI localisation
│ ├── platforms/ Douyin and TikTok adapters: endpoints, params, parsers
│ ├── signing/ a_bogus / X-Bogus / X-Gnarly / X-Dynosaur
│ ├── transport/ outbound requests, response classification
│ ├── identity/ identity minting and health
│ ├── scheduler/ identity selection, token buckets, circuit breakers
│ ├── services/ the business layer, shared by REST, MCP and the CLI
│ ├── worker/ async tasks, callbacks, scheduled collection
│ ├── db/ SQLAlchemy models and Alembic migrations
│ ├── ops/ diagnostics, backups, health checks, alerting
│ ├── media/ downloader client
│ ├── models/ one content model across both platforms
│ ├── urls/ link recognition, short-link expansion, id validation
│ ├── mcp/ MCP server
│ ├── cli/ the dtk command line
│ ├── i18n/ server-side English and Chinese strings
│ └── core/ settings, logging, error types
├── web/ the React console, built into the app image
│ └── src/
│ ├── pages/ one file per console page
│ ├── components/ design system and shared components
│ └── locales/ console English and Chinese strings
├── docker/ three Dockerfiles, compose, and two sidecars
│ ├── browser_rpc/ Python, wrapping CloakBrowser
│ ├── downloader/ Go, the media download sidecar
│ └── compose.yml
├── documents/ user documentation, 17 pages in each language
├── tests/ unit / integration / contract / replay
├── scripts/ smoke.sh
├── .github/workflows/ CI and Docker image publishing
├── alembic.ini
├── pyproject.toml
└── Makefile
You need Docker and Docker Compose. Nothing in the repository ships a default password
or key, so write .env first:
POSTGRES_PASSWORD=$(openssl rand -hex 24)
REDIS_PASSWORD=$(openssl rand -hex 24)
cat > .env <<EOF
DTK_SECRET_KEY=$(openssl rand -base64 48)
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
REDIS_PASSWORD=${REDIS_PASSWORD}
DTK_DATABASE_URL=postgresql+asyncpg://dtk:${POSTGRES_PASSWORD}@postgres:5432/dtk
DTK_REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379/0
EOF
docker compose -p dtk -f docker/compose.yml up -d
docker compose -p dtk -f docker/compose.yml logs api # prints the setup token
Open http://127.0.0.1:8000 and use the token from the log to create the first administrator.
By default it is built locally: the first up compiles the application image from the
Dockerfile in this repository, which takes a few minutes. To skip that, point compose at
the published image instead:
export DTK_IMAGE=evil0ctal/douyin_tiktok_download_api
export DTK_IMAGE_TAG=latest
docker compose -p dtk -f docker/compose.yml pull
docker compose -p dtk -f docker/compose.yml up -d
The pull is not optional: these services declare both image and build, so compose
builds from the local Dockerfile whenever the image is not already on the machine rather
than reaching for a registry.
Images are published for linux/amd64 and linux/arm64, so Apple Silicon and a
Raspberry Pi both run natively. The browser container is not published: it installs
CloakBrowser from a pinned commit, and that pin is a security control that should be
yours to choose, so it stays a local build.
For the browser container, the downloader sidecar, reverse proxies and backups, see docker/README.md.
| Entry point | Where | What it is |
|---|---|---|
| Web console | / | Identity pool, scheduler, library, downloads, logs, diagnostics |
| API reference | /docs | Swagger UI inside the console, English and Chinese |
| Bare reference | /swagger, /redoc | No login required |
| REST API | /api/v1/... | 93 operations |
| MCP | /mcp | Shares the service layer with REST; client setup at /mcp-guide in the console |
| CLI | dtk --help | Same |
The main capabilities:
/api/v1/ios/shortcutThe full documentation lives in documents/ — 17 pages, in
English and Chinese.
New here: Quick start · Concepts · Console overview
Running it: Installation and deployment · Configuration reference · Operations · Troubleshooting · Security
Building against it: REST API guide · MCP and AI agents · CLI reference · Contributing
The endpoint reference is not in there: it is generated from the code that serves the
requests, so your own instance is the copy that is never out of date. Find it at /docs
inside the console, or at /swagger, /redoc and /openapi.json without a login. Both
languages.
中文文档:documents/README.zh-CN.md
| Issues | GitHub Issues — public, keeps its history, and anyone who has hit the same thing can answer |
[email protected] — reaches one person; best for anything that does not belong in public | |
| Author | @Evil0ctal |
Before asking, read Troubleshooting and include
the output of the Diagnose page or dtk diagnose. It answers most of what a maintainer
would otherwise have to ask you.
Started 2021/11/06 · GitHub @Evil0ctal
You may use, modify and distribute this project, including commercially and inside closed-source products. The grant is irrevocable. In return the licence asks you to:
This project is given away, and it stays free because sponsors pay for it rather than users. If you are making money from it, please consider sponsoring instead of only taking.
This is a request, not a licence condition — Apache 2.0 permits commercial use, and nothing above takes that back.
The sponsors above pay for the project. This section is for the person who maintains it, and is entirely optional.
| Network | Address |
|---|---|
| Solana | HvtkxmDERbNXfCoojpdFAYN5mSWowjpXgedsG9eF7y9z |
| Tron (TRC20) | TQwSM2vjcnrdRU7gY7KNp2tCgMnK33azkT |
| Ethereum (ERC20) | 0x2f210FdfD981B59eC130370E5b1Aa8A6a06fb5Ad |
| BNB Smart Chain (BEP20) | 0x2f210FdfD981B59eC130370E5b1Aa8A6a06fb5Ad |
| Bitcoin | bc1q785j55cxlnjqe8lkwy8cq57t8t9vn3ak9tlsfy |
These networks carry the usual major tokens. USDT on Tron (TRC20) or Solana is the easiest to receive, and the cheapest to send.
Send only on the network an address is listed under. A transfer on the wrong chain cannot be recovered by anybody. Ethereum and BNB Smart Chain share one address on purpose: both are EVM chains, and the same key controls it.
GitHub Sponsors works too.
This fetches data from platforms that have their own terms, and it runs on your machine under your control. Respect those terms and applicable law, respect the people whose content you collect, do not use it to harass anyone, and do not redistribute work that is not yours. Nobody else can enforce any of that for you.
Content type
Image
Digest
sha256:cc8a7ab15…
Size
87.3 MB
Last updated
3 days ago
docker pull evil0ctal/douyin_tiktok_download_api