Answers
Why do some Douyin links say /note/ instead of /video/?
Short answer
A /note/ link is a Douyin photo post (图文): a set of images, usually with music, instead of a video. It uses the same aweme_id numbering, so okdata's Douyin video detail takes a /note/ link or its ID like any other and returns type image with every image URL, for $0.002.
Douyin has two kinds of posts. A video post opens at douyin.com/video/<id>. A photo post, which Douyin calls 图文, is a swipeable set of images with a caption and usually a soundtrack, and it opens at douyin.com/note/<id>. The number after /note/ is an ordinary aweme_id from the same 19-digit sequence as videos (see aweme_id and modal_id), so a photo post can be fetched, searched and commented on like a video. What breaks is code that assumes every post has a playable video: link parsers that only match /video/, downloaders that look for a video URL and find a list of images, spreadsheets that expect a duration. Share links (v.douyin.com/...) hide the difference until they redirect.
How to tell them apart
| Video post | Photo post (图文) | |
|---|---|---|
| Web link | /video/<id> |
/note/<id> |
type in okdata data |
video |
image |
images |
null | every image URL, in order |
| Likes, comments, shares, saves | yes | yes, same fields |
metrics.views |
null (Douyin hides plays) | null |
Some photo posts are live photos (实况): each picture also has a short clip behind it. okdata returns the still image for each; the clips are not included.
How the API handles both
Douyin video detail takes either link, a short link that redirects to either, or the bare ID. You do not need to know the type in advance; read type in the answer. Douyin video search returns both kinds mixed in one list, so filter on type if you only want one. Video comments work the same for a photo post's ID.
| Task | Calls | Cost |
|---|---|---|
| One /note/ link to images, caption and counts | 1 | $0.002 |
| 200 mixed links | 200 | $0.40 |
| First comment page of a photo post | 1 | $0.002 |
Example
import os, requests
r = requests.get(
"https://api.okdata.online/v1/douyin/videos/get",
headers={"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"},
params={"url": "https://www.douyin.com/note/7431266008815910153"},
timeout=60,
)
post = r.json()["data"]["item"]
if post["type"] == "image":
print(len(post["images"]), "images:", post["images"][:2])
else:
print("video post", post["url"])
print(post["text"], post["metrics"]["likes"])
With view=full, ext.music holds the soundtrack title, which photo posts usually have.
Limits
- Image URLs are signed Douyin CDN links with an
x-expirestime. Download what you need soon after the call. - No video file URL is returned for either kind of post.
- Douyin does not publish play counts for other people's posts, photo or video; see Douyin play counts.
- A deleted post returns
not_foundand is not charged.
Sources
- Live Photo posts: each image has its own MP4 under images[i].video (Douyin_TikTok_Download_API issue #792)
- Video-only download still trips over photo posts (TikTokDownloader issue #567)
- TikTokDownloader README: videos, photo sets (图集) and live photos listed separately
Where people asked this (read 2026-11-12)
Updated