Skip to main content
TikTokLive allows you to download profile images and avatars directly from event data. This is useful for creating custom overlays, user galleries, or archiving user information.

Overview

User profile images are available in most events that include user data, such as:
  • CommentEvent - Comments in chat
  • GiftEvent - Gift senders
  • JoinEvent - Users joining the stream
  • FollowEvent - New followers

Basic Image Download

1

Import required modules

from TikTokLive import TikTokLiveClient
from TikTokLive.events import CommentEvent, ConnectEvent
2

Create the client

client: TikTokLiveClient = TikTokLiveClient(
    unique_id="@username"
)
3

Add event handler with image download

@client.on(CommentEvent)
async def on_comment(event: CommentEvent):
    # Download the image
    image_bytes: bytes = await client.web.fetch_image_data(
        image=event.user.avatar_thumb
    )

    # Write to file
    with open(f"{event.user.unique_id}.webp", "wb") as file:
        file.write(image_bytes)
    
    client.logger.info("Downloaded an image!")

Complete Example

from TikTokLive.client.client import TikTokLiveClient
from TikTokLive.client.logger import LogLevel
from TikTokLive.events import ConnectEvent, CommentEvent

client: TikTokLiveClient = TikTokLiveClient(
    unique_id="@tv_asahi_news"
)


@client.on(ConnectEvent)
async def on_connect(event: ConnectEvent):
    client.logger.info(f"Connected to @{event.unique_id}!")


@client.on(CommentEvent)
async def on_comment(event: CommentEvent):
    client.logger.info("Received a comment!")

    # Download the image
    image_bytes: bytes = await client.web.fetch_image_data(
        image=event.user.avatar_thumb
    )

    # Write to bytes
    with open(f"{event.user.unique_id}.webp", "wb") as file:
        file.write(image_bytes)

    client.logger.info("Downloaded an image!")


if __name__ == '__main__':
    # Enable debug info
    client.logger.setLevel(LogLevel.INFO.value)

    # Connect
    client.run(process_connect_events=False)

Available Image Types

User objects typically contain multiple image URLs:
@client.on(CommentEvent)
async def on_comment(event: CommentEvent):
    # Thumbnail (small, square)
    avatar_thumb = event.user.avatar_thumb
    
    # Medium size avatar
    avatar_medium = event.user.avatar_medium
    
    # Large avatar
    avatar_large = event.user.avatar_large
    
    # Download the large version
    image_bytes = await client.web.fetch_image_data(
        image=avatar_large
    )

Downloading from Different Events

From Gift Events

from TikTokLive.events import GiftEvent

@client.on(GiftEvent)
async def on_gift(event: GiftEvent):
    # Download gift sender's avatar
    image_bytes = await client.web.fetch_image_data(
        image=event.user.avatar_thumb
    )
    
    with open(f"gifts/{event.user.unique_id}.webp", "wb") as file:
        file.write(image_bytes)

From Join Events

from TikTokLive.events import JoinEvent

@client.on(JoinEvent)
async def on_join(event: JoinEvent):
    # Download new viewer's avatar
    image_bytes = await client.web.fetch_image_data(
        image=event.user.avatar_thumb
    )
    
    with open(f"viewers/{event.user.unique_id}.webp", "wb") as file:
        file.write(image_bytes)

Advanced Usage

Caching Images

Avoid downloading the same image multiple times:
import os
from TikTokLive.events import CommentEvent

downloaded_users = set()

@client.on(CommentEvent)
async def on_comment(event: CommentEvent):
    user_id = event.user.unique_id
    
    # Skip if already downloaded
    if user_id in downloaded_users:
        return
    
    # Check if file exists
    filepath = f"avatars/{user_id}.webp"
    if os.path.exists(filepath):
        downloaded_users.add(user_id)
        return
    
    # Download image
    image_bytes = await client.web.fetch_image_data(
        image=event.user.avatar_thumb
    )
    
    # Create directory if needed
    os.makedirs("avatars", exist_ok=True)
    
    # Save image
    with open(filepath, "wb") as file:
        file.write(image_bytes)
    
    downloaded_users.add(user_id)
    client.logger.info(f"Downloaded avatar for {user_id}")

Processing Images

You can process images using PIL/Pillow:
from PIL import Image
from io import BytesIO
from TikTokLive.events import CommentEvent

@client.on(CommentEvent)
async def on_comment(event: CommentEvent):
    # Download image
    image_bytes = await client.web.fetch_image_data(
        image=event.user.avatar_thumb
    )
    
    # Open with PIL
    image = Image.open(BytesIO(image_bytes))
    
    # Resize to 128x128
    image = image.resize((128, 128))
    
    # Convert to PNG
    image.save(f"{event.user.unique_id}.png", "PNG")
Install Pillow first: pip install Pillow

Image Format

TikTok profile images are typically served in WebP format, which offers good compression and quality.
To convert to other formats:
from PIL import Image
from io import BytesIO

image_bytes = await client.web.fetch_image_data(
    image=event.user.avatar_thumb
)

image = Image.open(BytesIO(image_bytes))
image.save(f"{event.user.unique_id}.jpg", "JPEG")
image.save(f"{event.user.unique_id}.png", "PNG")

Error Handling

Always handle potential download errors:
@client.on(CommentEvent)
async def on_comment(event: CommentEvent):
    try:
        image_bytes = await client.web.fetch_image_data(
            image=event.user.avatar_thumb
        )
        
        with open(f"{event.user.unique_id}.webp", "wb") as file:
            file.write(image_bytes)
            
    except Exception as e:
        client.logger.error(f"Failed to download image: {e}")
Ensure you have proper error handling, as network issues or invalid URLs can cause download failures.

Best Practices

  1. Create directories - Use os.makedirs("path", exist_ok=True) before saving files
  2. Cache downloads - Don’t download the same image multiple times
  3. Handle errors - Network issues can occur, always use try-except blocks
  4. Use unique filenames - Base filenames on unique_id to avoid conflicts
  5. Clean up old files - Implement a cleanup strategy for old images

Build docs developers (and LLMs) love