An async Python SDK for TikTok's Content Posting API, Display API, and Data Portability API.
- Fully async — built on
aiohttpwith anasyncio-native interface - Typed responses — every API response is a frozen Pydantic v2 model
- Three API namespaces —
client.content_posting,client.display,client.data_portability - Convenience helpers — upload files from disk, poll for post completion, paginate videos automatically
- Clean exception hierarchy — catch broad or specific errors as needed
- Docker support — multi-stage Dockerfile for dev and prod environments
- Python ≥ 3.11
- A TikTok developer account with a registered app
- A valid user access token (OAuth 2.0 handled externally)
pip install tiktok-python-sdkimport asyncio
from tiktok import TikTokClient, UserField, VideoField, PrivacyLevel
async def main() -> None:
async with TikTokClient(access_token="act.your_token_here") as client:
# --- Display API ---
user = await client.display.get_user_info(
fields=[UserField.DISPLAY_NAME, UserField.FOLLOWER_COUNT, UserField.VIDEO_COUNT]
)
print(f"{user.display_name} has {user.follower_count:,} followers")
# Paginate through all videos
async for video in client.display.iter_videos(
fields=[VideoField.ID, VideoField.TITLE, VideoField.VIEW_COUNT]
):
print(video.id, video.title, video.view_count)
# --- Content Posting API ---
creator = await client.content_posting.query_creator_info()
print(f"Max video duration: {creator.max_video_post_duration_sec}s")
# Post a video by URL
init = await client.content_posting.post_video_from_url(
"https://example.com/my-video.mp4",
privacy_level=PrivacyLevel.PUBLIC_TO_EVERYONE,
title="Posted via TikTok Python SDK #python #dev",
)
# Poll until the post is live (or failed)
status = await client.content_posting.wait_for_post_completion(init.publish_id)
print(status.status, status.publicaly_available_post_id)
asyncio.run(main())TikTokClient(access_token: str, *, timeout: float = 30.0)The main client. Use as an async context manager or call await client.aclose() manually.
| Method | Description |
|---|---|
query_creator_info() |
Creator capabilities and privacy options |
init_video_post(...) |
Initialise a direct video post (returns publish_id + optional upload_url) |
init_inbox_video(...) |
Initialise an inbox/draft video upload |
upload_video_chunk(upload_url, data, ...) |
Upload one binary chunk |
upload_video_file(upload_url, file_path, ...) |
Upload a full file from disk, auto-chunked |
post_video_from_url(video_url, ...) |
Convenience: direct-post a video by URL |
post_video_from_file(file_path, ...) |
Convenience: direct-post a video from disk |
post_photos(photo_image_urls, ...) |
Post a photo carousel |
get_post_status(publish_id) |
Fetch current publish status |
wait_for_post_completion(publish_id, ...) |
Poll until terminal state |
class PrivacyLevel(str, Enum):
PUBLIC_TO_EVERYONE = "PUBLIC_TO_EVERYONE"
MUTUAL_FOLLOW_FRIENDS = "MUTUAL_FOLLOW_FRIENDS"
FOLLOWER_OF_CREATOR = "FOLLOWER_OF_CREATOR"
SELF_ONLY = "SELF_ONLY"class PostStatus(str, Enum):
PROCESSING_UPLOAD = "PROCESSING_UPLOAD"
PROCESSING_DOWNLOAD = "PROCESSING_DOWNLOAD"
SEND_TO_USER_INBOX = "SEND_TO_USER_INBOX"
PUBLISH_COMPLETE = "PUBLISH_COMPLETE"
FAILED = "FAILED"| Method | Description |
|---|---|
get_user_info(fields) |
Authenticated user's profile |
list_videos(fields, *, cursor, max_count) |
One page of the user's videos |
iter_videos(fields, ...) |
Async iterator over all videos (auto-paginates) |
query_videos(video_ids, fields) |
Fetch specific videos by ID (max 20) |
OPEN_ID, UNION_ID, AVATAR_URL, AVATAR_URL_100, AVATAR_LARGE_URL,
DISPLAY_NAME, BIO_DESCRIPTION, PROFILE_DEEP_LINK, IS_VERIFIED,
USERNAME, FOLLOWER_COUNT, FOLLOWING_COUNT, LIKES_COUNT, VIDEO_COUNT
ID, CREATE_TIME, COVER_IMAGE_URL, SHARE_URL, VIDEO_DESCRIPTION,
DURATION, HEIGHT, WIDTH, TITLE, EMBED_HTML, EMBED_LINK,
LIKE_COUNT, COMMENT_COUNT, SHARE_COUNT, VIEW_COUNT
Available only to TikTok users in the EEA or UK.
| Method | Description |
|---|---|
add_data_request(data_format, category_selection_list) |
Start a new export |
check_data_request_status(request_id, *, fields) |
Check export progress |
cancel_data_request(request_id) |
Cancel a pending export |
download_data(request_id) |
Download the zip archive as bytes |
ALL_DATA, ACTIVITY, VIDEO, PROFILE, DIRECT_MESSAGE
TikTokSDKError
├── TikTokAPIError ← non-OK error code from the platform
│ ├── TikTokAuthError ← invalid / expired token, missing scope
│ ├── TikTokRateLimitError
│ ├── TikTokNotFoundError
│ └── TikTokServerError ← 5xx from TikTok
├── TikTokUploadError ← chunk or download transport failure
└── TikTokConfigError ← SDK misconfiguration (e.g. empty token)
from tiktok import TikTokAuthError, TikTokRateLimitError, TikTokAPIError
try:
user = await client.display.get_user_info(fields=[UserField.DISPLAY_NAME])
except TikTokAuthError as e:
print(f"Auth failed: {e.code} — {e.message}")
except TikTokRateLimitError:
print("Rate limited, back off and retry.")
except TikTokAPIError as e:
print(f"API error {e.code}: {e.message} (log_id={e.log_id})")# Clone and install with dev extras
git clone https://github.com/inoue-ai/tiktok-python-sdk.git
cd tiktok-python-sdk
pip install -e ".[dev]"
# Run tests
pytest
# Lint and format
ruff check .
ruff format .
# Type-check
mypy tiktok/# Build the dev image
docker build --target dev -t tiktok-sdk:dev .
# Run tests in Docker
docker compose run test
# Run lint in Docker
docker compose run lint
# Run mypy in Docker
docker compose run typecheckThis SDK does not implement the TikTok OAuth 2.0 flow. Obtain an access
token externally (e.g. via your web server or the TikTok Developer Portal) and
pass it to TikTokClient. Token refresh must also be handled externally.
Required OAuth scopes per feature:
| Feature | Scopes |
|---|---|
| Query creator info | video.publish |
| Direct post video | video.publish |
| Inbox/draft video | video.upload |
| Post photos | video.publish |
| Display — user info (basic) | user.info.basic |
| Display — user info (profile) | user.info.profile |
| Display — user stats | user.info.stats |
| Display — video list/query | video.list |
| Data Portability | portability.<category>.single or .ongoing |